Fix null-pointer dereferences flagged by CodeQL java/dereferenced-value-may-be-null#225
Open
vharseko wants to merge 2 commits into
Open
Conversation
…ue-may-be-null Fix 12 genuine null-dereference defects across commons, script and persistit. In each case a value that can be null - per an explicit guard elsewhere or an unassigned local - was dereferenced. - AsciiDocTable.columnsPerRow: the range check dereferenced the Integer field this.columnsPerRow, which is provably null at that point (the preceding guard returns otherwise), so the setter always threw NPE. Check the int parameter. - JWK constructor: the "new JsonException(...)" guarding a null kty was never thrown, so kty fell through to kty.toString() and NPE'd. Add the missing throw; kty is required (RFC 7517 section 4.1). kid is optional (RFC 7517 section 4.5), so drop its dead exception and only store it when present, rather than making it mandatory - a mandatory kid rejects the keyless JWKs used by the JWE spec examples (RSAEncryptionHandlerTest). - DateUtil.getDateDifferenceInDays: the Integer result stayed null for null input dates and was unboxed on return. Throw IllegalArgumentException instead. - ScriptRegistryImpl.isDependOn: the guard used || instead of &&, so source or dependency could be null when dereferenced. Use &&. - ScriptExecutor.execute: the "null == scriptEngine" check had an empty body and fell through to scriptEngine.eval(). Throw ScriptException. - ManagementImpl.getLogicalRecordArray: the finally block dereferenced a possibly unassigned exchange, masking the original exception. Guard with a null check. - DefaultObjectCoder key encode/decode: the catch handlers called accessor.toString() when accessor could still be null. Use String.valueOf. - AdminUI: newPanel.setDefaultButton() ran outside the newPanel != null guard, and _buttonList.size() ran after a "_buttonList != null" block that could leave it null. Move/fold both into their guards. - AdminUITreePanel: treeInfoArray was dereferenced without a null check. Add one. - Exchange traversal loop: buffer was dereferenced without the null guard already applied just above it; add "&& buffer != null" so the loop ends cleanly. - RecoveryManager: lastRequiredPageNode is set in lockstep with the address that gates this block, so it is non-null here; guard the validate() call to make that explicit. - BufferPool.invalidateSmallVolume: this per-page variant requires a concrete volume, so the copy-pasted "|| volume == null" match clauses were dead code that made the analyzer treat volume as nullable at the loop bound. Remove them; the live "invalidate all" idiom stays in invalidateLargeVolume. - InspectorPanel.refresh: pass the already null-checked local record to Fetcher instead of re-reading the field, removing both the potential NPE and a race. Behaviour is unchanged on the non-error paths; only guaranteed or latent NPEs are avoided. The remaining alerts for this rule are dismissed as false positives (correlated invariants the analyzer cannot prove).
a911e42 to
e2770c0
Compare
maximthomas
approved these changes
Jul 8, 2026
ee2887e to
31e9c6d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Resolves 16 real
java/dereferenced-value-may-be-nullCodeQL alerts by fixinggenuine null-pointer dereferences. Each is a place where a value that can be null
— per an explicit guard elsewhere, or an unassigned local — is dereferenced.
Fixes
rest/api-descriptorAsciiDocTablethis.columnsPerRow(provablynullthere) instead of theintparameter — the setter always threw NPE.json-web-tokenJWKnew JsonException(...)guarding a nullktywas never thrown, soktyreachedkty.toString()(NPE). Added the missingthrow(ktyis required per RFC 7517 §4.1).kidis optional (RFC 7517 §4.5), so its dead exception is dropped and it is only stored when present.audit/coreDateUtilInteger result, returned asint, wasnullfor null input dates → unboxing NPE. Now throwsIllegalArgumentException.script/commonScriptRegistryImpl||instead of&&, sosource/dependencycould be null when dereferenced.script/commonScriptExecutorif (null == scriptEngine)body fell through to.eval(). Now throwsScriptException.persistit/coreManagementImplfinallydereferenced a possibly-unassignedexchange, masking the real exception. Guarded with a null check.persistit/coreDefaultObjectCodercatchhandlers calledaccessor.toString()withaccessorpossibly null. UseString.valueOf(accessor).persistit/uiAdminUInewPanel.setDefaultButton()outside its null guard;_buttonList.size()after a null-tolerating block.persistit/uiAdminUITreePaneltreeInfoArray.lengthwithout a null check.persistit/coreExchangebufferwithout the null guard applied just above; added&& buffer != nullto the loop condition.persistit/coreRecoveryManagerlastRequiredPageNode(set in lockstep with the gating address) dereferenced; guarded thevalidate()call to make the invariant explicit.persistit/coreBufferPoolinvalidateSmallVolume(per-page) requires a concrete volume; the copy-pasted|| volume == nullmatch clauses were dead code that made the analyzer treatvolumeas nullable. Removed them — behaviour-identical for a real volume; the live "invalidate all" idiom stays ininvalidateLargeVolume.persistit/uiInspectorPanelFetcherre-read the record field; pass the already null-checked local instead — removes the potential NPE and a TOCTOU race.Behaviour
Non-error paths are unchanged; the changes only avoid NPEs that were either
guaranteed (
AsciiDocTable,JWK) or latent on error/edge paths.JWKkeepskidoptional (RFC 7517 §4.5) so the keyless JWKs built from the JWE specexamples continue to parse.
Not in this PR
Of the 25 alerts for this rule, the other 9 are high-confidence false positives
(correlated invariants CodeQL cannot prove — e.g. boxed primitives in
ValueInspectorTreeNode, acorrupt()that always throws inExchange) and weredismissed on GitHub.
Testing
mvn -o -pl commons/rest/api-descriptor,commons/json-web-token,commons/audit/core,script/common,persistit/core,persistit/ui compile— all six modules compile.mvn -o -pl commons/json-web-token test— 328 tests, 0 failures, 0 errors.