Skip to content

Fix java/unsynchronized-getter CodeQL alerts in DebugLogPublisher - #788

Merged
vharseko merged 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:fix-unsynchronized-getter
Jul 30, 2026
Merged

Fix java/unsynchronized-getter CodeQL alerts in DebugLogPublisher#788
vharseko merged 1 commit into
OpenIdentityPlatform:masterfrom
vharseko:fix-unsynchronized-getter

Conversation

@vharseko

Copy link
Copy Markdown
Member

Closes the two remaining error-severity code scanning alerts, #651 and #652 (java/unsynchronized-getter), on getClassSettings() and getMethodSettings().

#785 already made the trace settings maps concurrent, but the alerts stayed open: the rule is structural — a synchronized setter paired with an unsynchronized getter — and setClassSettings(), setMethodSettings() and removeTraceSettings() still held the monitor.

Rather than locking the getters, this makes the whole access path lock-free:

  • Both maps become final, eagerly created ConcurrentHashMaps. They are therefore safely published to every reader without volatile, and the null checks spread over four accessors go away — the constructor always adds the global scope, so null was unreachable anyway.
  • synchronized is dropped from all three mutators, so no method of the class is synchronized any more.
  • The compound updates keep their atomicity through ConcurrentHashMap.compute() keyed by class name. setMethodSettings() creates the enclosing map and inserts the setting in one atomic step; removeTraceSettings() removes the method and discards the map once it is empty in the same computation. Both go through compute() on the same key, so they remain mutually exclusive.

This matters beyond the alert: getMethodSettings() hands out the live inner map, which DebugTracer caches and reads on the hot traceException() path while an administrative change to a debug target can be mutating it.

Behaviour is unchanged — the walk up the scope hierarchy, the global fallback that only applies while size() == 1, the null returned by getMethodSettings() when no method-level tracing is configured, and the removed settings returned by removeTraceSettings(). The javadoc of getMethodSettings() was also promising an unmodifiable map while returning a live one; it now describes what it returns.

TraceSettings still mutates its own non-volatile fields from applyConfigurationChange() while tracer threads read them. CodeQL does not flag it and it needs a different fix (make the class immutable and replace the instance in the map), so it is left out of this change.

Testing

New DebugLogPublisherTest covers the defaults, the global fallback, the most-specific-scope resolution, the method settings bookkeeping, dropping the enclosing map with its last method setting, and a contention test (4 writers × 2 readers × 5000 rounds) asserting that no setting is lost.

  • mvn -pl opendj-server-legacy test-compile — success; DebugLogPublisherTest 6/6 and the neighbouring TraceSettingsTest 3/3 pass.
  • Negative control: rebuilding the class with non-atomic mutators (get-then-put, remove-then-cleanup) makes the contention test fail, so it does guard the compute() atomicity rather than passing vacuously.

The trace settings maps were mutated under synchronized setters while the
getters read them without any lock, which CodeQL flags as inconsistent
synchronization (alerts 651 and 652).

Make the access lock-free instead of locking the getters: both maps are now
final, eagerly created ConcurrentHashMaps, so they are safely published and
the null checks spread over the accessors become unnecessary. The compound
updates keep their atomicity through ConcurrentHashMap.compute() on the
class name: adding a method setting creates the enclosing map and inserts
in one atomic step, and removing the last method setting discards that map
without racing against a concurrent insertion.

Add DebugLogPublisherTest covering the scope resolution, the removal
bookkeeping and the concurrent add/remove path.
@vharseko
vharseko requested a review from maximthomas July 30, 2026 08:22
@vharseko vharseko added security Security fixes / CodeQL code-scanning alerts concurrency Thread-safety / race-condition bugs java Pull requests that update java code tests Test suites: fixing, enabling, un-disabling labels Jul 30, 2026
@vharseko
vharseko merged commit 8c46e65 into OpenIdentityPlatform:master Jul 30, 2026
16 of 17 checks passed
@vharseko
vharseko deleted the fix-unsynchronized-getter branch July 30, 2026 13:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

concurrency Thread-safety / race-condition bugs java Pull requests that update java code security Security fixes / CodeQL code-scanning alerts tests Test suites: fixing, enabling, un-disabling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants