This is an automated email from the ASF dual-hosted git repository.

HappenLee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new ddbaaab1388 [fix](build) prevent math regression from global lance-c 
linkage (#67237)
ddbaaab1388 is described below

commit ddbaaab13882dab3dfa51ffb8038218df869e360
Author: linrrarity <[email protected]>
AuthorDate: Wed Sep 2 16:12:11 2026 +0800

    [fix](build) prevent math regression from global lance-c linkage (#67237)
    
    Problem Summary:
    
    PR #65304 added the following libraries to `COMMON_THIRDPARTY`:
    
    ```cmake
    list(APPEND COMMON_THIRDPARTY m lance_c)
    ```
    
    As a result, some math symbols are resolved by the system `libm` before
    the linker scans Doris' optimized compatibility implementations, causing
    a noticeable performance regression for functions such as `exp`, `log`,
    and `pow`:
    
    - exp: approximately 220%
    - ln: approximately 167%
    - log: approximately 197%
    - log2: approximately 165%
    
    Simply moving `-lm` and `lance_c` after `glibc-compatibility` exposes
    another issue. Once Lance is actually referenced, `liblance_c.a` pulls
    in Rust std objects containing late unresolved references to:
    
    - `posix_spawnp`
    - `posix_spawn_file_actions_init`
    - `posix_spawn_file_actions_destroy`
    - `posix_spawn_file_actions_adddup2`
    - `preadv`
    - `splice`
    
    The LDB toolchain resolves these references by extracting its monolithic
    `glibc-compatibility.c.o`, which also defines `getrandom`. This
    conflicts with Doris' explicitly linked `getrandom.c.o` and causes a
    duplicate-symbol error.
    
    #### Solution
    
    1. Restore the required link order
    For `GLIBC_COMPATIBILITY=ON`, use the following order:
    ```text
    glibc-compatibility-explicit
    → glibc-compatibility
    → -lm
    → lance_c
    ```
    This ordering ensures that:
    - Doris' optimized math implementations are scanned before `-lm`.
    - `-lm` is scanned before `lance_c`, preventing Rust compiler_builtins
    symbols such as cbrt from being selected.
    - `lance_c` remains available to its consumers.
    
    2. Resolve the late Lance/Rust libc references
    Add a small set of hidden symbol-version adapters for the six strong
    libc references introduced by the Rust std object.
    Each adapter has two parts. For example, the `splice` adapter is
    conceptually:
    ```c
    extern __typeof__(splice) __doris_old_splice;
    
    __asm__(
        ".symver __doris_old_splice,"
        "splice@GLIBC_2.5"
    );
    
    __attribute__((visibility("hidden")))
    ssize_t splice(...) {
        return __doris_old_splice(...);
    }
    ```
    The hidden `splice` wrapper is included in the
    `glibc-compatibility-explicit` OBJECT target, so its symbol is visible
    to the linker before `liblance_c.a` is processed.
    
    
    #### performance
    ```text
    Doris> select count(exp(db)) from double_ranges;
    +----------------+
    | count(exp(db)) |
    +----------------+
    |       50000000 |
    +----------------+
    1 row in set (0.980 sec)
    
    Doris> select count(exp(db)) from double_ranges;
    +----------------+
    | count(exp(db)) |
    +----------------+
    |       50000000 |
    +----------------+
    1 row in set (0.347 sec)
    
    
    Doris> select count(ln(db)), count(ln(in_one)) from double_ranges;
    +---------------+-------------------+
    | count(ln(db)) | count(ln(in_one)) |
    +---------------+-------------------+
    |      50000000 |          50000000 |
    +---------------+-------------------+
    1 row in set (1.486 sec)
    
    Doris> select count(ln(db)), count(ln(in_one)) from double_ranges;
    +---------------+-------------------+
    | count(ln(db)) | count(ln(in_one)) |
    +---------------+-------------------+
    |      50000000 |          50000000 |
    +---------------+-------------------+
    1 row in set (0.607 sec)
    
    
    Doris> select count(log(db, db)), count(log(in_one, db)), count(log(db, 
in_one)), count(log(db, in_ten)) from double_ranges;
    
+--------------------+------------------------+------------------------+------------------------+
    | count(log(db, db)) | count(log(in_one, db)) | count(log(db, in_one)) | 
count(log(db, in_ten)) |
    
+--------------------+------------------------+------------------------+------------------------+
    |           50000000 |               49999990 |               50000000 |    
           50000000 |
    
+--------------------+------------------------+------------------------+------------------------+
    1 row in set (5.944 sec)
    
    Doris> select count(log(db, db)), count(log(in_one, db)), count(log(db, 
in_one)), count(log(db, in_ten)) from double_ranges;
    
+--------------------+------------------------+------------------------+------------------------+
    | count(log(db, db)) | count(log(in_one, db)) | count(log(db, in_one)) | 
count(log(db, in_ten)) |
    
+--------------------+------------------------+------------------------+------------------------+
    |           50000000 |               49999990 |               50000000 |    
           50000000 |
    
+--------------------+------------------------+------------------------+------------------------+
    1 row in set (2.356 sec)
    
    
    Doris> select count(log2(db)), count(log2(in_one)) from double_ranges;
    +-----------------+---------------------+
    | count(log2(db)) | count(log2(in_one)) |
    +-----------------+---------------------+
    |        50000000 |            50000000 |
    +-----------------+---------------------+
    1 row in set (1.616 sec)
    
    Doris> select count(log2(db)), count(log2(in_one)) from double_ranges;
    +-----------------+---------------------+
    | count(log2(db)) | count(log2(in_one)) |
    +-----------------+---------------------+
    |        50000000 |            50000000 |
    +-----------------+---------------------+
    1 row in set (0.655 sec)
    ```
---
 be/CMakeLists.txt                                  |  9 ++-
 be/cmake/thirdparty.cmake                          |  8 +-
 be/src/glibc-compatibility/CMakeLists.txt          | 18 ++++-
 be/src/glibc-compatibility/lance_symbol_versions.c | 92 ++++++++++++++++++++++
 4 files changed, 122 insertions(+), 5 deletions(-)

diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt
index 0dc2196dc81..55f8166b200 100644
--- a/be/CMakeLists.txt
+++ b/be/CMakeLists.txt
@@ -901,7 +901,14 @@ endif()
 # NOTE(amos): This should come before -lc -lm to interpose symbols correctly.
 if (GLIBC_COMPATIBILITY)
     add_subdirectory(${SRC_DIR}/glibc-compatibility)
-    set(DORIS_LINK_LIBS ${DORIS_LINK_LIBS} glibc-compatibility-explicit 
glibc-compatibility)
+    # Keep lance_c here instead of COMMON_THIRDPARTY: placing its required 
libm there
+    # would resolve -lm symbol before Doris compatibility is scanned, 
preventing
+    # the linker from selecting Doris' optimized implementations.
+    set(DORIS_LINK_LIBS ${DORIS_LINK_LIBS}
+        glibc-compatibility-explicit
+        glibc-compatibility
+        -lm
+        lance_c)
 endif()
 
 if (NOT OS_MACOSX)
diff --git a/be/cmake/thirdparty.cmake b/be/cmake/thirdparty.cmake
index f3bd9867ee0..72da7afe1f3 100644
--- a/be/cmake/thirdparty.cmake
+++ b/be/cmake/thirdparty.cmake
@@ -113,9 +113,13 @@ add_thirdparty(arrow_acero LIB64)
 add_thirdparty(adbc_driver_manager LIB64)
 add_thirdparty(parquet LIB64)
 # liblance_c.a contains compiler_builtins cbrt symbols. Place libm before it
-# so the final linker resolves C math symbols from the system library first.
+# so the final linker resolves C math symbols from the system library first
 add_thirdparty(lance_c LIB64 NOTADD)
-list(APPEND COMMON_THIRDPARTY m lance_c)
+# liblance_c.a contains compiler_builtins cbrt symbols. Place libm before it
+# so the final linker resolves C math symbols from the system library first.
+if (NOT GLIBC_COMPATIBILITY)
+    list(APPEND COMMON_THIRDPARTY m lance_c)
+endif()
 add_thirdparty(brpc LIB64)
 add_thirdparty(rocksdb)
 add_thirdparty(cyrus-sasl LIBNAME "lib/libsasl2.a")
diff --git a/be/src/glibc-compatibility/CMakeLists.txt 
b/be/src/glibc-compatibility/CMakeLists.txt
index 370d7346691..116e0636893 100644
--- a/be/src/glibc-compatibility/CMakeLists.txt
+++ b/be/src/glibc-compatibility/CMakeLists.txt
@@ -49,6 +49,13 @@ if (GLIBC_COMPATIBILITY)
         list(APPEND glibc_compatibility_sources musl/getentropy.c)
     endif()
 
+    # lance_c is linked after this archive and introduces these libc references
+    # too late for another archive scan. Keep the hidden version adapters in 
the
+    # explicit object target so the final -lc does not pull in the toolchain's
+    # monolithic glibc-compatibility object and conflict with Doris' 
definitions.
+    set(lance_compatibility_source lance_symbol_versions.c)
+    list(REMOVE_ITEM glibc_compatibility_sources ${lance_compatibility_source})
+
     # Need to omit frame pointers to match the performance of glibc
     set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer")
 
@@ -65,9 +72,16 @@ if (GLIBC_COMPATIBILITY)
     # before ASAN shadow memory is initialized, causing SIGSEGV. Skip custom 
memcpy in
     # this case and fall back to glibc's memcpy.
     if (ARCH_ARM AND (CMAKE_BUILD_TYPE STREQUAL "ASAN_UT" OR CMAKE_BUILD_TYPE 
STREQUAL "ASAN"))
-        add_library(glibc-compatibility-explicit OBJECT musl/getrandom.c)
+        add_library(glibc-compatibility-explicit OBJECT
+            musl/getrandom.c
+            ${lance_compatibility_source}
+        )
     else()
-        add_library(glibc-compatibility-explicit OBJECT musl/getrandom.c 
${MEMCPY_SOURCE})
+        add_library(glibc-compatibility-explicit OBJECT
+            musl/getrandom.c
+            ${MEMCPY_SOURCE}
+            ${lance_compatibility_source}
+        )
     endif()
     target_compile_options(glibc-compatibility-explicit PRIVATE -fPIC)
     add_library(glibc-compatibility STATIC ${glibc_compatibility_sources})
diff --git a/be/src/glibc-compatibility/lance_symbol_versions.c 
b/be/src/glibc-compatibility/lance_symbol_versions.c
new file mode 100644
index 00000000000..b0594dce06b
--- /dev/null
+++ b/be/src/glibc-compatibility/lance_symbol_versions.c
@@ -0,0 +1,92 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <spawn.h>
+#include <sys/uio.h>
+
+#if defined(__x86_64__)
+#define DORIS_GLIBC_BASE_VERSION "GLIBC_2.2.5"
+#define DORIS_GLIBC_PREADV_VERSION "GLIBC_2.10"
+#define DORIS_GLIBC_SPLICE_VERSION "GLIBC_2.5"
+#elif defined(__aarch64__)
+#define DORIS_GLIBC_BASE_VERSION "GLIBC_2.17"
+#define DORIS_GLIBC_PREADV_VERSION "GLIBC_2.17"
+#define DORIS_GLIBC_SPLICE_VERSION "GLIBC_2.17"
+#else
+#error Unsupported architecture for Lance libc symbol version adapters.
+#endif
+
+#define DORIS_GLIBC_SYMVER(alias, symbol, version) \
+    __asm__(".symver " #alias "," #symbol "@" version)
+
+// Resolve late libc references from the static lance_c archive without 
exporting
+// process-wide interposers. Each wrapper forwards to an explicitly versioned
+// glibc symbol, so it cannot recurse back into the hidden wrapper.
+#define DORIS_HIDDEN __attribute__((visibility("hidden")))
+
+extern __typeof__(posix_spawnp) __doris_old_posix_spawnp;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawnp, posix_spawnp, 
DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_init) 
__doris_old_posix_spawn_file_actions_init;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_init, 
posix_spawn_file_actions_init,
+                   DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_destroy) 
__doris_old_posix_spawn_file_actions_destroy;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_destroy, 
posix_spawn_file_actions_destroy,
+                   DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(posix_spawn_file_actions_adddup2) 
__doris_old_posix_spawn_file_actions_adddup2;
+DORIS_GLIBC_SYMVER(__doris_old_posix_spawn_file_actions_adddup2,
+                   posix_spawn_file_actions_adddup2, DORIS_GLIBC_BASE_VERSION);
+
+extern __typeof__(preadv) __doris_old_preadv;
+DORIS_GLIBC_SYMVER(__doris_old_preadv, preadv, DORIS_GLIBC_PREADV_VERSION);
+
+extern __typeof__(splice) __doris_old_splice;
+DORIS_GLIBC_SYMVER(__doris_old_splice, splice, DORIS_GLIBC_SPLICE_VERSION);
+
+DORIS_HIDDEN int posix_spawnp(pid_t* pid, const char* file,
+                              const posix_spawn_file_actions_t* file_actions,
+                              const posix_spawnattr_t* attr, char* const 
argv[],
+                              char* const envp[]) {
+    return __doris_old_posix_spawnp(pid, file, file_actions, attr, argv, envp);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_init(posix_spawn_file_actions_t* 
file_actions) {
+    return __doris_old_posix_spawn_file_actions_init(file_actions);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* 
file_actions) {
+    return __doris_old_posix_spawn_file_actions_destroy(file_actions);
+}
+
+DORIS_HIDDEN int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* 
file_actions, int fd,
+                                                  int new_fd) {
+    return __doris_old_posix_spawn_file_actions_adddup2(file_actions, fd, 
new_fd);
+}
+
+DORIS_HIDDEN ssize_t preadv(int fd, const struct iovec* iov, int iov_count, 
off_t offset) {
+    return __doris_old_preadv(fd, iov, iov_count, offset);
+}
+
+DORIS_HIDDEN ssize_t splice(int fd_in, off64_t* offset_in, int fd_out, 
off64_t* offset_out,
+                            size_t length, unsigned int flags) {
+    return __doris_old_splice(fd_in, offset_in, fd_out, offset_out, length, 
flags);
+}


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

Reply via email to