-
Notifications
You must be signed in to change notification settings - Fork 437
Add RLC-only SideEffectFree stubs and tests #7609
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
kelloggm
merged 14 commits into
typetools:master
from
iamsanjaymalakar:rlc-sideeffect-stub
Apr 21, 2026
Merged
Changes from 10 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
77d5a28
Add RLC-only SideEffectFree stubs and tests
iamsanjaymalakar e1d5221
Merge branch 'master' into rlc-sideeffect-stub
iamsanjaymalakar 22fac31
Add Logger stubs/tests for Log4j 1.x and 2.x
iamsanjaymalakar d72e909
Expand RLC Log4j side-effect-free stubs and tests
iamsanjaymalakar 4abfe12
Merge branch 'master' into rlc-sideeffect-stub
iamsanjaymalakar 5d5fd21
Fix Log4j Message import and throwable regression test
iamsanjaymalakar e8970a4
Addresses PR comments.
iamsanjaymalakar 2806c28
Merge branch 'master' into rlc-sideeffect-stub
iamsanjaymalakar e910131
Logging methods are side-effect-free for all checkers.
iamsanjaymalakar d8032c6
Merge branch 'master' into rlc-sideeffect-stub
iamsanjaymalakar 6b44afe
Fix typo.
iamsanjaymalakar 0684ef0
Loading log4j stubs on for RLC.
iamsanjaymalakar d3c9a8a
Merge branch 'master' into rlc-sideeffect-stub
iamsanjaymalakar 6b94234
Resolve merge conflict.
iamsanjaymalakar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
19 changes: 19 additions & 0 deletions
19
checker/src/main/java/org/checkerframework/checker/rlccalledmethods/jdk.astub
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package java.lang; | ||
|
|
||
| import org.checkerframework.checker.lock.qual.GuardSatisfied; | ||
| import org.checkerframework.dataflow.qual.SideEffectFree; | ||
|
|
||
| public interface AutoCloseable { | ||
| @SideEffectFree | ||
| void close(@GuardSatisfied AutoCloseable this) throws Exception; | ||
| } | ||
|
|
||
| package java.io; | ||
|
|
||
| import org.checkerframework.checker.lock.qual.GuardSatisfied; | ||
| import org.checkerframework.dataflow.qual.SideEffectFree; | ||
|
|
||
| public interface Closeable extends AutoCloseable { | ||
| @SideEffectFree | ||
| public void close(@GuardSatisfied Closeable this) throws IOException; | ||
| } | ||
|
iamsanjaymalakar marked this conversation as resolved.
|
||
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
25 changes: 25 additions & 0 deletions
25
checker/tests/resourceleak/sideeffect-free-stubs-tests/AutoCloseableClose.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // RLC uses Called Methods facts to remember that a resource has already been closed. | ||
| // This test checks that the RLC-specific SideEffectFree stub for AutoCloseable.close() | ||
| // preserves those facts across another close call in the same destructor, rather than | ||
| // conservatively forgetting them after the first invocation. | ||
|
|
||
| import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods; | ||
| import org.checkerframework.checker.mustcall.qual.Owning; | ||
|
|
||
| class AutoCloseableClose implements AutoCloseable { | ||
| private @Owning AutoCloseable first = new AutoClosableResource(); | ||
| private @Owning AutoCloseable second = new AutoClosableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods( | ||
| value = {"this.first", "this.second"}, | ||
| methods = "close") | ||
| public void close() { | ||
| try { | ||
| first.close(); | ||
| second.close(); | ||
| } catch (Exception e) { | ||
| throw new AssertionError(e); | ||
| } | ||
| } | ||
|
iamsanjaymalakar marked this conversation as resolved.
|
||
| } | ||
14 changes: 14 additions & 0 deletions
14
checker/tests/resourceleak/sideeffect-free-stubs-tests/ClosableResource.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| // Class representing reources that implements Closable and Autoclosable to be used by other tests | ||
| // in this directory. | ||
|
|
||
| import java.io.Closeable; | ||
|
|
||
| final class CloseableResource implements Closeable { | ||
| @Override | ||
| public void close() {} | ||
| } | ||
|
|
||
| final class AutoClosableResource implements AutoCloseable { | ||
| @Override | ||
| public void close() {} | ||
| } | ||
|
iamsanjaymalakar marked this conversation as resolved.
Outdated
|
||
29 changes: 29 additions & 0 deletions
29
checker/tests/resourceleak/sideeffect-free-stubs-tests/CloseableClose.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| // RLC uses Called Methods facts to remember that a resource has already been closed. | ||
| // This test checks that the RLC-specific SideEffectFree stub for Closeable.close() | ||
| // preserves those facts across another close call in the same destructor, rather than | ||
| // conservatively forgetting them after the first invocation. | ||
|
|
||
| import java.io.Closeable; | ||
| import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods; | ||
| import org.checkerframework.checker.mustcall.qual.Owning; | ||
|
|
||
| class CloseableClose implements Closeable { | ||
| private @Owning Closeable first = new CloseableResource(); | ||
| private @Owning Closeable second = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods( | ||
| value = {"this.first", "this.second"}, | ||
| methods = "close") | ||
| public void close() { | ||
| try { | ||
| try { | ||
| first.close(); | ||
| } catch (Exception ignored) { | ||
| } | ||
| second.close(); | ||
| } catch (Exception e) { | ||
| throw new AssertionError(e); | ||
| } | ||
| } | ||
| } |
68 changes: 68 additions & 0 deletions
68
checker/tests/resourceleak/sideeffect-free-stubs-tests/Log4j1ObjectCalls.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // This test covers the Log4j 1.x API in package org.apache.log4j. | ||
| // The RLC-specific stub marks logging methods as @SideEffectFree, so logging after a resource is | ||
| // closed should not wipe out the close fact. | ||
|
|
||
| import java.io.Closeable; | ||
| import org.apache.log4j.Logger; | ||
| import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods; | ||
| import org.checkerframework.checker.mustcall.qual.Owning; | ||
|
|
||
| class Log4j1DebugObject implements Closeable { | ||
| private final Logger logger = Logger.getLogger("Log4j1DebugObject"); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.debug("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j1DebugWithThrowable implements Closeable { | ||
| private final Logger logger = Logger.getLogger("Log4j1DebugWithThrowable"); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.debug("after close", new RuntimeException()); | ||
| } | ||
| } | ||
|
|
||
| class Log4j1InfoObject implements Closeable { | ||
| private final Logger logger = Logger.getLogger("Log4j1InfoObject"); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.info("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j1WarnObject implements Closeable { | ||
| private final Logger logger = Logger.getLogger("Log4j1WarnObject"); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.warn("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j1ErrorObject implements Closeable { | ||
| private final Logger logger = Logger.getLogger("Log4j1ErrorObject"); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.error("after close"); | ||
| } | ||
| } |
81 changes: 81 additions & 0 deletions
81
checker/tests/resourceleak/sideeffect-free-stubs-tests/Log4j2ObjectCalls.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| // This test covers the Log4j 2.x API in package org.apache.logging.log4j. | ||
| // real library API. The RLC-specific stub marks logging methods as @SideEffectFree, so logging | ||
| // after a resource is closed should not wipe out the close fact. | ||
|
iamsanjaymalakar marked this conversation as resolved.
|
||
|
|
||
| import java.io.Closeable; | ||
| import org.apache.logging.log4j.LogManager; | ||
| import org.apache.logging.log4j.Logger; | ||
| import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods; | ||
| import org.checkerframework.checker.mustcall.qual.Owning; | ||
|
|
||
| class Log4j2DebugObject implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.debug("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j2DebugVarargs implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.debug("closed resource {}", "name"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j2InfoObject implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.info("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j2WarnObject implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.warn("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j2ErrorObject implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.error("after close"); | ||
| } | ||
| } | ||
|
|
||
| class Log4j2ErrorWithThrowable implements Closeable { | ||
| private static final Logger logger = LogManager.getLogger(); | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| logger.error("after close", new RuntimeException()); | ||
| } | ||
| } | ||
|
iamsanjaymalakar marked this conversation as resolved.
|
||
47 changes: 47 additions & 0 deletions
47
checker/tests/resourceleak/sideeffect-free-stubs-tests/ThrowablePrintStackTrace.java
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| // RLC-specific stubs mark Throwable.printStackTrace overloads as SideEffectFree so | ||
| // that debugging/logging after a resource is closed does not wipe out the close fact. | ||
| // This file checks the no-arg, PrintStream, and PrintWriter variants. | ||
|
|
||
| import java.io.Closeable; | ||
| import java.io.PrintStream; | ||
| import java.io.PrintWriter; | ||
| import java.io.StringWriter; | ||
| import org.checkerframework.checker.calledmethods.qual.EnsuresCalledMethods; | ||
| import org.checkerframework.checker.mustcall.qual.Owning; | ||
|
|
||
| class ThrowablePrintStackTrace implements Closeable { | ||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| new RuntimeException("debug").printStackTrace(); | ||
| } | ||
| } | ||
|
|
||
| class ThrowablePrintStackTracePrintStream implements Closeable { | ||
| private static final PrintStream STREAM = System.err; | ||
|
|
||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| new RuntimeException("debug").printStackTrace(STREAM); | ||
| } | ||
| } | ||
|
|
||
| class ThrowablePrintStackTracePrintWriter implements Closeable { | ||
| private static final PrintWriter WRITER = new PrintWriter(new StringWriter()); | ||
|
|
||
| private @Owning CloseableResource resource = new CloseableResource(); | ||
|
|
||
| @Override | ||
| @EnsuresCalledMethods(value = "this.resource", methods = "close") | ||
| public void close() { | ||
| resource.close(); | ||
| new RuntimeException("debug").printStackTrace(WRITER); | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.