Summary
ValidationTarget.cachedTargets is declared public static HashMap<String, ValidationTarget>, making it fully accessible and mutable by any caller. The build() factory methods perform a containsKey → put → get sequence without synchronization, creating a race window where two threads can both see containsKey return false, both call put, and the second overwrites the first.
The field's visibility is public, so callers outside LabelUtil have no enforced synchronization — yet LabelUtil.getIdentifiersCommon is synchronized specifically to avoid corrupting this map (per its Javadoc).
Affected code
gov/nasa/pds/tools/validate/ValidationTarget.java, line ~30:
public static HashMap<String, ValidationTarget> cachedTargets = new HashMap<>();
Recommended fix
Make cachedTargets private static and replace HashMap with ConcurrentHashMap. Use computeIfAbsent in build() to atomically eliminate the check-then-act race.
Related
Identified during immutability/synchronization audit triggered by PR #1607 review feedback.
🤖 Generated with Claude Code
Summary
ValidationTarget.cachedTargetsis declaredpublic static HashMap<String, ValidationTarget>, making it fully accessible and mutable by any caller. Thebuild()factory methods perform acontainsKey→put→getsequence without synchronization, creating a race window where two threads can both seecontainsKeyreturn false, both callput, and the second overwrites the first.The field's visibility is
public, so callers outsideLabelUtilhave no enforced synchronization — yetLabelUtil.getIdentifiersCommonissynchronizedspecifically to avoid corrupting this map (per its Javadoc).Affected code
gov/nasa/pds/tools/validate/ValidationTarget.java, line ~30:Recommended fix
Make
cachedTargetsprivate staticand replaceHashMapwithConcurrentHashMap. UsecomputeIfAbsentinbuild()to atomically eliminate the check-then-act race.Related
Identified during immutability/synchronization audit triggered by PR #1607 review feedback.
🤖 Generated with Claude Code