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

   ### What problem does this PR solve?
   
   Issue Number: N/A
   
   Problem Summary:
   
   **Context.** On macOS the only entry point for the BE unit tests is
   `run-be-ut.sh`, and it defaults to `BUILD_TYPE_UT=ASAN`. Since macOS 26.4 
that
   default cannot start a single process: every binary linked against llvm.org's
   `libclang_rt.asan_osx_dynamic` deadlocks during runtime initialisation, 
before
   `main()`. The same toolchain is what `env.sh` installs on macOS (`llvm@20`), 
so a
   developer who follows the documented setup gets a build that hangs instead 
of a
   build that fails.
   
   **1. The problem, and what it cost**
   
   *The deadlock.* `sample` on the stalled process shows the whole chain:
   
   ```
   __malloc_init (libsystem_malloc)                      <- early libSystem 
init calls malloc_default_zone()
    `- wrap_malloc_default_zone (asan runtime)
        `- AsanInitFromRtl -> AsanInitInternal -> InitializeShadowMemory
            `- MemoryRangeIsAvailable -> MemoryMappingLayout::Next -> 
get_dyld_hdr()
                `- dyld_shared_cache_iterate_text_swift   <- macOS 26.4 
reimplemented this in Swift
                    `- _Block_copy -> malloc
                        `- __sanitizer_mz_malloc (asan's own malloc)
                            `- AsanInitFromRtl()              <- re-enters init
                                `- StaticSpinMutex::LockSlow  <- spins on the 
lock it already holds
   ```
   
   This is an OS-side change, not a Doris one, and it is not "ASAN does not 
work on
   macOS 26" — Apple's own clang sanitizer runtime runs fine on the same host. 
Only
   llvm.org's compiler-rt is affected. Upstream fixed it by weak-importing
   `_dyld_get_dyld_header` and using it when present instead of walking the 
shared
   cache (llvm/llvm-project#182943, main `2e7d07a`; backport #188913, 
release/22.x
   `7b6514c`). **The fix shipped only in 22.1.8.** 20.1.8 is the last 20.x 
release
   and 21.1.8 the last 21.x, so there is no version of `llvm@20` that can ever 
be
   made to work.
   
   *Why it looks like a hang and not an error.* `be/CMakeLists.txt` reaches
   `storage/index/ann` unconditionally, whose `cmake-protect` target
   `add_subdirectory()`s `contrib/openblas`. OpenBLAS runs an instrumented 
`getarch`
   probe from its **configure** step 
(`contrib/openblas/cmake/prebuild.cmake:1513`,
   `execute_process(COMMAND .../getarch 0 ...)`), and `execute_process` has no
   timeout. So every ASAN build stops at `-- Running getarch` and never moves
   again, at ~90% CPU, with no diagnostic. `run-be-ut.sh` on macOS was therefore
   unusable at its default setting, and the failure mode gives the developer
   nothing to act on.
   
   *The second obstacle, once the toolchain is bumped.* clang 22 added
   `-Wc2y-extensions` and folds it into `-Wpedantic`. `__COUNTER__` only reached
   the C standard in C23, and `be/src/runtime/runtime_profile.h:73-85` uses it 
to
   give two `SCOPED_TIMER` / `SCOPED_RAW_TIMER` expansions on the same line
   distinct names — so a clang 22 build of any TU that includes that header 
fails
   under `-Werror`. Three representative unity TUs were enough to hit it; it is 
not
   confined to one module.
   
   *Two latent defects clang 22 then surfaced.* The bump is not a pure version
   change: clang 22's stricter diagnostics stop the build on two pre-existing 
bugs,
   and both are worth fixing on their own merits.
   
   | # | Site | Diagnostic | What is actually wrong |
   |---|---|---|---|
   | 1 | `be/src/load/group_commit/wal/wal_dirs_info.cpp:98` | 
`-Wunused-result` | `LOG(INFO) << "… err: {}", e.what();` — the `,` is the 
comma operator, not an argument separator, so the statement is `(LOG(INFO) << 
"…{}") , (e.what())`. The `{}` is never substituted and `e.what()` is evaluated 
and discarded: **the error message has never been logged**, only the literal 
`{}`. A repo-wide scan for the same shape finds exactly this one site 
(`cloud/src/common/logging.h` matches only inside macro definitions and is not 
a bug). |
   | 2 | `common/cpp/sync_point.cpp:208,210` | `-Wthread-safety-analysis` | The 
function holds `std::unique_lock lock(mutex_)` and then releases it with a raw 
`mutex_.unlock()` / `mutex_.lock()` pair around the callback, bypassing the 
lock's ownership tracking. If the callback throws, the re-lock is skipped while 
`~unique_lock` still believes it owns the mutex, so the destructor unlocks a 
mutex that is not held (UB) and `num_callbacks_running_` is never decremented. 
Using `lock.unlock()` / `lock.lock()` keeps the callback running unlocked — the 
intent — while leaving the ownership state correct on every path. |
   
   **2. What this PR does, and why it helps**
   
   - `env.sh`: the macOS `CELLARS` list moves from `llvm@20` to `llvm@22`, with 
