commit 4b22351c31db179a117ab4658745bc16ef4ec73f from: Sergey Bronnikov date: Fri Jun 21 13:33:41 2024 UTC cmake: update UBSan integration in LuaJIT The patch updates integration of Undefined Behaviour Sanitizer with LuaJIT: some suppressions removed, some suppressions added per file, not project-wide. The patch is based on the patch made by Sergey Kaplun [1]. 1. https://github.com/tarantool/luajit/commit/b9ff5ae8ea60516f630a380948bfd140c237385a commit - b9f120ef9bd9064c343e73cd65f9f43f4da37892 commit + 4b22351c31db179a117ab4658745bc16ef4ec73f blob - 7ddcc982461b93dd2cf2cd9e5828959067859c1c blob + ffe9176a1142b82e308eb15b81e2e33b592a75c1 --- cmake/BuildLuaJIT.cmake +++ cmake/BuildLuaJIT.cmake @@ -33,35 +33,44 @@ macro(build_luajit LJ_VERSION) if (ENABLE_UBSAN) string(JOIN "," NO_SANITIZE_FLAGS - # lj_str.c - implicit-integer-sign-change - # lj_opt_fold.c - implicit-unsigned-integer-truncation - # lj_parse.c + # Misaligned pseudo-pointers are used to determine + # internal variable names inside the `for` cycle. alignment - # lj_tab.c + # Not interested in float cast overflow errors. These + # overflows are handled by special checks after + # `lj_num2int()`, etc. float-cast-overflow - # lj_gc.c - function - # lj_buf.c - shift - # lj_obj.h - unsigned-integer-overflow - # lj_prng.c - unsigned-shift-base - # lj_parse.c - pointer-overflow - # The object size sanitizer has no effect at -O0. - object-size - # lj_parse.c + # NULL checking is disabled because this is not a UB + # and raises lots of false-positive fails. null - # lj_vmmath.c - float-divide-by-zero - integer-divide-by-zero + # Not interested in checking arithmetic with NULL. + pointer-overflow + # Shifts of negative numbers are widely used in + # parsing ULEB, cdata arithmetic, vmevent hash + # calculation, etc. + shift-base ) + # GCC has no "function" UB check. + if(NOT CMAKE_C_COMPILER_ID STREQUAL "GNU") + string(JOIN "," NO_SANITIZE_FLAGS + ${NO_SANITIZE_FLAGS} + # Not interested in function type mismatch errors. + function + ) + endif() + # Enable UndefinedBehaviorSanitizer support. + # This flag enables all supported options (the + # documentation on site is not correct about that moment, + # unfortunately) except float-divide-by-zero. Floating + # point division by zero behaviour is defined without + # -ffast-math and uses the IEEE 754 standard on which all + # NaN tagging is based. set(UBSAN_FLAGS "-fsanitize=undefined") set(UBSAN_FLAGS "-fno-sanitize-recover=undefined") + # XXX: To get nicer stack traces in error messages. + set(UBSAN_FLAGS "-fno-omit-frame-pointer") set(UBSAN_FLAGS "-fno-sanitize=${NO_SANITIZE_FLAGS}") + set(CFLAGS "${CFLAGS} -DLUAJIT_USE_UBSAN") set(CFLAGS "${CFLAGS} ${UBSAN_FLAGS}") set(LDFLAGS "${LDFLAGS} ${UBSAN_FLAGS}") endif (ENABLE_UBSAN) blob - f03f959b136b8bd6e5a66bf38bed102c2883f1f7 blob + 2ee1561e6ca7b1d4b792961f3b16f670c41cc34a --- patches/luajit-v2.1.patch +++ patches/luajit-v2.1.patch @@ -1,26 +1,110 @@ diff --git a/src/host/buildvm.c b/src/host/buildvm.c -index 9ee47ada..0cb6be1b 100644 +index ec99e501..d23530c4 100644 --- a/src/host/buildvm.c +++ b/src/host/buildvm.c @@ -35,6 +35,10 @@ #include #endif - + +#if LUAJIT_USE_ASAN +int __lsan_is_turned_off() { return 1; } /* leaks are ok */ +#endif + /* ------------------------------------------------------------------------ */ - + /* DynASM glue definitions. */ +diff --git a/src/lj_buf.h b/src/lj_buf.h +index 744e5747..ea299472 100644 +--- a/src/lj_buf.h ++++ b/src/lj_buf.h +@@ -165,6 +165,13 @@ LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putchar(SBuf *sb, int c); + #endif + LJ_FUNC SBuf * LJ_FASTCALL lj_buf_putstr(SBuf *sb, GCstr *s); + ++#if LUAJIT_USE_UBSAN ++/* The `NULL` argument with the zero length, like in the case: ++** | luajit -e 'error("x", 3)' ++*/ ++static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len) ++ __attribute__((no_sanitize("nonnull-attribute"))); ++#endif + static LJ_AINLINE char *lj_buf_wmem(char *p, const void *q, MSize len) + { + return (char *)memcpy(p, q, len) + len; +diff --git a/src/lj_carith.c b/src/lj_carith.c +index 9bea0a33..046dea4c 100644 +--- a/src/lj_carith.c ++++ b/src/lj_carith.c +@@ -159,6 +159,11 @@ static int carith_ptr(lua_State *L, CTState *cts, CDArith *ca, MMS mm) + } + + /* 64 bit integer arithmetic. */ ++#if LUAJIT_USE_UBSAN ++/* See https://github.com/LuaJIT/LuaJIT/issues/928. */ ++static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) ++ __attribute__((no_sanitize("signed-integer-overflow"))); ++#endif + static int carith_int64(lua_State *L, CTState *cts, CDArith *ca, MMS mm) + { + if (ctype_isnum(ca->ct[0]->info) && ca->ct[0]->size <= 8 && +diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c +index ce78505b..bc9d64f3 100644 +--- a/src/lj_opt_fold.c ++++ b/src/lj_opt_fold.c +@@ -260,6 +260,11 @@ LJFOLDF(kfold_numcomp) + + /* -- Constant folding for 32 bit integers -------------------------------- */ + ++#if LUAJIT_USE_UBSAN ++/* Cdata arithmetic depends on the interger overflow. */ ++static int32_t kfold_intop(int32_t k1, int32_t k2, IROp op) ++ __attribute__((no_sanitize("signed-integer-overflow"))); ++#endif + static int32_t kfold_intop(int32_t k1, int32_t k2, IROp op) + { + switch (op) { +diff --git a/src/lj_parse.c b/src/lj_parse.c +index 5a44f8db..bfe044a8 100644 +--- a/src/lj_parse.c ++++ b/src/lj_parse.c +@@ -934,6 +934,11 @@ static void bcemit_binop(FuncState *fs, BinOpr op, ExpDesc *e1, ExpDesc *e2) + } + + /* Emit unary operator. */ ++#if LUAJIT_USE_UBSAN ++/* See https://github.com/LuaJIT/LuaJIT/issues/928. */ ++static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e) ++ __attribute__((no_sanitize("signed-integer-overflow"))); ++#endif + static void bcemit_unop(FuncState *fs, BCOp op, ExpDesc *e) + { + if (op == BC_NOT) { +diff --git a/src/lj_snap.c b/src/lj_snap.c +index 6fda08ba..c7f51d7d 100644 +--- a/src/lj_snap.c ++++ b/src/lj_snap.c +@@ -763,6 +763,13 @@ static void snap_restoreval(jit_State *J, GCtrace *T, ExitState *ex, + } + + #if LJ_HASFFI ++# if LUAJIT_USE_UBSAN ++/* See https://github.com/LuaJIT/LuaJIT/issues/1193. */ ++static void snap_restoredata(jit_State *J, GCtrace *T, ExitState *ex, ++ SnapNo snapno, BloomFilter rfilt, ++ IRRef ref, void *dst, CTSize sz) ++ __attribute__((no_sanitize("bounds"))); ++# endif + /* Restore raw data from the trace exit state. */ + static void snap_restoredata(jit_State *J, GCtrace *T, ExitState *ex, + SnapNo snapno, BloomFilter rfilt, diff --git a/src/lj_str.c b/src/lj_str.c -index a5282da6..f31172bb 100644 +index cfdaec6f..88f9c765 100644 --- a/src/lj_str.c +++ b/src/lj_str.c @@ -13,6 +13,15 @@ #include "lj_char.h" #include "lj_prng.h" - + +#if LUAJIT_USE_ASAN +/* These functions may read past a buffer end, that's ok. */ +GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx) @@ -31,5 +115,21 @@ index a5282da6..f31172bb 100644 +#endif /* LUAJIT_USE_ASAN */ + /* -- String helpers ------------------------------------------------------ */ - + /* Ordered compare of strings. Assumes string data is 4-byte aligned. */ +diff --git a/src/lj_strfmt.c b/src/lj_strfmt.c +index 909255db..ef9bd4f9 100644 +--- a/src/lj_strfmt.c ++++ b/src/lj_strfmt.c +@@ -99,6 +99,11 @@ retlit: + { uint32_t d = (x*(((1<>sh; x -= d*sc; *p++ = (char)('0'+d); } + + /* Write integer to buffer. */ ++#if LUAJIT_USE_UBSAN ++/* See https://github.com/LuaJIT/LuaJIT/issues/928. */ ++char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k) ++ __attribute__((no_sanitize("signed-integer-overflow"))); ++#endif + char * LJ_FASTCALL lj_strfmt_wint(char *p, int32_t k) + { + uint32_t u = (uint32_t)k;