Repository navigation
[P2] Do not report an atomic store that was never built from its read - #1193
Merged
Merged
Conversation
…1187) A get whose value is only logged, then a set from queue.size(), is correct, but the woven pair reports it as a PROMPT on AtomicNonAtomicUpdate. The end-to-end test fails on that finding (red, verified with CI=true mvn -pl async-test-agent -am test). The positive control, a set built from the read (counter.set(v + 1)), passes and must stay green. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
… from a read or not (#1187) The woven get-then-set rule reports a store from an unrelated size as a lost update, because the hook sees calls and not values. This adds the proof of concept for telling them apart from the class's own bytes: a taint pass over ASM's analysis of each method, where a bit marks what came from an atomic read. Verified by AtomicStoreTaintAnalysisTest: the unrelated store is not derived, a read-built store is derived, a two-word (long) value keeps its taint through the add, a constant store after a dropped read is not derived, a read reaching a store on one branch is derived, and a read of one atomic stored into another is derived by the conservative rule. Not yet wired into the weaver, so the end-to-end false positive is still red. Adds org.ow2.asm:asm-tree and asm-analysis at the root's asm.version, shaded into the agent jar with org.objectweb.asm relocated, since Byte Buddy's shaded ASM has no tree or analysis package. Verified: the 1.14.1 agent jar holds 98 relocated ASM entries and no unrelocated org/objectweb entries; the fast tier passes (lib 3905, agent 103). Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…ts read (#1187) AtomicNonAtomicUpdate reported a get followed by a plain store to the same atomic even when the stored value came from unrelated code. gauge.get() for a log line, then gauge.set(queue.size()), cannot lose an update, but the weaver routed every store to the hook that reports one, so correct code was flagged. The agent now reads each class's bytes from its loader, runs a taint analysis per method (AtomicStoreTaintAnalysis), and says for each atomic store whether the stored value was derived from an atomic read in that method. A store that was not derived is woven through a twin hook (<hook>Unrelated) that reports it as an update with no read before it. Covers set, lazySet, setPlain, setOpaque and setRelease on AtomicInteger, and set, lazySet and setRelease on AtomicLong. Stores are matched to verdicts by ordinal within the method, using one shared predicate, and a store the analysis cannot reach keeps its old hook. Verified: AtomicUnrelatedStoreWeavingEndToEndTest was red before this change (75 get+set sequences reported) and is green with CI=true, now including a lazySet case; AtomicDerivedStoreWeavingEndToEndTest, the positive control, is still green. AtomicStoreTaintAnalysisTest (7, including a dead-store ordinal case built with ASM), AtomicStoreTwinHooksTest, SubstitutionHooksArePointsTest and ControlledScheduleHookPointsTest pass. Fast tier: 3905 library tests and 106 agent tests, zero failures. Not done: the lazySet end-to-end case has not been shown red without its twin. Re-reading the class costs a second parse of every woven class when fields=true; not measured. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…eady has (#1187) AtomicStoreTaintAnalysis reads each class's atomic stores with unshaded ASM, which the Maven POM declares (asm, asm-tree, asm-analysis) and relocates into the agent jar. The Gradle build declared only Byte Buddy, so :async-test-agent:compileJava failed with "package org.objectweb.asm does not exist" in the Gradle Test Suite job. The Gradle build now declares the same three artifacts at the version the root build already reads from pom.xml (asm.version), and its shadowJar includes them and relocates org.objectweb.asm to se.deversity.asynctest.agent.shaded.asm, as the Maven shade does. Verified locally: ./gradlew :async-test-agent:compileJava succeeds, and :async-test-agent:shadowJar produces async-test-agent-1.14.1.jar with 98 shaded ASM entries, no org/objectweb entries, and Byte Buddy still relocated. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
The Maven verify gate (maven-pmd-plugin check) failed the Corpus Eval job with one violation: UnusedNullCheckInEquals at AtomicStoreTaintAnalysis:119. The null check on the expected descriptor came before descriptor.equals(expected), which PMD reads as a redundant null check. The expected descriptor is now chosen from the owner after the owner is known to be an AtomicInteger or AtomicLong, so it is never null and the check goes away. The predicate's result is unchanged. Verified locally: mvn -pl async-test-agent -am verify -DskipTests -Djacoco.skip=true passes; before this change the same command reported the one PMD violation above. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
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.
Why
AtomicNonAtomicUpdate reported a get followed by a plain store to the same atomic even when the
stored value came from unrelated code.
gauge.get()for a log line, thengauge.set(queue.size())cannot lose an update, but the weaver sent every store to the hook that reports one, so correct code
was flagged (#1187).
What
(
AtomicStoreTaintAnalysis). For each atomic store it records whether the stored value was derivedfrom an atomic read in the same method.
<hook>Unrelated. The twin reportsthe store as an update with no read before it. Twins exist for set, lazySet, setPlain, setOpaque and
setRelease on AtomicInteger, and for set, lazySet and setRelease on AtomicLong. Each twin keeps the
original's point and spin-lock release.
analysis and the weaver. A store the analysis cannot reach gets the conservative verdict, so later
stores keep their ordinals.
Verification
AtomicUnrelatedStoreWeavingEndToEndTest(CI=true) was red before this change withExpected no finding from detector 'AtomicNonAtomicUpdate', but got 1(75 get+set sequences) and isgreen now. It now includes a lazySet case.
AtomicDerivedStoreWeavingEndToEndTest, the positive control, is still green.AtomicStoreTaintAnalysisTest(7 tests, one built with ASM for a dead store afterreturn),AtomicStoreTwinHooksTest,SubstitutionHooksArePointsTestandControlledScheduleHookPointsTestpass.
Not verified: the lazySet end-to-end case has not been shown red without its twin, and the cost of
re-reading the class bytes has not been measured.
Docs
docs/CHANGELOG.md: Unreleased, Fixed entry with the known limit.AtomicStoreTaintAnalysis,FieldAccessWeaver.visitor, the weaverbranch, the twin hooks,
AsyncTestAgent.storeVerdicts).@AICorenote onAsyncTestAgentstill lists the store forms as they were. It isgenerated from the annotation, so it is left for the next vibetags regeneration.
Follow-ups
through a helper keeps the finding.
Fixes #1187
🤖 Generated with Claude Code
CI fixes on this branch
f702273c4gives the Gradle agent build the ASM artifacts Maven already declares and relocates them in its shadow jar. Without it,:async-test-agent:compileJavafailed in the Gradle Test Suite job. Verified locally:compileJavapasses, and the shadow jar has 98 shaded ASM entries and none underorg/objectweb.a685f3999removes a PMDUnusedNullCheckInEqualsviolation inAtomicStoreTaintAnalysis.isAtomicStore, which failed the Maven verify gate in Corpus Eval.agent_jctoolsHandOff_offererWritesAfterTheOffersilent, the known flake in [P3] Flaky: corpus agent-pairs row agent_jctoolsHandOff_offererWritesAfterTheOffer silent once #1133. Its re-run passed that gate. Other red jobs in this PR were GitHub infrastructure: a checkout that could not reach github.com, a Maven Central plugin that could not be fetched, and a runner that lost communication. Each was re-run and passed.