RFR: 8313796: AsyncGetCallTrace crash on unreadable interpreter method pointer [v2]
Andrew Haley
aph at openjdk.org
Mon Aug 7 21:19:31 UTC 2023
On Mon, 7 Aug 2023 21:03:28 GMT, Richard Startin <duke at openjdk.org> wrote:
>> src/hotspot/cpu/aarch64/frame_aarch64.cpp line 514:
>>
>>> 512: return false;
>>> 513: }
>>> 514: Method* m = *m_addr;
>>
>> Suggestion:
>>
>> Method* m_addr = interpreter_frame_method_addr();
>> if (m_addr == nullptr) {
>> return false;
>> }
>> Method* m = SafeFetchN(m_addr, nullptr);
>> if (m == nullptr) {
>> return false;
>> }
>>
>>
>> Reason: more robust against changes in memory map, faster.
>
> Thanks for raising this. It doesn't look like `SafeFetchN` is async signal safe because it calls into this:
>
>
> template <class T>
> ATTRIBUTE_NO_ASAN static bool _SafeFetchXX_internal(const T *adr, T* result) {
>
> T n = 0;
>
> // Set up a jump buffer. Anchor its pointer in TLS. Then read from the unsafe address.
> // If that address was invalid, we fault, and in the signal handler we will jump back
> // to the jump point.
> sigjmp_buf jb;
> if (sigsetjmp(jb, 1) != 0) {
> // We faulted. Reset TLS slot, then return.
> pthread_setspecific(g_jmpbuf_key, nullptr);
> *result = 0;
> return false;
> }
>
> // Anchor jump buffer in TLS
> pthread_setspecific(g_jmpbuf_key, &jb);
>
> // unsafe access
> n = *adr;
>
> // Still here... All went well, adr was valid.
> // Reset TLS slot, then return result.
> pthread_setspecific(g_jmpbuf_key, nullptr);
> *result = n;
>
> return true;
>
> }
>
>
> This means we shouldn't be calling `os:: is_readable_pointer` either here, because it calls `SafeFetch32` which calls into the same function above. I had originally intended to simply perform a null check here (because that's the condition we've actually observed) and will push a change to revert to the null check.
> Thanks for raising this. It doesn't look like `SafeFetchN` is async signal safe because it calls into this:
>
> ```c++
> template <class T>
> ATTRIBUTE_NO_ASAN static bool _SafeFetchXX_internal(const T *adr, T* result) {
>
> ```
>
> This means we shouldn't be calling `os:: is_readable_pointer` either here, because it calls `SafeFetch32` which calls into the same function above. I had originally intended to simply perform a null check here (because that's the condition we've actually observed) and will push a change to revert to the null check.
That's not how `SafeFetchN` is normally implemented. On Linux and BSD it's more like
# Support for intptr_t SafeFetchN(intptr_t* address, intptr_t defaultval);
#
# x1 : address
# x0 : defaultval
SafeFetchN_impl:
_SafeFetchN_fault:
ldr x0, [x0]
ret
_SafeFetchN_continuation:
mov x0, x1
ret
which should be fine.
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/15178#discussion_r1286391557
More information about the hotspot-dev
mailing list