Skip to content

Add --file_write_strategy to Bazel #9

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

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Conversation

arvi18
Copy link

@arvi18 arvi18 commented Apr 16, 2025

Work towards bazelbuild#24808

RELNOTES: If the new --file_write_strategy flag is set to lazy, files produced by file write actions (e.g. the ones produced by ctx.actions.write and ctx.actions.expand_template) are not written to disk with BwoB unless required by local execution or upon explicit request. The default is eager, which retains the current behavior.

fmeum added 25 commits February 20, 2025 14:32
# Conflicts:
#	src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
#	src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java
#	src/main/java/com/google/devtools/build/lib/skyframe/CompletionFunction.java

# Conflicts:
#	src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
� Conflicts:
�	src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java
�	src/main/java/com/google/devtools/build/lib/remote/merkletree/DirectoryTree.java
�	src/main/java/com/google/devtools/build/lib/remote/merkletree/MerkleTree.java
# Conflicts:
#	src/test/java/com/google/devtools/build/lib/actions/ActionCacheCheckerTest.java
#	src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
@coderabbit-test coderabbit-test deleted a comment from arvi18 Aug 7, 2025
@visz11
Copy link
Collaborator

visz11 commented Aug 7, 2025

/refacto-test

Copy link

refacto-test bot commented Aug 7, 2025

Refacto is reviewing this PR. Please wait for the review comments to be posted.

Copy link

refacto-test bot commented Aug 7, 2025

Secure Implementation of Lazy File Writing Strategy

👍 Well Done
Secure Handling of Inline File Content

The implementation correctly handles inline file content with proper digest calculation and validation, preventing potential data tampering.

Proper Error Handling

The code includes appropriate error handling for IO exceptions and properly propagates them with detailed error codes.

Secure Temporary File Management

When files need to be materialized, the implementation uses secure temporary file handling to prevent path traversal issues.

📌 Files Processed
  • src/main/java/com/google/devtools/build/lib/actions/BUILD
  • src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java
  • src/main/java/com/google/devtools/build/lib/actions/cache/VirtualActionInput.java
  • src/main/java/com/google/devtools/build/lib/analysis/BUILD
  • src/main/java/com/google/devtools/build/lib/analysis/actions/DeterministicWriter.java
  • src/main/java/com/google/devtools/build/lib/analysis/actions/FileWriteActionContext.java
  • src/main/java/com/google/devtools/build/lib/analysis/actions/LocalTemplateExpansionStrategy.java
  • src/main/java/com/google/devtools/build/lib/exec/BUILD
  • src/main/java/com/google/devtools/build/lib/exec/EagerFileWriteStrategy.java
  • src/main/java/com/google/devtools/build/lib/exec/ExecutionOptions.java
  • src/main/java/com/google/devtools/build/lib/exec/LazyFileWriteStrategy.java
  • src/main/java/com/google/devtools/build/lib/remote/AbstractActionInputPrefetcher.java
  • src/main/java/com/google/devtools/build/lib/remote/RemoteActionFileSystem.java
  • src/main/java/com/google/devtools/build/lib/remote/RemoteActionInputFetcher.java
  • src/main/java/com/google/devtools/build/lib/remote/RemoteExecutionCache.java
  • src/main/java/com/google/devtools/build/lib/remote/RemoteOutputChecker.java
  • src/main/java/com/google/devtools/build/lib/remote/merkletree/BUILD
  • src/main/java/com/google/devtools/build/lib/remote/merkletree/DirectoryTree.java
  • src/main/java/com/google/devtools/build/lib/remote/merkletree/DirectoryTreeBuilder.java
  • src/main/java/com/google/devtools/build/lib/remote/merkletree/MerkleTree.java
  • src/main/java/com/google/devtools/build/lib/runtime/commands/RunCommand.java
  • src/main/java/com/google/devtools/build/lib/skyframe/FilesystemValueChecker.java
  • src/main/java/com/google/devtools/build/lib/standalone/StandaloneModule.java
  • src/main/java/com/google/devtools/build/lib/util/BUILD
  • src/main/java/com/google/devtools/build/lib/util/StreamWriter.java
  • src/test/java/com/google/devtools/build/lib/buildtool/ConvenienceSymlinkTest.java
  • src/test/java/com/google/devtools/build/lib/exec/BUILD
  • src/test/java/com/google/devtools/build/lib/exec/EagerFileWriteStrategyTest.java
  • src/test/java/com/google/devtools/build/lib/exec/LazyFileWriteStrategyTest.java
  • src/test/java/com/google/devtools/build/lib/exec/util/TestExecutorBuilder.java
  • src/test/java/com/google/devtools/build/lib/remote/BUILD
  • src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTest.java
  • src/test/java/com/google/devtools/build/lib/remote/BuildWithoutTheBytesIntegrationTestBase.java
  • src/test/java/com/google/devtools/build/lib/remote/RemoteActionFileSystemTest.java
  • src/test/java/com/google/devtools/build/lib/skyframe/FilesystemValueCheckerTest.java