a
     comment recording that 22.1.8 is the floor and why. `env.sh` is what puts 
the
     toolchain on `PATH` and what derives `DORIS_CLANG_HOME`, so this is the 
single
     line that decides which clang a macOS developer builds with.
   - `be/CMakeLists.txt`: add `-Wno-c2y-extensions` to the clang suppression 
block
     that already sits **after** `-Wpedantic` (`-Wno-pass-failed` and friends). 
The
     position matters: a `-Wno-` placed before `-Wpedantic` is silently 
re-enabled
     by it, which is why passing the flag through `EXTRA_CXX_FLAGS` does not 
work —
     that variable lands near the front of the command line. clang 20 accepts 
the
     unknown `-Wno-` without a diagnostic, so no version guard is needed and
     Linux/older clang are unaffected.
   - `.github/workflows/be-ut-mac.yml`: install `llvm@22` so the workflow's
     toolchain matches `env.sh`.
   - `be/src/load/group_commit/wal/wal_dirs_info.cpp` and
     `common/cpp/sync_point.cpp`: the two fixes from the table above — one line 
each,
     the smallest change that removes the defect rather than a suppression. No
     `-Wno-unused-result` / `-Wno-thread-safety-analysis` is added: those
     diagnostics are pointing at real bugs and should keep firing.
   - `.github/workflows/build-thirdparty.yml` (both macOS jobs): same bump. This
     one is not cosmetic — `thirdparty/build-thirdparty.sh:55` sources 
`env.sh`, so
     once `env.sh` names `llvm@22` a runner that still installs `llvm@20` would 
put
     a non-existent directory on `PATH` and fall through to `/usr/bin/clang`, 
i.e.
     Apple clang. Installing `llvm@22` keeps the job on the intended compiler.
   
   **Consequence worth naming:** because `build-thirdparty.sh` reads `env.sh`, 
the
   macOS thirdparty prebuilt (`doris-thirdparty-prebuilt-darwin-arm64.tar.xz`) 
is
   built with clang 22 from the next run of that workflow onward. That is the
   intended outcome — the prebuilt and the BE that links it should come from the
   same toolchain — but it is a published artifact change, not a private one.
   
   **3. The classes, and how they call each other**
   
   ```
   env.sh  CELLARS := llvm@22
     |- generates custom_env_mac.sh, which prepends $HOMEBREW/opt/llvm@22/bin 
to PATH
     |- DORIS_CLANG_HOME := dirname($(command -v clang))/..   -> CC / CXX / 
ASAN_SYMBOLIZER_PATH
     '- is sourced by:
          |- run-be-ut.sh        -> cmake -DCMAKE_BUILD_TYPE=ASAN_UT
          |- thirdparty/build-thirdparty.sh:55  -> the macOS prebuilt job
          '- .github/workflows/be-ut-mac.yml    -> brew install llvm@22
   
   be/CMakeLists.txt  if (COMPILER_CLANG)
     |- add_compile_options(-Wpedantic ...)        <- enables the c2y group
     '- add_compile_options(-Wno-pass-failed
                            -Wno-c2y-extensions)   <- added here; must stay 
after the line above
            |
   be/src/runtime/runtime_profile.h:73-85
     '- MACRO_CONCAT(SCOPED_TIMER, __COUNTER__)    <- the only __COUNTER__ use 
in be/src, be/test
            |
   be/src/storage/index/ann/cmake-protect/CMakeLists.txt:48
     '- add_subdirectory(contrib/openblas)
          '- cmake/prebuild.cmake:1513  execute_process(getarch)   <- where the 
hang surfaced
   ```
   
   ### Release note
   
   None
   
   ### Check List (For Author)
   
   - Test: Manual test on macOS 26.5.1 (arm64, dyld-1378).
       - `clang -fsanitize=address` hello world exits 0 with llvm@22 and still
         deadlocks with llvm@20 on the same host.
       - `sh run-be-ut.sh` with no environment overrides now selects 
`Clang-22.1.8`
         and clears the `-- Running getarch` point that previously hung forever:
         zero FAILED targets, `doris_be_test` links.
       - `sh run-be-ut.sh --run --filter=FormatRoundTest.*` starts the ASAN 
binary
         and passes 8 tests.
       - `build-support/check-build-hygiene.sh` passes.
       - Regression test / unit test: N/A (toolchain and flag change).
   - Behavior changed: Yes — macOS builds now use LLVM 22 instead of LLVM 20, 
and
     because `thirdparty/build-thirdparty.sh` sources `env.sh`, the macOS 
thirdparty
     prebuilt is built with clang 22 from the next run of that workflow onward.
   - Does this need documentation: No
   


-- 
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