Skip to content
Open

test #467

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions deps/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,21 @@ DEPS_CFLAGS := $(CFLAGS)
DEPS_LDFLAGS := $(LDFLAGS)
CLANG := $(findstring clang,$(shell sh -c '$(CC) --version | head -1'))

# Make sure the dependencies honor SANITIZER as well. Otherwise top-level
# sanitized Redis builds can end up linking unsanitized vendored libraries.
ifeq ($(SANITIZER),address)
DEPS_CFLAGS+=-fsanitize=address -fno-sanitize-recover=all -fno-omit-frame-pointer
DEPS_LDFLAGS+=-fsanitize=address
else
ifeq ($(SANITIZER),undefined)
DEPS_CFLAGS+=-fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer
DEPS_LDFLAGS+=-fsanitize=undefined
else
ifeq ($(SANITIZER),thread)
DEPS_CFLAGS+=-fsanitize=thread -fno-sanitize-recover=all -fno-omit-frame-pointer
DEPS_LDFLAGS+=-fsanitize=thread
else

# MSan looks for errors related to uninitialized memory.
# Make sure to build the dependencies with MSan as it needs all the code to be instrumented.
# A library could be used to initialize memory but if it's not build with --fsanitize=memory then
Expand All @@ -28,6 +43,9 @@ else
$(error "MemorySanitizer needs to be compiled and linked with clang. Please use CC=clang")
endif
endif
endif
endif
endif

default:
@echo "Explicit target required"
Expand Down Expand Up @@ -115,6 +133,13 @@ endif

LUA_CFLAGS+= -Wall -DLUA_ANSI -DENABLE_CJSON_GLOBAL -DREDIS_STATIC='' -DLUA_USE_MKSTEMP $(DEPS_CFLAGS)
LUA_LDFLAGS+= $(DEPS_LDFLAGS)
# Lua's table/index code intentionally casts possibly out-of-range lua_Numbers
# to int (it then validates via a round-trip comparison, e.g. luaH_get), which
# is benign but trips UBSan's float-cast-overflow check and aborts under
# -fno-sanitize-recover. Disable that sub-check for Lua only.
ifeq ($(SANITIZER),undefined)
LUA_CFLAGS+= -fno-sanitize=float-cast-overflow
endif
ifeq ($(LUA_DEBUG),yes)
LUA_CFLAGS+= -O0 -g -DLUA_USE_APICHECK
else
Expand Down
26 changes: 14 additions & 12 deletions deps/lua/src/lua_cmsgpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -628,10 +628,11 @@ void mp_decode_to_lua_type(lua_State *L, mp_cur *c) {
case 0xd2: /* int 32 */
mp_cur_need(c,5);
lua_pushinteger(L,
((int32_t)c->p[1] << 24) |
((int32_t)c->p[2] << 16) |
((int32_t)c->p[3] << 8) |
(int32_t)c->p[4]);
(int32_t)(
((uint32_t)c->p[1] << 24) |
((uint32_t)c->p[2] << 16) |
((uint32_t)c->p[3] << 8) |
(uint32_t)c->p[4]));
mp_cur_consume(c,5);
break;
case 0xcf: /* uint 64 */
Expand All @@ -654,14 +655,15 @@ void mp_decode_to_lua_type(lua_State *L, mp_cur *c) {
#else
lua_pushinteger(L,
#endif
((int64_t)c->p[1] << 56) |
((int64_t)c->p[2] << 48) |
((int64_t)c->p[3] << 40) |
((int64_t)c->p[4] << 32) |
((int64_t)c->p[5] << 24) |
((int64_t)c->p[6] << 16) |
((int64_t)c->p[7] << 8) |
(int64_t)c->p[8]);
(int64_t)(
((uint64_t)c->p[1] << 56) |
((uint64_t)c->p[2] << 48) |
((uint64_t)c->p[3] << 40) |
((uint64_t)c->p[4] << 32) |
((uint64_t)c->p[5] << 24) |
((uint64_t)c->p[6] << 16) |
((uint64_t)c->p[7] << 8) |
(uint64_t)c->p[8]));
mp_cur_consume(c,9);
break;
case 0xc0: /* nil */
Expand Down
9 changes: 9 additions & 0 deletions modules/vector-sets/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
# Compiler settings
CC = cc

CLANG := $(findstring clang,$(shell $(CC) --version 2>/dev/null | head -1))

