-
Notifications
You must be signed in to change notification settings - Fork 641
LogFileManager.getLogString leaking Closeable during SessionReportingCoordinator.addLogsCustomKeysAndEventKeysToEvent #7403
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
base: main
Are you sure you want to change the base?
Conversation
…a RandomAccessFile instance, instead a reference for the underlying file is kept. See firebase#7341 for further context.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. |
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request refactors QueueFile.java
to address a potential resource leak by no longer holding a persistent RandomAccessFile
instance. While the overall approach is sound, the implementation introduces several critical bugs that could lead to NullPointerException
and ClosedChannelException
at runtime. I've identified issues in the QueueFile
constructor, the initialize
method, and the expandIfNecessary
method, and have provided code suggestions to resolve them. The related changes in QueueFileLogStore.java
are correct and align with the intended refactoring.
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Show resolved
Hide resolved
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
…sable' into crashlytics_strictmode_leakedclosable
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request successfully refactors QueueFile
to avoid holding a long-lived RandomAccessFile
instance, which resolves a potential resource leak. The new approach involves opening and closing the file on-demand for each operation. While this fixes the leak, it introduces a critical bug and several significant performance regressions where file operations are performed repeatedly, such as in loops or for stream-based reading. I have provided detailed comments on these issues with suggestions for how to resolve them while maintaining the leak-safe design.
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively addresses a potential resource leak in QueueFile
by refactoring it to not hold a persistent RandomAccessFile
instance. Instead, file operations are wrapped in a new openAndExecute
helper that manages the RandomAccessFile
lifecycle using try-with-resources. This is a solid improvement.
My review includes a high-severity point about a potential issue with nested file access that could arise from the new implementation of setLength
, and a suggestion to improve encapsulation for the clear
method. Overall, the changes are in the right direction to make the class more robust.
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
...e-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/metadata/QueueFile.java
Outdated
Show resolved
Hide resolved
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request effectively addresses a potential resource leak in QueueFile
by changing the strategy for handling RandomAccessFile
. Instead of holding a reference to an open file, the implementation now opens and closes the file for each operation, ensuring resources are properly managed using try-with-resources. This is a solid improvement for robustness. While this approach prioritizes correctness and leak prevention, it introduces a performance trade-off due to the overhead of repeated file open/close operations, which I've noted in a specific comment. The changes in QueueFileLogStore
are consistent with the QueueFile
refactoring. Overall, this is a good change that improves the reliability of the logging mechanism.
private final byte[] buffer = new byte[16]; | ||
|
||
/** | ||
* Constructs a new queue backed by the given file. Only one {@code QueueFile} instance should | ||
* access a given file at a time. | ||
*/ | ||
public QueueFile(File file) throws IOException { | ||
this.rafFile = file; | ||
if (!file.exists()) { | ||
initialize(file); | ||
} | ||
raf = open(file); | ||
readHeader(); | ||
} | ||
|
||
/** For testing. */ | ||
QueueFile(RandomAccessFile raf) throws IOException { | ||
this.raf = raf; | ||
readHeader(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This constructor, which was marked for testing, was very useful for injecting a mock RandomAccessFile
to unit test the class's logic without touching the file system. Its removal makes unit testing more difficult, as tests will now likely need to interact with real files. While the new design with openAndExecute
makes this kind of injection harder, it might be worth considering if there's an alternative way to maintain the same level of testability, perhaps by allowing injection of a RandomAccessFile
factory.
private void openAndExecute(RandomAccessFileCallable rafCallable) throws IOException { | ||
try (RandomAccessFile raf = open(rafFile)) { | ||
rafCallable.run(raf); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This new openAndExecute
pattern successfully prevents resource leaks by ensuring the RandomAccessFile
is always closed. However, it's worth noting the performance trade-off. Opening and closing a file for every operation (like add
, peek
, remove
) can introduce significant overhead compared to keeping the file handle open. For the use case of crash logging, this is likely an acceptable trade-off for improved robustness, but it's an important design consideration to be aware of if this class were to be used in a high-throughput scenario.
int readByte; | ||
raf.seek(position); | ||
int b = raf.read(); | ||
readByte = raf.read(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactoring QueueFile.java to avoid holding a leakable reference for a RandomAccessFile instance, instead a reference for the underlying file is kept. See #7341 for further context.