📝 Additional Comments
src/main/java/com/google/devtools/build/lib/actions/FileArtifactValue.java (1)
Potential Timing Attack in Equals Method

The equals method in FileWriteOutputArtifactValue uses Arrays.equals() to compare digests, which does not perform a constant-time comparison. This could potentially be vulnerable to timing attacks if an attacker can measure the time it takes to compare digests. While this is a low risk in most scenarios, it's a security best practice to use constant-time comparisons for cryptographic material.

return Objects.equals(writer, that.writer)
    && size == that.size
    && MessageDigest.isEqual(digest, that.digest);

Standards:

  • CWE-208
  • A02:2021-Cryptographic Failures

public InputStream getInputStream() {
// TODO: Avoid materializing the full content in memory by using a variant of
// Piped{Input,Output}Stream that works well with virtual threads.
var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Integer.MAX_VALUE));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential Memory Exhaustion in Inline File Handling

The code attempts to allocate a ByteArrayOutputStream with a size potentially as large as Integer.MAX_VALUE. While there is a clamp function to limit the size, this could still lead to memory exhaustion if a malicious or corrupted file has a very large reported size. This could be exploited as a denial of service attack by causing the JVM to run out of memory when processing large files.

Suggested change
var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Integer.MAX_VALUE));
// Define a reasonable maximum size (e.g., 10MB)
private static final int MAX_IN_MEMORY_SIZE = 10 * 1024 * 1024;
var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Math.min(MAX_IN_MEMORY_SIZE, Integer.MAX_VALUE)));
Standards
  • CWE-400
  • A05:2021-Security Misconfiguration

Comment on lines +1079 to +1090
public InputStream getInputStream() {
// TODO: Avoid materializing the full content in memory by using a variant of
// Piped{Input,Output}Stream that works well with virtual threads.
var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Integer.MAX_VALUE));
try {
writeTo(out);
} catch (IOException e) {
// writer is not expected to throw if out doesn't.
throw new IllegalStateException(e);
}
return new ByteArrayInputStream(out.toByteArray());
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential Resource Leak in getInputStream Method

The getInputStream method creates a ByteArrayOutputStream, writes to it, and then returns a ByteArrayInputStream without closing the ByteArrayOutputStream. While ByteArrayOutputStream doesn't use system resources that need explicit closing, this pattern could lead to resource leaks with other stream implementations or if the implementation changes in the future. Additionally, the exception handling assumes the writer won't throw if the output stream doesn't, which may not always be true.

Suggested change
public InputStream getInputStream() {
// TODO: Avoid materializing the full content in memory by using a variant of
// Piped{Input,Output}Stream that works well with virtual threads.
var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Integer.MAX_VALUE));
try {
writeTo(out);
} catch (IOException e) {
// writer is not expected to throw if out doesn't.
throw new IllegalStateException(e);
}
return new ByteArrayInputStream(out.toByteArray());
}
public InputStream getInputStream() {
// TODO: Avoid materializing the full content in memory by using a variant of
// Piped{Input,Output}Stream that works well with virtual threads.
try (var out = new ByteArrayOutputStream(Math.clamp(getSize(), 0, Integer.MAX_VALUE))) {
try {
writeTo(out);
return new ByteArrayInputStream(out.toByteArray());
} catch (IOException e) {
// writer is not expected to throw if out doesn't.
throw new IllegalStateException(e);
}
}
}
Standards
  • CWE-772
  • A06:2021-Vulnerable and Outdated Components

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants