morningman opened a new pull request, #68507:
URL: https://github.com/apache/doris/pull/68507

   Cherry-picked from #67877 (master commit `e797e99fcbe`) via its branch-4.1 
pick #68339 (commit `5e1ee245e23`) to `branch-4.1.4`.
   
   **Conflict resolution.** This branch is a 2026-09-04 cut of branch-4.1, so 
two of the seven files differed:
   
   - `thirdparty/CHANGELOG.md`: branch-4.1's `## 20260901` thrift 0.16.0 → 
0.24.0 entry is not on this branch (it still pins thrift 0.16.0), and neither 
is master's `## 20260909` snappy 1.2.1 entry. Only the `## 20260911` libunwind 
entry is inserted, above `## 20260429`.
   - `thirdparty/patches/libunwind-1.8.3-doris-phdr-cache.patch`: this branch 
still carries the pre-#67564 1.6.2 patch, and a patch file has no mergeable 
content, so the new file is taken wholesale from the branch-4.1 pick. It is 
byte-identical to the branch-4.1 and master versions.
   
   The other five files applied without conflict. `thirdparty/vars.sh`, 
`thirdparty/build-thirdparty.sh`, `thirdparty/download-thirdparty.sh` and 
`.github/workflows/build-thirdparty.yml` still differ from branch-4.1, but only 
by thirdparty drift this branch has not taken (thrift 0.24.0, aws-sdk-cpp 
1.11.221, simdutf, google-cloud-cpp, lance-c 0.1.9, jemalloc); no hunk of this 
change is affected. `thirdparty/test/libunwind-page-size-test.sh` and the 
rebased patch are byte-identical to master's.
   
   ### What problem does this PR solve?
   
   Related PRs: #64093, #67877, #68339
   
   Problem Summary:
   
   **Every aarch64 BE built from branch-4.1.4 since 4.1.4-rc01 crashes before 
`main()` on a 64 KiB-page kernel** (Kunpeng 920 + Kylin V10 / openEuler / 
CentOS aarch64, the common ARM server stack). The core from the 4.1.4 arm64 
deployment shows:
   
   ```
   access_mem (addr=0)            src/aarch64/Ginit.c
   is_plt_entry                   src/aarch64/Gstep.c
   _ULaarch64_step
   _ULaarch64_tdep_trace
   unw_backtrace
   <bthread/mutex.cpp static initializer: backtrace(dummy_buf, 4)>   ← bRPC 
"Warm up backtrace before main()"
   __libc_csu_init
   ```
   
   SIGSEGV with `si_addr=0`, AUXV `PAGESZ=65536`, and inside the libunwind 
cursor `ip=0`, `validate=0`, `mem_validate_func=msync_validate`, 
`last_good_addr[]={0,0,0,0}`.
   
   How it happens:
   
   1. #64093 links GNU libunwind statically into the aarch64 BE (it forces 
