diff --git a/be/CMakeLists.txt b/be/CMakeLists.txt index 26b0055f3cf536..fead02b9727544 100644 --- a/be/CMakeLists.txt +++ b/be/CMakeLists.txt @@ -772,7 +772,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 eed1823515f492..06fc25cbab0201 100644 --- a/be/cmake/thirdparty.cmake +++ b/be/cmake/thirdparty.cmake @@ -111,10 +111,12 @@ add_thirdparty(arrow_flight_sql LIB64) add_thirdparty(arrow_dataset LIB64) add_thirdparty(arrow_acero LIB64) add_thirdparty(parquet LIB64) +add_thirdparty(lance_c LIB64 NOTADD) # 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. -add_thirdparty(lance_c LIB64 NOTADD) -list(APPEND COMMON_THIRDPARTY m lance_c) +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 370d73466918ae..3f8dad4aa356d3 100644 --- a/be/src/glibc-compatibility/CMakeLists.txt +++ b/be/src/glibc-compatibility/CMakeLists.txt @@ -49,6 +49,15 @@ if (GLIBC_COMPATIBILITY) list(APPEND glibc_compatibility_sources musl/getentropy.c) endif() + set(lance_compatibility_sources + musl/execvpe.c + musl/posix_spawn_file_actions.c + musl/posix_spawnp.c + musl/preadv.c + musl/splice.c + ) + list(REMOVE_ITEM glibc_compatibility_sources ${lance_compatibility_sources}) + # Need to omit frame pointers to match the performance of glibc set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fomit-frame-pointer") @@ -65,9 +74,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_sources} + ) 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_sources} + ) endif() target_compile_options(glibc-compatibility-explicit PRIVATE -fPIC) add_library(glibc-compatibility STATIC ${glibc_compatibility_sources}) diff --git a/be/src/glibc-compatibility/musl/execvpe.c b/be/src/glibc-compatibility/musl/execvpe.c new file mode 100644 index 00000000000000..d614cea1b5d647 --- /dev/null +++ b/be/src/glibc-compatibility/musl/execvpe.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +static char* strchrnul_compat(const char* str, int ch) { + const char* found = strchr(str, ch); + return (char*)(found ? found : str + strlen(str)); +} + +int __execvpe(const char* file, char* const argv[], char* const envp[]) { + const char* path = getenv("PATH"); + int seen_eacces = 0; + + errno = ENOENT; + if (!*file) return -1; + if (strchr(file, '/')) return execve(file, argv, envp); + if (!path) path = "/usr/local/bin:/bin:/usr/bin"; + + size_t file_len = strnlen(file, NAME_MAX + 1); + if (file_len > NAME_MAX) { + errno = ENAMETOOLONG; + return -1; + } + size_t path_len = strnlen(path, PATH_MAX - 1) + 1; + + const char* cursor; + const char* end; + for (cursor = path;; cursor = end) { + char candidate[path_len + file_len + 1]; + end = strchrnul_compat(cursor, ':'); + if (end - cursor >= path_len) { + if (!*end++) break; + continue; + } + memcpy(candidate, cursor, end - cursor); + candidate[end - cursor] = '/'; + memcpy(candidate + (end - cursor) + (end > cursor), file, file_len + 1); + execve(candidate, argv, envp); + switch (errno) { + case EACCES: + seen_eacces = 1; + // Fall through. + case ENOENT: + case ENOTDIR: + break; + default: + return -1; + } + if (!*end++) break; + } + if (seen_eacces) errno = EACCES; + return -1; +} diff --git a/be/src/glibc-compatibility/musl/fdop.h b/be/src/glibc-compatibility/musl/fdop.h new file mode 100644 index 00000000000000..400f113fb22371 --- /dev/null +++ b/be/src/glibc-compatibility/musl/fdop.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#define FDOP_CLOSE 1 +#define FDOP_DUP2 2 +#define FDOP_OPEN 3 +#define FDOP_CHDIR 4 +#define FDOP_FCHDIR 5 + +struct fdop { + struct fdop* next; + struct fdop* prev; + int cmd; + int fd; + int srcfd; + int oflag; + mode_t mode; + char path[]; +}; diff --git a/be/src/glibc-compatibility/musl/posix_spawn_file_actions.c b/be/src/glibc-compatibility/musl/posix_spawn_file_actions.c new file mode 100644 index 00000000000000..53bb8820bff7ca --- /dev/null +++ b/be/src/glibc-compatibility/musl/posix_spawn_file_actions.c @@ -0,0 +1,95 @@ +#define _GNU_SOURCE +#include +#include +#include +#include + +#include "fdop.h" + +static struct fdop* first_action(const posix_spawn_file_actions_t* file_actions) { + return (struct fdop*)file_actions->__actions; +} + +static void prepend_action(posix_spawn_file_actions_t* file_actions, struct fdop* action) { + action->next = first_action(file_actions); + if (action->next) action->next->prev = action; + action->prev = NULL; + file_actions->__actions = (struct __spawn_action*)action; +} + +int posix_spawn_file_actions_init(posix_spawn_file_actions_t* file_actions) { + file_actions->__allocated = 0; + file_actions->__used = 0; + file_actions->__actions = NULL; + return 0; +} + +int posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t* restrict file_actions, + const char* restrict path) { + struct fdop* action = malloc(sizeof(*action) + strlen(path) + 1); + if (!action) return ENOMEM; + action->cmd = FDOP_CHDIR; + action->fd = -1; + strcpy(action->path, path); + prepend_action(file_actions, action); + return 0; +} + +int posix_spawn_file_actions_addclose(posix_spawn_file_actions_t* file_actions, int fd) { + if (fd < 0) return EBADF; + struct fdop* action = malloc(sizeof(*action)); + if (!action) return ENOMEM; + action->cmd = FDOP_CLOSE; + action->fd = fd; + prepend_action(file_actions, action); + return 0; +} + +int posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t* file_actions, int source_fd, + int target_fd) { + if (source_fd < 0 || target_fd < 0) return EBADF; + struct fdop* action = malloc(sizeof(*action)); + if (!action) return ENOMEM; + action->cmd = FDOP_DUP2; + action->srcfd = source_fd; + action->fd = target_fd; + prepend_action(file_actions, action); + return 0; +} + +int posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t* file_actions, int fd) { + if (fd < 0) return EBADF; + struct fdop* action = malloc(sizeof(*action)); + if (!action) return ENOMEM; + action->cmd = FDOP_FCHDIR; + action->fd = fd; + prepend_action(file_actions, action); + return 0; +} + +int posix_spawn_file_actions_addopen(posix_spawn_file_actions_t* restrict file_actions, int fd, + const char* restrict path, int flags, mode_t mode) { + if (fd < 0) return EBADF; + struct fdop* action = malloc(sizeof(*action) + strlen(path) + 1); + if (!action) return ENOMEM; + action->cmd = FDOP_OPEN; + action->fd = fd; + action->oflag = flags; + action->mode = mode; + strcpy(action->path, path); + prepend_action(file_actions, action); + return 0; +} + +int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t* file_actions) { + struct fdop* action = first_action(file_actions); + while (action) { + struct fdop* next = action->next; + free(action); + action = next; + } + file_actions->__allocated = 0; + file_actions->__used = 0; + file_actions->__actions = NULL; + return 0; +} diff --git a/be/src/glibc-compatibility/musl/posix_spawnp.c b/be/src/glibc-compatibility/musl/posix_spawnp.c new file mode 100644 index 00000000000000..c650dd8f9afb76 --- /dev/null +++ b/be/src/glibc-compatibility/musl/posix_spawnp.c @@ -0,0 +1,16 @@ +#include + +int __execvpe(const char* file, char* const argv[], char* const envp[]); + +int __posix_spawnx(pid_t* restrict result, const char* restrict path, + int (*exec)(const char*, char* const*, char* const*), + const posix_spawn_file_actions_t* file_actions, + const posix_spawnattr_t* restrict attr, char* const argv[restrict], + char* const envp[restrict]); + +int posix_spawnp(pid_t* restrict result, const char* restrict file, + const posix_spawn_file_actions_t* file_actions, + const posix_spawnattr_t* restrict attr, char* const argv[restrict], + char* const envp[restrict]) { + return __posix_spawnx(result, file, __execvpe, file_actions, attr, argv, envp); +} diff --git a/be/src/glibc-compatibility/musl/preadv.c b/be/src/glibc-compatibility/musl/preadv.c new file mode 100644 index 00000000000000..eef05969d84287 --- /dev/null +++ b/be/src/glibc-compatibility/musl/preadv.c @@ -0,0 +1,9 @@ +#define _DEFAULT_SOURCE +#include +#include + +#include "syscall.h" + +ssize_t preadv(int fd, const struct iovec* iov, int count, off_t offset) { + return syscall(SYS_preadv, fd, iov, count, (long)(offset), (long)(offset >> 32)); +} diff --git a/be/src/glibc-compatibility/musl/splice.c b/be/src/glibc-compatibility/musl/splice.c new file mode 100644 index 00000000000000..5bffd77a922aa6 --- /dev/null +++ b/be/src/glibc-compatibility/musl/splice.c @@ -0,0 +1,10 @@ +#define _GNU_SOURCE +#include +#include + +#include "syscall.h" + +ssize_t splice(int fd_in, off_t* off_in, int fd_out, off_t* off_out, size_t len, + unsigned int flags) { + return syscall(SYS_splice, fd_in, off_in, fd_out, off_out, len, flags); +}