From 8f28809aa87b1026cdbdd1ea88da3c7f0c994697 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 10 Aug 2023 07:21:47 +0000 Subject: [PATCH] 8299790: os::print_hex_dump is racy Reviewed-by: shade, dholmes --- src/hotspot/share/runtime/os.cpp | 65 +++++++++++++++++++++----- test/hotspot/gtest/runtime/test_os.cpp | 30 ++++++------ 2 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 89511362dc1..08d0b0066f4 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -928,13 +928,58 @@ bool os::print_function_and_library_name(outputStream* st, return have_function_name || have_library_name; } -ATTRIBUTE_NO_ASAN static void print_hex_readable_pointer(outputStream* st, address p, - int unitsize) { - switch (unitsize) { - case 1: st->print("%02x", *(u1*)p); break; - case 2: st->print("%04x", *(u2*)p); break; - case 4: st->print("%08x", *(u4*)p); break; - case 8: st->print("%016" FORMAT64_MODIFIER "x", *(u8*)p); break; +ATTRIBUTE_NO_ASAN static bool read_safely_from(intptr_t* p, intptr_t* result) { + const intptr_t errval = 0x1717; + intptr_t i = SafeFetchN(p, errval); + if (i == errval) { + i = SafeFetchN(p, ~errval); + if (i == ~errval) { + return false; + } + } + (*result) = i; + return true; +} + +static void print_hex_location(outputStream* st, address p, int unitsize) { + address pa = align_down(p, sizeof(intptr_t)); +#ifndef _LP64 + // Special handling for printing qwords on 32-bit platforms + if (unitsize == 8) { + intptr_t i1, i2; + if (read_safely_from((intptr_t*)pa, &i1) && + read_safely_from((intptr_t*)pa + 1, &i2)) { + const uint64_t value = + LITTLE_ENDIAN_ONLY((((uint64_t)i2) << 32) | i1) + BIG_ENDIAN_ONLY((((uint64_t)i1) << 32) | i2); + st->print("%016" FORMAT64_MODIFIER "x", value); + } else { + st->print_raw("????????????????"); + } + return; + } +#endif // 32-bit, qwords + intptr_t i = 0; + if (read_safely_from((intptr_t*)pa, &i)) { + const int offset = (int)(p - (address)pa); + const int bitoffset = + LITTLE_ENDIAN_ONLY(offset * BitsPerByte) + BIG_ENDIAN_ONLY((int)(sizeof(intptr_t) - 1 - offset) * BitsPerByte); + const int bitfieldsize = unitsize * BitsPerByte; + intptr_t value = bitfield(i, bitoffset, bitfieldsize); + switch (unitsize) { + case 1: st->print("%02x", (u1)value); break; + case 2: st->print("%04x", (u2)value); break; + case 4: st->print("%08x", (u4)value); break; + case 8: st->print("%016" FORMAT64_MODIFIER "x", (u8)value); break; + } + } else { + switch (unitsize) { + case 1: st->print_raw("??"); break; + case 2: st->print_raw("????"); break; + case 4: st->print_raw("????????"); break; + case 8: st->print_raw("????????????????"); break; + } } } @@ -955,11 +1000,7 @@ void os::print_hex_dump(outputStream* st, address start, address end, int unitsi // Print out the addresses as if we were starting from logical_start. st->print(PTR_FORMAT ": ", p2i(logical_p)); while (p < end) { - if (is_readable_pointer(p)) { - print_hex_readable_pointer(st, p, unitsize); - } else { - st->print("%*.*s", 2*unitsize, 2*unitsize, "????????????????"); - } + print_hex_location(st, p, unitsize); p += unitsize; logical_p += unitsize; cols++; diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index fb2ab86a7b9..d44dc3216ee 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -169,31 +169,31 @@ static void do_test_print_hex_dump(address addr, size_t len, int unitsize, const buf[0] = '\0'; stringStream ss(buf, sizeof(buf)); os::print_hex_dump(&ss, addr, addr + len, unitsize); -// tty->print_cr("expected: %s", expected); -// tty->print_cr("result: %s", buf); - ASSERT_NE(strstr(buf, expected), (char*)NULL); + // tty->print_cr("expected: %s", expected); + // tty->print_cr("result: %s", buf); + EXPECT_THAT(buf, testing::HasSubstr(expected)); } TEST_VM(os, test_print_hex_dump) { const char* pattern [4] = { #ifdef VM_LITTLE_ENDIAN - "00 01 02 03 04 05 06 07", - "0100 0302 0504 0706", - "03020100 07060504", - "0706050403020100" + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", + "0100 0302 0504 0706 0908 0b0a 0d0c 0f0e", + "03020100 07060504 0b0a0908 0f0e0d0c", + "0706050403020100 0f0e0d0c0b0a0908" #else - "00 01 02 03 04 05 06 07", - "0001 0203 0405 0607", - "00010203 04050607", - "0001020304050607" + "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f", + "0001 0203 0405 0607 0809 0a0b 0c0d 0e0f", + "00010203 04050607 08090a0b 0c0d0e0f", + "0001020304050607 08090a0b0c0d0e0f" #endif }; const char* pattern_not_readable [4] = { - "?? ?? ?? ?? ?? ?? ?? ??", - "???? ???? ???? ????", - "???????? ????????", - "????????????????" + "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??", + "???? ???? ???? ???? ???? ???? ???? ????", + "???????? ???????? ???????? ????????", + "???????????????? ????????????????" }; // On AIX, zero page is readable.