Skip to content

Bug: ReferentialIntegrityUtil and CrossLabelFileAreaReferenceChecker use unsynchronized static mutable collections #1619

Description

@jordanpadams

Summary

Both ReferentialIntegrityUtil and CrossLabelFileAreaReferenceChecker maintain static mutable HashMap/ArrayList/HashSet fields accessed from public methods that are not synchronized. In a multi-threaded validation run, concurrent access to these collections can produce ConcurrentModificationException, lost updates, or silently corrupted results.

ReferentialIntegrityUtil

All thirteen private static collection fields (lines ~54–145) use HashMap, ArrayList, or HashSet:

  • lidOrLidVidReferencesCumulative (ArrayList)
  • lidAndFilenameCombo (HashSet)
  • contextReferencesCumulative, bundleOrCollectionReferenceMap, bundleReferenceMap, collectionReferenceMap, bundleURLMap, labelIdentifierCache (all HashMap)
  • etc.

None of the methods that mutate or iterate these fields are synchronized. The catch (Exception e) blocks in performReporting() (~lines 345, 470) swallow all exceptions including ConcurrentModificationException, so concurrency failures produce only a stack trace on stderr and continue with corrupted state.

CrossLabelFileAreaReferenceChecker

final private static HashMap<String,Boolean> isObservational = new HashMap<>();
final private static HashMap<String,List<String>> knownRefs    = new HashMap<>();

add(), getOtherId(), and getOtherFilename() are all unsynchronized. The final modifier only prevents reference reassignment — the map contents remain fully mutable.

Recommended fix

  • Replace HashMap with ConcurrentHashMap and use atomic operations (computeIfAbsent, merge, putIfAbsent) where check-then-act patterns exist.
  • Replace ArrayList with CopyOnWriteArrayList or a synchronized wrapper.
  • Replace HashSet with ConcurrentHashMap.newKeySet().
  • Change catch (Exception e) in performReporting() to catch specific exception types and let unexpected runtime exceptions propagate (or rethrow as RuntimeException after logging).

Related

Identified during immutability/synchronization audit triggered by PR #1607 review feedback.

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    ToDo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions