From eaa088ba55343d6841c4cb1b41ea99ee280f28e4 Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 30 Oct 2024 19:55:42 -0700 Subject: [PATCH] Fix missing symbol errors and add a test (#14907) Co-authored-by: Jarred Sumner --- .vscode/launch.json | 58 ++++++++++++++++ cmake/targets/BuildBun.cmake | 41 ++++++++---- .../bun-usockets/src/eventing/epoll_kqueue.c | 20 ++++-- .../bindings/workaround-missing-symbols.cpp | 66 ++++++++++++------- src/linux_c.zig | 14 ++++ test/js/bun/symbols.test.ts | 65 ++++++++++++++++++ 6 files changed, 219 insertions(+), 45 deletions(-) create mode 100644 test/js/bun/symbols.test.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 3e453e8052..191c0a815e 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,6 +22,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -37,6 +39,8 @@ "BUN_DEBUG_jest": "1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -58,6 +62,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "0", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -73,6 +79,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -88,6 +96,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -103,6 +113,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -119,6 +131,8 @@ "BUN_INSPECT": "ws://localhost:0/?wait=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -140,6 +154,8 @@ "BUN_INSPECT": "ws://localhost:0/?break=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -160,6 +176,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -178,6 +196,8 @@ "GOMAXPROCS": "1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -192,6 +212,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -206,6 +228,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -220,6 +244,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -235,6 +261,8 @@ "BUN_INSPECT": "ws://localhost:0/?wait=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -255,6 +283,8 @@ "BUN_INSPECT": "ws://localhost:0/?break=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -276,6 +306,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -291,6 +323,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "0", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -306,6 +340,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -321,6 +357,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -336,6 +374,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -352,6 +392,8 @@ "BUN_INSPECT": "ws://localhost:0/?wait=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -373,6 +415,8 @@ "BUN_INSPECT": "ws://localhost:0/?break=1", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -393,6 +437,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, // bun test [*] { @@ -408,6 +454,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -422,6 +470,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "0", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -437,6 +487,8 @@ "BUN_INSPECT": "ws://localhost:0/", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], "serverReadyAction": { "pattern": "https://debug.bun.sh/#localhost:([0-9]+)/", "uriFormat": "https://debug.bun.sh/#ws://localhost:%s/", @@ -456,6 +508,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, { "type": "lldb", @@ -470,6 +524,8 @@ "BUN_GARBAGE_COLLECTOR_LEVEL": "2", }, "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, // Windows: bun test [file] { @@ -1182,6 +1238,8 @@ }, ], "console": "internalConsole", + // Don't pause when the GC runs while the debugger is open. + "postRunCommands": ["process handle -p true -s false -n false SIGUSR1"], }, ], "inputs": [ diff --git a/cmake/targets/BuildBun.cmake b/cmake/targets/BuildBun.cmake index 38c8003c5d..c247d1e16c 100644 --- a/cmake/targets/BuildBun.cmake +++ b/cmake/targets/BuildBun.cmake @@ -482,13 +482,16 @@ endif() set(BUN_ZIG_OUTPUT ${BUILD_PATH}/bun-zig.o) + if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM|arm64|ARM64|aarch64|AARCH64") + set(IS_ARM64 ON) if(APPLE) set(ZIG_CPU "apple_m1") else() set(ZIG_CPU "native") endif() elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|X86_64|x64|X64|amd64|AMD64") + set(IS_X86_64 ON) if(ENABLE_BASELINE) set(ZIG_CPU "nehalem") else() @@ -846,6 +849,29 @@ else() set(LLD_NAME lld-${LLVM_VERSION_MAJOR}) endif() + if (IS_ARM64) + set(ARCH_WRAP_FLAGS + -Wl,--wrap=fcntl64 + -Wl,--wrap=statx + ) + elseif(IS_X86_64) + set(ARCH_WRAP_FLAGS + -Wl,--wrap=fcntl + -Wl,--wrap=fcntl64 + -Wl,--wrap=fstat + -Wl,--wrap=fstat64 + -Wl,--wrap=fstatat + -Wl,--wrap=fstatat64 + -Wl,--wrap=lstat + -Wl,--wrap=lstat64 + -Wl,--wrap=mknod + -Wl,--wrap=mknodat + -Wl,--wrap=stat + -Wl,--wrap=stat64 + -Wl,--wrap=statx + ) + endif() + target_link_options(${bun} PUBLIC -fuse-ld=${LLD_NAME} -fno-pic @@ -856,32 +882,21 @@ else() -Wl,--as-needed -Wl,--gc-sections -Wl,-z,stack-size=12800000 + ${ARCH_WRAP_FLAGS} -Wl,--wrap=cosf -Wl,--wrap=exp -Wl,--wrap=expf - -Wl,--wrap=fcntl - -Wl,--wrap=fcntl64 -Wl,--wrap=fmod -Wl,--wrap=fmodf - -Wl,--wrap=fstat - -Wl,--wrap=fstat64 - -Wl,--wrap=fstatat - -Wl,--wrap=fstatat64 -Wl,--wrap=log -Wl,--wrap=log10f -Wl,--wrap=log2 -Wl,--wrap=log2f -Wl,--wrap=logf - -Wl,--wrap=lstat - -Wl,--wrap=lstat64 - -Wl,--wrap=mknod - -Wl,--wrap=mknodat -Wl,--wrap=pow + -Wl,--wrap=powf -Wl,--wrap=sincosf -Wl,--wrap=sinf - -Wl,--wrap=stat - -Wl,--wrap=stat64 - -Wl,--wrap=statx -Wl,--wrap=tanf -Wl,--compress-debug-sections=zlib -Wl,-z,lazy diff --git a/packages/bun-usockets/src/eventing/epoll_kqueue.c b/packages/bun-usockets/src/eventing/epoll_kqueue.c index 9091cef8b7..8e4e90c252 100644 --- a/packages/bun-usockets/src/eventing/epoll_kqueue.c +++ b/packages/bun-usockets/src/eventing/epoll_kqueue.c @@ -113,6 +113,9 @@ struct us_loop_t *us_timer_loop(struct us_timer_t *t) { #if defined(LIBUS_USE_EPOLL) #include +#include +#include + static int has_epoll_pwait2 = -1; #ifndef SYS_epoll_pwait2 @@ -122,18 +125,21 @@ static int has_epoll_pwait2 = -1; #define SYS_epoll_pwait2 441 #endif -static ssize_t sys_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout, const sigset_t *sigmask, size_t sigsetsize) { - return syscall(SYS_epoll_pwait2, epfd, events, maxevents, timeout, sigmask, sigsetsize); -} +extern ssize_t sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, + const struct timespec* timeout, const sigset_t* sigmask); + static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, const struct timespec *timeout) { int ret; + sigset_t mask; + sigemptyset(&mask); + if (has_epoll_pwait2 != 0) { do { - ret = sys_epoll_pwait2(epfd, events, maxevents, timeout, NULL, 0); - } while (IS_EINTR(ret)); + ret = sys_epoll_pwait2(epfd, events, maxevents, timeout, &mask); + } while (ret == -EINTR); - if (LIKELY(ret != -1 || errno != ENOSYS)) { + if (LIKELY(ret != -ENOSYS && ret != -EPERM && ret != -EOPNOTSUPP)) { return ret; } @@ -146,7 +152,7 @@ static int bun_epoll_pwait2(int epfd, struct epoll_event *events, int maxevents, } do { - ret = epoll_wait(epfd, events, maxevents, timeoutMs); + ret = epoll_pwait(epfd, events, maxevents, timeoutMs, &mask); } while (IS_EINTR(ret)); return ret; diff --git a/src/bun.js/bindings/workaround-missing-symbols.cpp b/src/bun.js/bindings/workaround-missing-symbols.cpp index 31c82dfd69..f53174c4f8 100644 --- a/src/bun.js/bindings/workaround-missing-symbols.cpp +++ b/src/bun.js/bindings/workaround-missing-symbols.cpp @@ -87,6 +87,7 @@ __asm__(".symver log2,log2@GLIBC_2.2.5"); __asm__(".symver log2f,log2f@GLIBC_2.2.5"); __asm__(".symver logf,logf@GLIBC_2.2.5"); __asm__(".symver pow,pow@GLIBC_2.2.5"); +__asm__(".symver powf,powf@GLIBC_2.2.5"); __asm__(".symver sincosf,sincosf@GLIBC_2.2.5"); __asm__(".symver sinf,sinf@GLIBC_2.2.5"); __asm__(".symver tanf,tanf@GLIBC_2.2.5"); @@ -94,7 +95,6 @@ __asm__(".symver tanf,tanf@GLIBC_2.2.5"); __asm__(".symver cosf,cosf@GLIBC_2.17"); __asm__(".symver exp,exp@GLIBC_2.17"); __asm__(".symver expf,expf@GLIBC_2.17"); -__asm__(".symver fcntl,fcntl@GLIBC_2.17"); __asm__(".symver fmod,fmod@GLIBC_2.17"); __asm__(".symver fmodf,fmodf@GLIBC_2.17"); __asm__(".symver log,log@GLIBC_2.17"); @@ -103,6 +103,7 @@ __asm__(".symver log2,log2@GLIBC_2.17"); __asm__(".symver log2f,log2f@GLIBC_2.17"); __asm__(".symver logf,logf@GLIBC_2.17"); __asm__(".symver pow,pow@GLIBC_2.17"); +__asm__(".symver powf,powf@GLIBC_2.17"); __asm__(".symver sincosf,sincosf@GLIBC_2.17"); __asm__(".symver sinf,sinf@GLIBC_2.17"); __asm__(".symver tanf,tanf@GLIBC_2.17"); @@ -134,6 +135,9 @@ void BUN_WRAP_GLIBC_SYMBOL(sincosf)(float, float*, float*); } extern "C" { + +#if defined(__x86_64__) || defined(__aarch64__) + int __wrap_fcntl(int fd, int cmd, ...) { va_list args; @@ -150,6 +154,10 @@ static void init_real_fcntl64() { if (!real_fcntl64) { real_fcntl64 = (fcntl64_func)dlsym(RTLD_NEXT, "fcntl64"); + + if (!real_fcntl64) { + real_fcntl64 = (fcntl64_func)dlsym(RTLD_NEXT, "fcntl"); + } } } @@ -233,32 +241,10 @@ extern "C" int __wrap_fcntl64(int fd, int cmd, ...) return -1; } } -double __wrap_exp(double x) { return exp(x); } -double __wrap_fmod(double x, double y) { return fmod(x, y); } -double __wrap_log(double x) { return log(x); } -double __wrap_log2(double x) { return log2(x); } -double __wrap_pow(double x, double y) { return pow(x, y); } -float __wrap_cosf(float x) { return cosf(x); } -float __wrap_expf(float x) { return expf(x); } -float __wrap_fmodf(float x, float y) { return fmodf(x, y); } -float __wrap_log10f(float x) { return log10f(x); } -float __wrap_log2f(float x) { return log2f(x); } -float __wrap_logf(float x) { return logf(x); } -float __wrap_sinf(float x) { return sinf(x); } -float __wrap_tanf(float x) { return tanf(x); } -void __wrap_sincosf(float x, float* sin_x, float* cos_x) { sincosf(x, sin_x, cos_x); } -} -// ban statx, for now -extern "C" int __wrap_statx(int fd, const char* path, int flags, - unsigned int mask, struct statx* buf) -{ - errno = ENOSYS; -#ifdef BUN_DEBUG - abort(); #endif - return -1; -} + +#if defined(__x86_64__) #ifndef _MKNOD_VER #define _MKNOD_VER 1 @@ -326,6 +312,36 @@ extern "C" int __wrap_mknodat(int dirfd, const char* path, __mode_t mode, __dev_ #endif +double __wrap_exp(double x) { return exp(x); } +double __wrap_fmod(double x, double y) { return fmod(x, y); } +double __wrap_log(double x) { return log(x); } +double __wrap_log2(double x) { return log2(x); } +double __wrap_pow(double x, double y) { return pow(x, y); } +float __wrap_powf(float x, float y) { return powf(x, y); } +float __wrap_cosf(float x) { return cosf(x); } +float __wrap_expf(float x) { return expf(x); } +float __wrap_fmodf(float x, float y) { return fmodf(x, y); } +float __wrap_log10f(float x) { return log10f(x); } +float __wrap_log2f(float x) { return log2f(x); } +float __wrap_logf(float x) { return logf(x); } +float __wrap_sinf(float x) { return sinf(x); } +float __wrap_tanf(float x) { return tanf(x); } +void __wrap_sincosf(float x, float* sin_x, float* cos_x) { sincosf(x, sin_x, cos_x); } +} + +// ban statx, for now +extern "C" int __wrap_statx(int fd, const char* path, int flags, + unsigned int mask, struct statx* buf) +{ + errno = ENOSYS; +#ifdef BUN_DEBUG + abort(); +#endif + return -1; +} + +#endif + // macOS #if defined(__APPLE__) diff --git a/src/linux_c.zig b/src/linux_c.zig index 64b46ea178..32292c6426 100644 --- a/src/linux_c.zig +++ b/src/linux_c.zig @@ -771,3 +771,17 @@ pub extern "C" fn memrchr(ptr: [*]const u8, val: c_int, len: usize) ?[*]const u8 pub const netdb = @cImport({ @cInclude("netdb.h"); }); + +export fn sys_epoll_pwait2(epfd: i32, events: ?[*]std.os.linux.epoll_event, maxevents: i32, timeout: ?*const std.os.linux.timespec, sigmask: ?*const std.os.linux.sigset_t) isize { + return @bitCast( + std.os.linux.syscall6( + .epoll_pwait2, + @bitCast(@as(isize, @intCast(epfd))), + @intFromPtr(events), + @bitCast(@as(isize, @intCast(maxevents))), + @intFromPtr(timeout), + @intFromPtr(sigmask), + 8, + ), + ); +} diff --git a/test/js/bun/symbols.test.ts b/test/js/bun/symbols.test.ts new file mode 100644 index 0000000000..67127e3555 --- /dev/null +++ b/test/js/bun/symbols.test.ts @@ -0,0 +1,65 @@ +import { test, expect } from "bun:test"; +import { $ } from "bun"; +import { bunExe } from "harness"; +import { semver } from "bun"; + +const BUN_EXE = bunExe(); + +if (process.platform === "linux") { + test("objdump -T does not include symbols from glibc > 2.27", async () => { + const objdump = Bun.which("objdump") || Bun.which("llvm-objdump"); + if (!objdump) { + throw new Error("objdump executable not found. Please install it."); + } + + const output = await $`${objdump} -T ${BUN_EXE} | grep GLIBC_`.text(); + const lines = output.split("\n"); + const errors = []; + for (const line of lines) { + const match = line.match(/\(GLIBC_2(.*)\)\s/); + if (match?.[1]) { + let version = "2." + match[1]; + if (version.startsWith("2..")) { + version = "2." + version.slice(3); + } + if (semver.order(version, "2.27.0") >= 0) { + errors.push({ + symbol: line.slice(line.lastIndexOf(")") + 1).trim(), + "glibc version": version, + }); + } + } + } + if (errors.length) { + throw new Error(`Found glibc symbols >= 2.27. This breaks Amazon Linux 2 and Vercel. + +${Bun.inspect.table(errors, { colors: true })} +To fix this, add it to -Wl,-wrap=symbol in the linker flags and update workaround-missing-symbols.cpp.`); + } + }); + + test("libatomic.so is not linked", async () => { + const ldd = Bun.which("ldd"); + + if (!ldd) { + throw new Error("ldd executable not found. Please install it."); + } + + const output = await $`${ldd} ${BUN_EXE}`.text(); + const lines = output.split("\n"); + const errors = []; + for (const line of lines) { + // libatomic + if (line.includes("libatomic")) { + errors.push(line); + } + } + if (errors.length) { + throw new Error(`libatomic.so is linked. This breaks Amazon Linux 2 and Vercel. + +${errors.join("\n")} + +To fix this, figure out which C math symbol is being used that causes it, and wrap it in workaround-missing-symbols.cpp.`); + } + }); +}