Skip to content

Commit 92deb02

Browse files
ghislainpiotsonartech
authored andcommitted
SONARPY-3095 Race condition in Typeshed (#350)
GitOrigin-RevId: 4edbf79722ab00c6826bc3ea46ec486480d2e48c
1 parent 4cc30e2 commit 92deb02

1 file changed

Lines changed: 41 additions & 19 deletions

File tree

  • python-frontend/src/main/java/org/sonar/python/types

python-frontend/src/main/java/org/sonar/python/types/TypeShed.java

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package org.sonar.python.types;
1818

19+
import com.google.common.annotations.VisibleForTesting;
1920
import java.io.IOException;
2021
import java.io.InputStream;
2122
import java.util.Arrays;
@@ -26,6 +27,8 @@
2627
import java.util.List;
2728
import java.util.Map;
2829
import java.util.Set;
30+
import java.util.concurrent.ConcurrentHashMap;
31+
import java.util.concurrent.locks.ReentrantLock;
2932
import java.util.stream.Collectors;
3033
import javax.annotation.CheckForNull;
3134
import javax.annotation.Nullable;
@@ -59,9 +62,10 @@
5962

6063
public class TypeShed {
6164

62-
private static Map<String, Symbol> builtins;
63-
private static final Map<String, Map<String, Symbol>> typeShedSymbols = new HashMap<>();
64-
private static final Map<String, Set<Symbol>> builtinGlobalSymbols = new HashMap<>();
65+
private static volatile Map<String, Symbol> builtins;
66+
private static final Map<String, Map<String, Symbol>> typeShedSymbols = new ConcurrentHashMap<>();
67+
private static final Map<String, Set<Symbol>> builtinGlobalSymbols = new ConcurrentHashMap<>();
68+
private static final ReentrantLock resolutionLock = new ReentrantLock();
6569

6670
private static final String PROTOBUF_CUSTOM_STUBS = "custom_protobuf/";
6771
private static final String PROTOBUF = "stdlib_protobuf/";
@@ -87,8 +91,8 @@ public class TypeShed {
8791
}
8892

8993
private static final Logger LOG = LoggerFactory.getLogger(TypeShed.class);
90-
private static Set<String> supportedPythonVersions;
91-
private static ProjectLevelSymbolTable projectLevelSymbolTable;
94+
private static volatile Set<String> supportedPythonVersions;
95+
private static volatile ProjectLevelSymbolTable projectLevelSymbolTable;
9296

9397
private TypeShed() {
9498
}
@@ -102,20 +106,23 @@ public static void setProjectLevelSymbolTable(ProjectLevelSymbolTable projectLev
102106
}
103107

104108
public static Map<String, Symbol> builtinSymbols() {
105-
if ((TypeShed.builtins == null)) {
106-
supportedPythonVersions = ProjectPythonVersion.currentVersions().stream().map(PythonVersionUtils.Version::serializedValue).collect(Collectors.toSet());
107-
Map<String, Symbol> builtins = getSymbolsFromProtobufModule(BUILTINS_FQN, PROTOBUF);
108-
builtins.put(NONE_TYPE, new ClassSymbolImpl(NONE_TYPE, NONE_TYPE));
109-
TypeShed.builtins = Collections.unmodifiableMap(builtins);
110-
TypeShed.builtinGlobalSymbols.put("", new HashSet<>(builtins.values()));
109+
if (builtins == null) {
110+
resolutionLock.lock();
111+
try {
112+
if (builtins == null) {
113+
supportedPythonVersions = ProjectPythonVersion.currentVersions().stream().map(PythonVersionUtils.Version::serializedValue).collect(Collectors.toSet());
114+
Map<String, Symbol> builtinMap = getSymbolsFromProtobufModule(BUILTINS_FQN, PROTOBUF);
115+
builtinMap.put(NONE_TYPE, new ClassSymbolImpl(NONE_TYPE, NONE_TYPE));
116+
builtins = Collections.unmodifiableMap(builtinMap);
117+
builtinGlobalSymbols.put("", new HashSet<>(builtinMap.values()));
118+
}
119+
} finally {
120+
resolutionLock.unlock();
121+
}
111122
}
112123
return builtins;
113124
}
114125

115-
public static Map<String, Map<String, Symbol>> getLoadedTypeShedSymbols() {
116-
return typeShedSymbols;
117-
}
118-
119126
public static ClassSymbol typeShedClass(String fullyQualifiedName) {
120127
Symbol symbol = builtinSymbols().get(fullyQualifiedName);
121128
if (symbol == null) {
@@ -138,19 +145,34 @@ private static boolean searchedModuleMatchesCurrentProject(String searchedModule
138145
* Returns map of exported symbols by name for a given module
139146
*/
140147
public static Map<String, Symbol> symbolsForModule(String moduleName) {
141-
return symbolsForModule(moduleName, new HashSet<>());
148+
Map<String, Symbol> symbols = typeShedSymbols.get(moduleName);
149+
if (symbols != null) {
150+
return symbols;
151+
}
152+
153+
resolutionLock.lock();
154+
try {
155+
symbols = typeShedSymbols.get(moduleName);
156+
if (symbols != null) {
157+
return symbols;
158+
}
159+
return symbolsForModule(moduleName, new HashSet<>());
160+
} finally {
161+
resolutionLock.unlock();
162+
}
142163
}
143164

144-
private static Map<String, Symbol> symbolsForModule(String moduleName, Set<String> modulesInProgress) {
165+
@VisibleForTesting
166+
static Map<String, Symbol> symbolsForModule(String moduleName, Set<String> modulesInProgress) {
145167
if (searchedModuleMatchesCurrentProject(moduleName)) {
146168
return Collections.emptyMap();
147169
}
148-
if (!TypeShed.typeShedSymbols.containsKey(moduleName)) {
170+
if (!typeShedSymbols.containsKey(moduleName)) {
149171
Map<String, Symbol> symbols = searchTypeShedForModule(moduleName, modulesInProgress);
150172
typeShedSymbols.put(moduleName, symbols);
151173
return symbols;
152174
}
153-
return TypeShed.typeShedSymbols.get(moduleName);
175+
return typeShedSymbols.get(moduleName);
154176
}
155177

156178
@CheckForNull

0 commit comments

Comments
 (0)