ifdef SANITIZER
ifeq ($(SANITIZER),address)
SAN=-fsanitize=address
else
ifeq ($(SANITIZER),undefined)
SAN=-fsanitize=undefined
# The Redis module API calls every RedisModule_* symbol through a
# type-erased (void*-cast) function pointer, which is ABI-safe but trips
# clang UBSan's -fsanitize=function check. Disable that sub-check (the
# option/check is clang-only; gcc has no `function` sanitizer for C).
ifeq ($(CLANG),clang)
SAN+=-fno-sanitize=function
endif
else
ifeq ($(SANITIZER),thread)
SAN=-fsanitize=thread
Expand Down
15 changes: 15 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,19 @@ CLANG := $(findstring clang,$(shell sh -c '$(CC) --version | head -1'))
# explicitly without any defaults added, pass the OPT variable instead.
OPTIMIZATION?=-O3
ENABLE_LTO?=
# Don't enable LTO under a sanitizer build: clang's LTO emits per-TU ASan
# module destructors that the GNU bfd linker fails to resolve ("defined in
# discarded section"), and LTO offers no benefit while sanitizing anyway.
ifeq ($(OPTIMIZATION),-O3)
ifeq ($(SANITIZER),)
ifeq (clang,$(CLANG))
ENABLE_LTO=-flto
else
ENABLE_LTO=-flto=auto -ffat-lto-objects
endif
OPTIMIZATION+=$(ENABLE_LTO)
endif
endif
ifneq ($(OPTIMIZATION),-O0)
OPTIMIZATION+=-fno-omit-frame-pointer
endif
Expand Down Expand Up @@ -343,6 +348,16 @@ ifneq ($(SKIP_VEC_SETS),yes)
vpath %.c ../modules/vector-sets
REDIS_VEC_SETS_OBJ=hnsw.o vset.o vset_config.o
FINAL_CFLAGS+=-DINCLUDE_VEC_SETS=1
# Vector sets are built into the server but use the Redis module API
# (redismodule.h), which calls every RedisModule_* symbol through a type-erased
# (void*-cast) function pointer. That is ABI-safe but trips clang UBSan's
# -fsanitize=function check, so disable that sub-check for these objects only
# (the check is clang-only; gcc has no C `function` sanitizer).
ifeq ($(SANITIZER),undefined)
ifeq ($(CLANG),clang)
$(REDIS_VEC_SETS_OBJ): FINAL_CFLAGS += -fno-sanitize=function
endif
endif
endif

ifndef V
Expand Down
8 changes: 7 additions & 1 deletion src/module.c
Original file line number Diff line number Diff line change
Expand Up @@ -13390,7 +13390,13 @@ int moduleLoad(const char *path, void **module_argv, int module_argc, int is_loa
}

/* Load a module by its 'onload' callback and initialize it. On success C_OK is returned, otherwise
* C_ERR is returned. */
* C_ERR is returned.
*
* The module's RedisModule_OnLoad is resolved via dlsym and called through a
* type-erased pointer (int (*)(void *, void **, int)), which does not match its
* real signature (int (RedisModuleCtx *, RedisModuleString **, int)). This is
* intentional and ABI-safe, but trips UBSan's -fsanitize=function check, so we
* disable it for this function only. */
int moduleOnLoad(int (*onload)(void *, void **, int), const char *path, void *handle, void **module_argv, int module_argc, int is_loadex) {
RedisModuleCtx ctx;
moduleCreateContext(&ctx, NULL, REDISMODULE_CTX_TEMP_CLIENT); /* We pass NULL since we don't have a module yet. */
Expand Down
10 changes: 10 additions & 0 deletions src/tsan.sup
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ signal:printCrashReport
# https://github.com/jemalloc/jemalloc/issues/2621
race:malloc_mutex_trylock_final

# redis-benchmark with --threads shares one hdr_histogram across worker threads:
# they record latencies via hdr_record_value_atomic (atomic increments to the
# counts/min/max/total) while thread 0's showThroughput reads it with non-atomic
# accessors (hdr_mean) and periodically resets current_sec via hdr_reset, to
# print live throughput. The displayed stats are approximate by design, so these
# races are benign and not worth per-bucket synchronization. hdr_histogram is
# only accessed concurrently by redis-benchmark; the server uses it from the
# main thread only. The final benchmark report runs after all workers stopped.
race:hdr_histogram.c

# A race can happen on conn->last_errno if replica client is reading/writing
# data in IO thread and main thread is calling connAddrPeerName for some reason
# (f.e genRedisInfoString/roleCommand...).
Expand Down
16 changes: 13 additions & 3 deletions tests/support/benchmark.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,32 @@ proc redisbenchmark_tls_config {testsdir} {
}
}

# When running under ThreadSanitizer, redis-benchmark must load the same
# suppressions file as the server (it is exec'd separately and otherwise gets
# no TSAN_OPTIONS). Returns an `env`-prefix list, or empty when not under tsan.
proc redisbenchmark_tsan_prefix {} {
if {$::tsan} {
return [list /usr/bin/env "TSAN_OPTIONS=allocator_may_return_null=1,detect_deadlocks=0,suppressions=src/tsan.sup"]
}
return {}
}

proc redisbenchmark {host port {opts {}}} {
set cmd [list src/redis-benchmark -h $host -p $port]
set cmd [list {*}[redisbenchmark_tsan_prefix] src/redis-benchmark -h $host -p $port]
lappend cmd {*}[redisbenchmark_tls_config "tests"]
lappend cmd {*}$opts
return $cmd
}

proc redisbenchmarkuri {host port {opts {}}} {
set cmd [list src/redis-benchmark -u redis://$host:$port]
set cmd [list {*}[redisbenchmark_tsan_prefix] src/redis-benchmark -u redis://$host:$port]
lappend cmd {*}[redisbenchmark_tls_config "tests"]
lappend cmd {*}$opts
return $cmd
}

proc redisbenchmarkuriuserpass {host port user pass {opts {}}} {
set cmd [list src/redis-benchmark -u redis://$user:$pass@$host:$port]
set cmd [list {*}[redisbenchmark_tsan_prefix] src/redis-benchmark -u redis://$user:$pass@$host:$port]
lappend cmd {*}[redisbenchmark_tls_config "tests"]
lappend cmd {*}$opts
return $cmd
Expand Down
Loading