Skip to content
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

8286978: SIGBUS in libz during CDS initialization #8799

Closed
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -409,17 +409,39 @@ public static long writeData(File file, long offset, int value) throws Exception
}
}

// Helper method for calling FileChannel.transferFrom and checking the
// return value.
private static void transferFrom(FileChannel inputChannel,
FileChannel outputChannel,
long offset,
long length) throws Exception {
long position = offset;
long count = length;
long n = count;
// The count != offset check is for handling the case where the length
// of the outputChannel is shorter than the inputChannel.
while (count > 0 && n > 0 && count != offset) {
n = (long)outputChannel.transferFrom(inputChannel, position, count);
if (n < 0 || n > count) {
throw new RuntimeException("Incorrect transfer length n = " + n
+ " (expected 0 <= n <= " + length + ")");
}
position += n;
count -= n;
}
}

// dstFile will keep original size so will remove corresponding bytes.length bytes at end of file
public static File insertBytesRandomlyAfterHeader(File orgFile, String newFileName, byte[] bytes) throws Exception {
long offset = fileHeaderSize(orgFile) + getRandomBetween(0L, 4096L);
File dstFile = new File(newFileName);
try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {
long orgSize = inputChannel.size();
outputChannel.transferFrom(inputChannel, 0, offset);
transferFrom(inputChannel, outputChannel, 0, offset);
outputChannel.position(offset);
outputChannel.write(ByteBuffer.wrap(bytes));
Copy link
Member

@iklam iklam May 20, 2022

Choose a reason for hiding this comment

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

The changes for transferFrom looks good, but we still have a problem with outputChannel.write(), which can also return fewer bytes than requested (or even zero).

For simplicity, I think it's best to ditch FileChannel and use FileOutputStream.write() instead.

Copy link
Member

@iklam iklam May 20, 2022

Choose a reason for hiding this comment

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

Another option is to avoid using outputChannel.write(). Instead, duplicate some bytes from the end of the header.

    public static File insertBytesRandomlyAfterHeader(File orgFile, String newFileName) throws Exception {
        long headerSize = fileHeaderSize(orgFile);
        long dupSize = getRandomBetween(0L, headerSize);
        File dstFile = new File(newFileName);
        try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
             FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {
            long orgSize = inputChannel.size();
            // Copy the header
            transferFrom(inputChannel, outputChannel, 0, headerSize);
            // Copy dupSize bytes from the end of the header. Then, copy the rest
            // of the input such that the new file will have the same size as
            // the old file.
            inputChannel.position(headerSize - dupSize);
            transferFrom(inputChannel, outputChannel, headerSize, orgSize - headerSize);
        }
        return dstFile;
    }

Copy link
Member Author

@calvinccheung calvinccheung May 20, 2022

Choose a reason for hiding this comment

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

Thanks for the suggestions. I've pushed another commit with the above changes. I also changed the callsite in SharedArchiveConsistency.java since there's no need to pass in a byte array.

outputChannel.transferFrom(inputChannel, offset + bytes.length, orgSize - bytes.length);
transferFrom(inputChannel, outputChannel, offset + bytes.length, orgSize - bytes.length);
}
return dstFile;
}
@@ -431,9 +453,10 @@ public static File deleteBytesAtRandomPositionAfterHeader(File orgFile, String n
try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {
long orgSize = inputChannel.size();
outputChannel.transferFrom(inputChannel, 0, offset);
transferFrom(inputChannel, outputChannel, 0, offset);
inputChannel.position(offset + nBytes);
outputChannel.transferFrom(inputChannel, offset, orgSize - nBytes);
long length = orgSize - nBytes;
Copy link
Member

@iklam iklam May 20, 2022

Choose a reason for hiding this comment

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

Line 458 doesn't seem to be needed.

Copy link
Member Author

@calvinccheung calvinccheung May 20, 2022

Choose a reason for hiding this comment

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

transferFrom(inputChannel, outputChannel, offset, orgSize - nBytes);
}
return dstFile;
}