Skip to content

Commit 99cfbf2

Browse files
committed
[GR-23488] All accesses to registeredAutoloads or the nested data structures should be done under the lock.
PullRequest: truffleruby/1766
2 parents 57c5fd6 + 569e553 commit 99cfbf2

File tree

2 files changed

+19
-8
lines changed

2 files changed

+19
-8
lines changed

src/main/java/org/truffleruby/language/RubyConstant.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
public class RubyConstant implements ObjectGraphNode {
2424

25+
public static final RubyConstant[] EMPTY_ARRAY = new RubyConstant[0];
26+
2527
private final DynamicObject declaringModule;
2628
private final String name;
2729
private final Object value;

src/main/java/org/truffleruby/language/loader/FeatureLoader.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ public class FeatureLoader {
5555

5656
private final ReentrantLockFreeingMap<String> fileLocks = new ReentrantLockFreeingMap<>();
5757
/** Maps basename without extension -> autoload path -> autoload constant, to detect when require-ing a file already
58-
* registered with autoload. */
58+
* registered with autoload.
59+
*
60+
* Synchronization: Both levels of Map and the Lists are protected by registeredAutoloadsLock. */
5961
private final Map<String, Map<String, List<RubyConstant>>> registeredAutoloads = new HashMap<>();
6062
private final ReentrantLock registeredAutoloadsLock = new ReentrantLock();
6163

@@ -86,29 +88,38 @@ public void addAutoload(RubyConstant autoloadConstant) {
8688
try {
8789
final Map<String, List<RubyConstant>> constants = ConcurrentOperations
8890
.getOrCompute(registeredAutoloads, basename, k -> new LinkedHashMap<>());
89-
ConcurrentOperations.getOrCompute(constants, autoloadPath, k -> new ArrayList<>()).add(autoloadConstant);
91+
final List<RubyConstant> list = ConcurrentOperations
92+
.getOrCompute(constants, autoloadPath, k -> new ArrayList<>());
93+
list.add(autoloadConstant);
9094
} finally {
9195
registeredAutoloadsLock.unlock();
9296
}
9397
}
9498

9599
public List<RubyConstant> getAutoloadConstants(String expandedPath) {
96100
final String basename = basenameWithoutExtension(expandedPath);
97-
final Map<String, List<RubyConstant>> constantsMap;
101+
final Map<String, RubyConstant[]> constantsMapCopy;
98102

99103
registeredAutoloadsLock.lock();
100104
try {
101-
constantsMap = registeredAutoloads.get(basename);
105+
final Map<String, List<RubyConstant>> constantsMap = registeredAutoloads.get(basename);
102106
if (constantsMap == null || constantsMap.isEmpty()) {
103107
return null;
104108
}
109+
110+
// Deep-copy constantsMap so we can call findFeature() outside the lock
111+
constantsMapCopy = new LinkedHashMap<>();
112+
for (Map.Entry<String, List<RubyConstant>> entry : constantsMap.entrySet()) {
113+
constantsMapCopy.put(entry.getKey(), entry.getValue().toArray(RubyConstant.EMPTY_ARRAY));
114+
}
105115
} finally {
106116
registeredAutoloadsLock.unlock();
107117
}
108118

109119
final List<RubyConstant> constants = new ArrayList<>();
110-
for (Map.Entry<String, List<RubyConstant>> entry : constantsMap.entrySet()) {
120+
for (Map.Entry<String, RubyConstant[]> entry : constantsMapCopy.entrySet()) {
111121
final String expandedAutoloadPath = findFeature(entry.getKey());
122+
112123
if (expandedPath.equals(expandedAutoloadPath)) {
113124
for (RubyConstant constant : entry.getValue()) {
114125
// Do not autoload recursively from the #require call in GetConstantNode
@@ -252,9 +263,7 @@ public String findFeatureImpl(String feature) {
252263
RubyContext.fileLine(sourceSection),
253264
originalFeature);
254265
});
255-
}
256266

257-
if (context.getOptions().LOG_FEATURE_LOCATION) {
258267
RubyLanguage.LOGGER.info(String.format("current directory: %s", getWorkingDirectory()));
259268
}
260269

@@ -392,7 +401,7 @@ public void ensureCExtImplementationLoaded(String feature, RequireNode requireNo
392401
throw new RaiseException(
393402
context,
394403
context.getCoreExceptions().loadError(
395-
"cannot load as C extensions are disabled with -Xcexts=false",
404+
"cannot load as C extensions are disabled with --ruby.cexts=false",
396405
feature,
397406
null));
398407
}

0 commit comments

Comments
 (0)