`USE_UNWIND=ON` on Linux, references `unw_*` from `phdr_cache.cpp` without the 
`__x86_64__` guard, and builds jemalloc with `--enable-prof-libunwind`). 
libunwind's weak `backtrace` alias then replaces glibc's `backtrace()` for 
every caller in the process: bRPC's pre-main warm-up, 
`StackTrace::tryCapture()` on aarch64, jemalloc heap profiling. The 4.1.3 arm64 
package was immune only because it was built with `USE_UNWIND=OFF` (which the 
ARM compilation doc still prescribes and #64093 removed): it has 
`backtrace@GLIBC_2.17` and zero `_ULaarch64_*` symbols.
   2. libunwind 1.6.2 hard-codes `PAGE_SIZE 4096` in `src/aarch64/Ginit.c`. On 
a 64 KiB-page kernel `mincore()`/`msync()` reject its 4 KiB-aligned probes with 
`EINVAL`, so `validate_mem()` fails for 15/16 of all addresses (the core's 
`msync_validate` + empty `last_good_addr` are exactly this).
   3. `unw_step()` therefore gets `unw_is_signal_frame() < 0` for a valid IP, 
takes the "IP points to non-mapped memory, use LR" recovery path and loads 
`uc.regs[30]` — a slot `_Uaarch64_getcontext_trace` never writes (it saves only 
FP/SP/PC). On the reporting host that stack garbage is 0.
   4. `dwarf_step(ip=0)` finds nothing, and the fallback calls `is_plt_entry()` 
with `c->validate` restored to 0, so `access_mem` executes `ldr x8, [x1]` with 
`x1=0`.
   
   The PHDR cache being empty before `main()` is not what breaks this (step 3 
has already poisoned `ip` before any FDE lookup, and the same crash reproduces 
without the Doris hook); changing the cache initialisation order would not fix 
it, and every later `backtrace()` on such a host rolls the same dice.
   
   ### Changes
   
   Fix: **upgrade libunwind 1.6.2 → 1.8.3**, which was never bumped since it 
was introduced in 2023 (#21938):
   
   - 1.7.0+: `unw_page_size = sysconf(_SC_PAGESIZE)` instead of the hard-coded 
4096.
   - 1.8.0+: `src/mi/Gaddress_validator.c` validates through the pipe-write 
probe only, so `mincore`/`msync` alignment no longer matters at all; 
`unw_step()` sets `c->validate = 1` before the DWARF-failure fallback, so a 
garbage IP is rejected instead of dereferenced.
   
   Specifically:
   
   - `thirdparty/vars.sh`: libunwind 1.6.2 → 1.8.3 (md5 
`13bc7b41462ac6ea157d350eaf6c1503`).
   - `thirdparty/patches/libunwind-1.8.3-doris-phdr-cache.patch`: the #64093 
hook rebased onto 1.8.3's `as->iterate_phdr_function` call site; semantics 
unchanged (`doris_unwind_iterate_phdr` still takes precedence whenever it is 
linked in). 1.8 also exposes `unw_set_iterate_phdr_function()`, which could 
replace the source patch in a follow-up.
   - `thirdparty/build-thirdparty.sh`: `--disable-tests 
--disable-documentation`; only `libunwind.a` is consumed.
   - `thirdparty/test/libunwind-page-size-test.sh` (+ run at the end of the 
Linux thirdparty CI build): reproduces the failure on any Linux host. An 
`LD_PRELOAD` shim gives libunwind a 64 KiB-page kernel's behaviour (`EINVAL` 
for unaligned `mincore`/`msync`, `sysconf(_SC_PAGESIZE)=65536`), and a program 
shaped like the bRPC warm-up calls `backtrace()` from a constructor with a 
zeroed stack. Against 1.6.2 it segfaults with the customer's exact stack and 
cursor state; against 1.8.3 it passes.
   
   No BE source change: every `unw_*` API the BE, jemalloc and the x86_64 
stack-trace code use is unchanged in 1.8.3, `cxx_exceptions` stays off on 
x86_64/aarch64, and the weak `backtrace` alias is still provided.
   
   ### Release note
   
   Fix the aarch64 BE crashing before `main()` (SIGSEGV in 
`access_mem`/`is_plt_entry` under `unw_backtrace`) on 64 KiB-page kernels such 
as Kunpeng 920 with Kylin, openEuler or CentOS, by upgrading the bundled 
libunwind from 1.6.2 to 1.8.3.
   
   ### Check List (For Author)
   
   - Test
       - [x] Manual test (add detailed scripts or steps below)
           - The change is carried over verbatim from #67877 / #68339, where 
the reproduction, the symbolised customer core and the new 
`thirdparty/test/libunwind-page-size-test.sh` (1.6.2 FAIL, 1.8.3 PASS on 
aarch64 and x86_64) were verified; `Build Third Party Libraries (Linux)`, 
`(macOS)`, `(macOS-arm64)` and `Thirdparty Script Test` passed there.
           - For this pick: every hunk is identical to the branch-4.1 commit 
(only hunk offsets differ); `libunwind-1.8.3-doris-phdr-cache.patch` and 
`thirdparty/test/libunwind-page-size-test.sh` are byte-identical to master's; 
`bash -n` passes on the four touched scripts; no stale `libunwind-1.6.2` 
reference remains in the tree.
           - Not done here: a Linux `doris_be` rebuilt with 1.8.3 on a real 64 
KiB-page host. That is the one check that still needs an aarch64 machine.
   
   - Behavior changed:
       - [x] Yes. Bundled libunwind 1.6.2 → 1.8.3; libunwind's own test 
programs and man pages are no longer built. Unwinding semantics for the BE 
otherwise unchanged.
   
   - Does this need documentation?
       - [x] No.
   
   ### Check List (For Reviewer who merge this PR)
   
   - [ ] Confirm the release note
   - [ ] Confirm test cases
   - [ ] Confirm document
   - [ ] Add branch pick label
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to