@@ -558,6 +558,26 @@ class UnwindCursor : public AbstractUnwindCursor {
558
558
_info.handler = 0 ;
559
559
return UNW_STEP_SUCCESS;
560
560
}
561
+ bool isReadableAddr (const void *addr) const {
562
+ // This code is heavily based on Abseil's 'address_is_readable.cc',
563
+ // which is Copyright Abseil Authors (2017), and provided under
564
+ // the Apache License 2.0.
565
+
566
+ // We have to check that addr is a nullptr because sigprocmask allows that
567
+ // as an argument without failure.
568
+ if (!addr)
569
+ return false ;
570
+ // Align to 8-bytes.
571
+ const auto uintptr_addr = reinterpret_cast <uintptr_t >(addr) & ~uintptr_t {7 };
572
+ const auto sigsetaddr = reinterpret_cast <sigset_t *>(uintptr_addr);
573
+ [[maybe_unused]] int Result = sigprocmask (/* how=*/ -1 , sigsetaddr, nullptr );
574
+ // Because our "how" is invalid, this syscall should always fail, and our
575
+ // errno should always be EINVAL or an EFAULT. EFAULT is not guaranteed
576
+ // by the POSIX standard, so this is (for now) Linux specific.
577
+ assert (Result == -1 );
578
+ assert (errno == EFAULT || errno == EINVAL);
579
+ return errno != EFAULT;
580
+ }
561
581
562
582
A &_addressSpace;
563
583
unw_proc_info_t _info;
@@ -2701,19 +2721,13 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_arm64 &) {
2701
2721
// [1] https://github.com/torvalds/linux/blob/master/arch/arm64/kernel/vdso/sigreturn.S
2702
2722
const pint_t pc = static_cast <pint_t >(this ->getReg (UNW_REG_IP));
2703
2723
// The PC might contain an invalid address if the unwind info is bad, so
2704
- // directly accessing it could cause a segfault. Use pipe/write/read to read
2705
- // the memory safely instead.
2706
- int pipefd[2 ];
2707
- if (pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK) == -1 )
2708
- return false ;
2709
- uint32_t instructions[2 ];
2710
- const auto bufferSize = sizeof instructions;
2711
- if (write (pipefd[1 ], reinterpret_cast <void *>(pc), bufferSize) != bufferSize)
2724
+ // directly accessing it could cause a SIGSEGV.
2725
+ if (!isReadableAddr (static_cast <void *>(pc)) ||
2726
+ !isReadableAddr (static_cast <void *>(pc + 4 )))
2712
2727
return false ;
2713
- const auto bytesRead = read (pipefd[ 0 ], instructions, bufferSize );
2728
+ auto *instructions = static_cast < uint32_t *>(pc );
2714
2729
// Look for instructions: mov x8, #0x8b; svc #0x0
2715
- if (bytesRead != bufferSize || instructions[0 ] != 0xd2801168 ||
2716
- instructions[1 ] != 0xd4000001 )
2730
+ if (instructions[0 ] != 0xd2801168 || instructions[1 ] != 0xd4000001 )
2717
2731
return false ;
2718
2732
2719
2733
_info = {};
@@ -2762,21 +2776,18 @@ int UnwindCursor<A, R>::stepThroughSigReturn(Registers_arm64 &) {
2762
2776
template <typename A, typename R>
2763
2777
bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_riscv &) {
2764
2778
const pint_t pc = static_cast <pint_t >(getReg (UNW_REG_IP));
2765
- int pipefd[2 ];
2766
- if (pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK) == -1 )
2767
- return false ;
2768
- uint32_t instructions[2 ];
2769
- const auto bufferSize = sizeof instructions;
2770
- if (write (pipefd[1 ], reinterpret_cast <void *>(pc), bufferSize) != bufferSize)
2779
+ // The PC might contain an invalid address if the unwind info is bad, so
2780
+ // directly accessing it could cause a SIGSEGV.
2781
+ if (!isReadableAddr (static_cast <void *>(pc)) ||
2782
+ !isReadableAddr (static_cast <void *>(pc + 4 )))
2771
2783
return false ;
2772
- const auto bytesRead = read (pipefd[ 0 ], instructions, bufferSize );
2784
+ const auto *instructions = static_cast < uint32_t *>(pc );
2773
2785
// Look for the two instructions used in the sigreturn trampoline
2774
2786
// __vdso_rt_sigreturn:
2775
2787
//
2776
2788
// 0x08b00893 li a7,0x8b
2777
2789
// 0x00000073 ecall
2778
- if (bytesRead != bufferSize || instructions[0 ] != 0x08b00893 ||
2779
- instructions[1 ] != 0x00000073 )
2790
+ if (instructions[0 ] != 0x08b00893 || instructions[1 ] != 0x00000073 )
2780
2791
return false ;
2781
2792
2782
2793
_info = {};
@@ -2825,17 +2836,12 @@ bool UnwindCursor<A, R>::setInfoForSigReturn(Registers_s390x &) {
2825
2836
// onto the stack.
2826
2837
const pint_t pc = static_cast <pint_t >(this ->getReg (UNW_REG_IP));
2827
2838
// The PC might contain an invalid address if the unwind info is bad, so
2828
- // directly accessing it could cause a segfault. Use pipe/write/read to
2829
- // read the memory safely instead.
2830
- int pipefd[2 ];
2831
- if (pipe2 (pipefd, O_CLOEXEC | O_NONBLOCK) == -1 )
2832
- return false ;
2833
- uint16_t inst;
2834
- const auto bufferSize = sizeof inst;
2835
- if (write (pipefd[1 ], reinterpret_cast <void *>(pc), bufferSize) != bufferSize)
2839
+ // directly accessing it could cause a SIGSEGV.
2840
+ if (!isReadableAddr (static_cast <void *>(pc)) ||
2841
+ !isReadableAddr (static_cast <void *>(pc + 2 )))
2836
2842
return false ;
2837
- const auto bytesRead = read (pipefd[ 0 ], &inst, bufferSize );
2838
- if (bytesRead == bufferSize && ( inst == 0x0a77 || inst == 0x0aad ) ) {
2843
+ const auto inst = * reinterpret_cast < uint16_t *>(pc );
2844
+ if (inst == 0x0a77 || inst == 0x0aad ) {
2839
2845
_info = {};
2840
2846
_info.start_ip = pc;
2841
2847
_info.end_ip = pc + 2 ;
0 commit comments