8287101: CDS should check for file truncation for all regions

Reviewed-by: iklam, coleenp
This commit is contained in:
Calvin Cheung 2022-06-06 21:56:01 +00:00
parent 0e06bf3b04
commit 124ba45fb8
3 changed files with 44 additions and 8 deletions
src/hotspot/share/cds
test
hotspot/jtreg/runtime/cds/appcds
lib/jdk/test/lib/cds

@ -1370,12 +1370,10 @@ bool FileMapInfo::init_from_file(int fd) {
_file_offset = header()->header_size(); // accounts for the size of _base_archive_name
if (is_static()) {
// just checking the last region is sufficient since the archive is written
// in sequential order
size_t len = os::lseek(fd, 0, SEEK_END);
FileMapRegion* si = space_at(MetaspaceShared::last_valid_region);
// The last space might be empty
size_t len = os::lseek(fd, 0, SEEK_END);
for (int i = 0; i <= MetaspaceShared::last_valid_region; i++) {
FileMapRegion* si = space_at(i);
if (si->file_offset() > len || len - si->file_offset() < si->used()) {
fail_continue("The shared archive file has been truncated.");
return false;

@ -76,7 +76,7 @@ public class SharedArchiveConsistency {
return newArchiveName;
}
public static void testAndCheck(String[] execArgs) throws Exception {
public static void testAndCheck(String[] execArgs, String... expectedMessages) throws Exception {
OutputAnalyzer output = shareAuto ? TestCommon.execAuto(execArgs) : TestCommon.execCommon(execArgs);
String stdtxt = output.getOutput();
System.out.println("Note: this test may fail in very rare occasions due to CRC32 checksum collision");
@ -88,6 +88,9 @@ public class SharedArchiveConsistency {
output.shouldNotContain("A fatal error has been detected by the Java Runtime Environment");
}
}
for (int i = 0; i < expectedMessages.length; i++) {
output.shouldContain(expectedMessages[i]);
}
for (String message : matchMessages) {
if (stdtxt.contains(message)) {
// match any to return
@ -236,11 +239,17 @@ public class SharedArchiveConsistency {
testAndCheck(verifyExecArgs);
// delete bytes in data section forward
System.out.println("\n6. Delete bytes at beginning of data section, should fail\n");
System.out.println("\n6a. Delete bytes at beginning of data section, should fail\n");
String deleteBytes = startNewArchive("delete-bytes");
CDSArchiveUtils.deleteBytesAtRandomPositionAfterHeader(orgJsaFile, deleteBytes, 4096 /*bytes*/);
testAndCheck(verifyExecArgs);
// delete bytes at the end
System.out.println("\n6b. Delete bytes at the end, should fail\n");
deleteBytes = startNewArchive("delete-bytes-end");
CDSArchiveUtils.deleteBytesAtTheEnd(orgJsaFile, deleteBytes);
testAndCheck(verifyExecArgs, "The shared archive file has been truncated.");
// modify contents in random area
System.out.println("\n7. modify Content in random areas, should fail\n");
String randomAreas = startNewArchive("random-areas");

@ -461,6 +461,35 @@ public class CDSArchiveUtils {
return dstFile;
}
// returns the size of the last region with used bytes > 0.
private static long getLastUsedRegionSize(File jsaFile) throws Exception {
int i = num_regions - 1;
long regionSize = 0;
while (i >= 0) {
regionSize = usedRegionSizeAligned(jsaFile, i);
if (regionSize > 0) {
break;
}
i--;
}
return regionSize;
}
// delete last regions's used bytes at the end, so new file will be smaller than the original
public static File deleteBytesAtTheEnd(File orgFile, String newFileName) throws Exception {
long offset = fileHeaderSize(orgFile);
long bytesToDelete = getLastUsedRegionSize(orgFile);
File dstFile = new File(newFileName);
try (FileChannel inputChannel = new FileInputStream(orgFile).getChannel();
FileChannel outputChannel = new FileOutputStream(dstFile).getChannel()) {
long orgSize = inputChannel.size();
transferFrom(inputChannel, outputChannel, 0, offset);
inputChannel.position(offset);
transferFrom(inputChannel, outputChannel, offset, orgSize - bytesToDelete);
}
return dstFile;
}
// used region size
public static long usedRegionSizeAligned(File archiveFile, int region) throws Exception {
long offset = spOffset + cdsFileMapRegionSize * region + spUsedOffset;