diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml index 7685ca1a0..42a13f100 100644 --- a/.github/workflows/daily.yml +++ b/.github/workflows/daily.yml @@ -11,7 +11,7 @@ on: inputs: skipjobs: description: 'jobs to skip (delete the ones you wanna keep, do not leave empty)' - default: 'valgrind,sanitizer,tls,freebsd,macos,alpine,32bit,iothreads,ubuntu,centos,malloc,specific,reply-schema' + default: 'valgrind,sanitizer,tls,freebsd,macos,alpine,32bit,iothreads,ubuntu,centos,malloc,specific,fortify,reply-schema' skiptests: description: 'tests to skip (delete the ones you wanna keep, do not leave empty)' default: 'redis,modules,sentinel,cluster,unittest' @@ -71,6 +71,50 @@ jobs: if: true && !contains(github.event.inputs.skiptests, 'unittest') run: ./src/redis-server test all --accurate + test-ubuntu-jemalloc-fortify: + runs-on: ubuntu-latest + if: | + (github.event_name == 'workflow_dispatch' || (github.event_name != 'workflow_dispatch' && github.repository == 'redis/redis')) && + !contains(github.event.inputs.skipjobs, 'fortify') + container: ubuntu:lunar + timeout-minutes: 14400 + steps: + - name: prep + if: github.event_name == 'workflow_dispatch' + run: | + echo "GITHUB_REPOSITORY=${{github.event.inputs.use_repo}}" >> $GITHUB_ENV + echo "GITHUB_HEAD_REF=${{github.event.inputs.use_git_ref}}" >> $GITHUB_ENV + echo "skipjobs: ${{github.event.inputs.skipjobs}}" + echo "skiptests: ${{github.event.inputs.skiptests}}" + echo "test_args: ${{github.event.inputs.test_args}}" + echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}" + - uses: actions/checkout@v3 + with: + repository: ${{ env.GITHUB_REPOSITORY }} + ref: ${{ env.GITHUB_HEAD_REF }} + - name: make + run: | + apt-get update && apt-get install -y make gcc-13 + update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100 + make CC=gcc REDIS_CFLAGS='-Werror -DREDIS_TEST -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3' + - name: testprep + run: apt-get install -y tcl8.6 tclx procps + - name: test + if: true && !contains(github.event.inputs.skiptests, 'redis') + run: ./runtest --accurate --verbose --dump-logs ${{github.event.inputs.test_args}} + - name: module api test + if: true && !contains(github.event.inputs.skiptests, 'modules') + run: ./runtest-moduleapi --verbose --dump-logs ${{github.event.inputs.test_args}} + - name: sentinel tests + if: true && !contains(github.event.inputs.skiptests, 'sentinel') + run: ./runtest-sentinel ${{github.event.inputs.cluster_test_args}} + - name: cluster tests + if: true && !contains(github.event.inputs.skiptests, 'cluster') + run: ./runtest-cluster ${{github.event.inputs.cluster_test_args}} + - name: unittest + if: true && !contains(github.event.inputs.skiptests, 'unittest') + run: ./src/redis-server test all --accurate + test-ubuntu-libc-malloc: runs-on: ubuntu-latest if: | diff --git a/deps/jemalloc/src/jemalloc.c b/deps/jemalloc/src/jemalloc.c index 97da1ee72..cbc31bbd5 100644 --- a/deps/jemalloc/src/jemalloc.c +++ b/deps/jemalloc/src/jemalloc.c @@ -1024,8 +1024,8 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS], static const char *opts_explain[MALLOC_CONF_NSOURCES] = { "string specified via --with-malloc-conf", "string pointed to by the global variable malloc_conf", - "\"name\" of the file referenced by the symbolic link named " - "/etc/malloc.conf", + ("\"name\" of the file referenced by the symbolic link named " + "/etc/malloc.conf"), "value of the environment variable MALLOC_CONF" }; unsigned i; diff --git a/src/config.h b/src/config.h index c3d80c831..3c9a27013 100644 --- a/src/config.h +++ b/src/config.h @@ -309,16 +309,6 @@ int pthread_setname_np(const char *name); void setcpuaffinity(const char *cpulist); #endif -/* deprecate unsafe functions - * - * NOTE: We do not use the poison pragma since it - * will error on stdlib definitions in files as well*/ -#if (__GNUC__ && __GNUC__ >= 4) && !defined __APPLE__ -int sprintf(char *str, const char *format, ...) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of snprintf instead"))); -char *strcpy(char *restrict dest, const char *src) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of redis_strlcpy instead"))); -char *strcat(char *restrict dest, const char *restrict src) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of redis_strlcat instead"))); -#endif - /* Test for posix_fadvise() */ #if defined(__linux__) || __FreeBSD__ >= 10 #define HAVE_FADVISE diff --git a/src/fmacros.h b/src/fmacros.h index a97d21a47..c5da4b734 100644 --- a/src/fmacros.h +++ b/src/fmacros.h @@ -58,6 +58,16 @@ #define _LARGEFILE_SOURCE #define _FILE_OFFSET_BITS 64 +/* deprecate unsafe functions + * + * NOTE: We do not use the poison pragma since it + * will error on stdlib definitions in files as well*/ +#if (__GNUC__ && __GNUC__ >= 4) && !defined __APPLE__ +int sprintf(char *str, const char *format, ...) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of snprintf instead"))); +char *strcpy(char *restrict dest, const char *src) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of redis_strlcpy instead"))); +char *strcat(char *restrict dest, const char *restrict src) __attribute__((deprecated("please avoid use of unsafe C functions. prefer use of redis_strlcat instead"))); +#endif + #ifdef __linux__ /* features.h uses the defines above to set feature specific defines. */ #include diff --git a/src/networking.c b/src/networking.c index 224b7df4b..f8fb6bee2 100644 --- a/src/networking.c +++ b/src/networking.c @@ -873,6 +873,7 @@ void addReplyDouble(client *c, double d) { const int dlen = d2string(dbuf+7,sizeof(dbuf)-7,d); int digits = digits10(dlen); int start = 4 - digits; + serverAssert(start >= 0); dbuf[start] = '$'; /* Convert `dlen` to string, putting it's digits after '$' and before the diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 0d10e8d3f..5e80de076 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -1414,6 +1414,7 @@ int parseOptions(int argc, char **argv) { int i; int lastarg; int exit_status = 1; + char *tls_usage; for (i = 1; i < argc; i++) { lastarg = (i == (argc-1)); @@ -1575,8 +1576,31 @@ invalid: printf("Invalid option \"%s\" or option argument missing\n\n",argv[i]); usage: + tls_usage = +#ifdef USE_OPENSSL +" --tls Establish a secure TLS connection.\n" +" --sni Server name indication for TLS.\n" +" --cacert CA Certificate file to verify with.\n" +" --cacertdir Directory where trusted CA certificates are stored.\n" +" If neither cacert nor cacertdir are specified, the default\n" +" system-wide trusted root certs configuration will apply.\n" +" --insecure Allow insecure TLS connection by skipping cert validation.\n" +" --cert Client certificate to authenticate with.\n" +" --key Private key file to authenticate with.\n" +" --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" +#ifdef TLS1_3_VERSION +" --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" +" and specifically for TLSv1.3 ciphersuites.\n" +#endif +#endif +""; + printf( -"%s%s", /* Split to avoid strings longer than 4095 (-Woverlength-strings). */ +"%s%s%s", /* Split to avoid strings longer than 4095 (-Woverlength-strings). */ "Usage: redis-benchmark [OPTIONS] [COMMAND ARGS...]\n\n" "Options:\n" " -h Server hostname (default 127.0.0.1)\n" @@ -1617,29 +1641,10 @@ usage: " The -t option is ignored if a specific command is supplied\n" " on the command line.\n" " -I Idle mode. Just open N idle connections and wait.\n" -" -x Read last argument from STDIN.\n" -#ifdef USE_OPENSSL -" --tls Establish a secure TLS connection.\n" -" --sni Server name indication for TLS.\n" -" --cacert CA Certificate file to verify with.\n" -" --cacertdir Directory where trusted CA certificates are stored.\n" -" If neither cacert nor cacertdir are specified, the default\n" -" system-wide trusted root certs configuration will apply.\n" -" --insecure Allow insecure TLS connection by skipping cert validation.\n" -" --cert Client certificate to authenticate with.\n" -" --key Private key file to authenticate with.\n" -" --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n" -" in order of preference from highest to lowest separated by colon (\":\").\n" -" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" -#ifdef TLS1_3_VERSION -" --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n" -" in order of preference from highest to lowest separated by colon (\":\").\n" -" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" -" and specifically for TLSv1.3 ciphersuites.\n" -#endif -#endif +" -x Read last argument from STDIN.\n", +tls_usage, " --help Output this help and exit.\n" -" --version Output version and exit.\n\n", +" --version Output version and exit.\n\n" "Examples:\n\n" " Run the benchmark with the default configuration against 127.0.0.1:6379:\n" " $ redis-benchmark\n\n" diff --git a/src/redis-cli.c b/src/redis-cli.c index 2bb2d6e67..ad2c79840 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -2981,6 +2981,29 @@ static void parseEnv() { static void usage(int err) { sds version = cliVersion(); FILE *target = err ? stderr: stdout; + const char *tls_usage = +#ifdef USE_OPENSSL +" --tls Establish a secure TLS connection.\n" +" --sni Server name indication for TLS.\n" +" --cacert CA Certificate file to verify with.\n" +" --cacertdir Directory where trusted CA certificates are stored.\n" +" If neither cacert nor cacertdir are specified, the default\n" +" system-wide trusted root certs configuration will apply.\n" +" --insecure Allow insecure TLS connection by skipping cert validation.\n" +" --cert Client certificate to authenticate with.\n" +" --key Private key file to authenticate with.\n" +" --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" +#ifdef TLS1_3_VERSION +" --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n" +" in order of preference from highest to lowest separated by colon (\":\").\n" +" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" +" and specifically for TLSv1.3 ciphersuites.\n" +#endif +#endif +""; + fprintf(target, "redis-cli %s\n" "\n" @@ -3012,26 +3035,7 @@ static void usage(int err) { " -D Delimiter between responses for raw formatting (default: \\n).\n" " -c Enable cluster mode (follow -ASK and -MOVED redirections).\n" " -e Return exit error code when command execution fails.\n" -#ifdef USE_OPENSSL -" --tls Establish a secure TLS connection.\n" -" --sni Server name indication for TLS.\n" -" --cacert CA Certificate file to verify with.\n" -" --cacertdir Directory where trusted CA certificates are stored.\n" -" If neither cacert nor cacertdir are specified, the default\n" -" system-wide trusted root certs configuration will apply.\n" -" --insecure Allow insecure TLS connection by skipping cert validation.\n" -" --cert Client certificate to authenticate with.\n" -" --key Private key file to authenticate with.\n" -" --tls-ciphers Sets the list of preferred ciphers (TLSv1.2 and below)\n" -" in order of preference from highest to lowest separated by colon (\":\").\n" -" See the ciphers(1ssl) manpage for more information about the syntax of this string.\n" -#ifdef TLS1_3_VERSION -" --tls-ciphersuites Sets the list of preferred ciphersuites (TLSv1.3)\n" -" in order of preference from highest to lowest separated by colon (\":\").\n" -" See the ciphers(1ssl) manpage for more information about the syntax of this string,\n" -" and specifically for TLSv1.3 ciphersuites.\n" -#endif -#endif +"%s" " --raw Use raw formatting for replies (default when STDOUT is\n" " not a tty).\n" " --no-raw Force formatted output even when STDOUT is not a tty.\n" @@ -3041,7 +3045,8 @@ static void usage(int err) { " --quoted-json Same as --json, but produce ASCII-safe quoted strings, not Unicode.\n" " --show-pushes Whether to print RESP3 PUSH messages. Enabled by default when\n" " STDOUT is a tty but can be overridden with --show-pushes no.\n" -" --stat Print rolling stats about server: mem, clients, ...\n",version); +" --stat Print rolling stats about server: mem, clients, ...\n", +version,tls_usage); fprintf(target, " --latency Enter a special mode continuously sampling latency.\n" diff --git a/src/server.c b/src/server.c index 1a9312df0..9ec13ef12 100644 --- a/src/server.c +++ b/src/server.c @@ -3128,6 +3128,7 @@ struct redisCommand *lookupCommandBySdsLogic(dict *commands, sds s) { return NULL; } + serverAssert(argc > 0); /* Avoid warning `-Wmaybe-uninitialized` in lookupCommandLogic() */ robj objects[argc]; robj *argv[argc]; for (j = 0; j < argc; j++) { diff --git a/src/sha1.h b/src/sha1.h index 167d0390c..a6cb6e885 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -15,7 +15,10 @@ typedef struct { void SHA1Transform(uint32_t state[5], const unsigned char buffer[64]); void SHA1Init(SHA1_CTX* context); -void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); +/* 'noinline' attribute is intended to prevent the `-Wstringop-overread` warning + * when using gcc-12 later with LTO enabled. It may be removed once the + * bug[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80922] is fixed. */ +__attribute__((noinline)) void SHA1Update(SHA1_CTX* context, const unsigned char* data, uint32_t len); void SHA1Final(unsigned char digest[20], SHA1_CTX* context); #ifdef REDIS_TEST diff --git a/src/zmalloc.h b/src/zmalloc.h index 9ed92407c..499cb7ec8 100644 --- a/src/zmalloc.h +++ b/src/zmalloc.h @@ -96,13 +96,16 @@ #define HAVE_DEFRAG #endif -__attribute__((malloc,alloc_size(1))) void *zmalloc(size_t size); -__attribute__((malloc,alloc_size(1))) void *zcalloc(size_t size); -__attribute__((malloc,alloc_size(1,2))) void *zcalloc_num(size_t num, size_t size); -__attribute__((alloc_size(2))) void *zrealloc(void *ptr, size_t size); -__attribute__((malloc,alloc_size(1))) void *ztrymalloc(size_t size); -__attribute__((malloc,alloc_size(1))) void *ztrycalloc(size_t size); -__attribute__((alloc_size(2))) void *ztryrealloc(void *ptr, size_t size); +/* 'noinline' attribute is intended to prevent the `-Wstringop-overread` warning + * when using gcc-12 later with LTO enabled. It may be removed once the + * bug[https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96503] is fixed. */ +__attribute__((malloc,alloc_size(1),noinline)) void *zmalloc(size_t size); +__attribute__((malloc,alloc_size(1),noinline)) void *zcalloc(size_t size); +__attribute__((malloc,alloc_size(1,2),noinline)) void *zcalloc_num(size_t num, size_t size); +__attribute__((alloc_size(2),noinline)) void *zrealloc(void *ptr, size_t size); +__attribute__((malloc,alloc_size(1),noinline)) void *ztrymalloc(size_t size); +__attribute__((malloc,alloc_size(1),noinline)) void *ztrycalloc(size_t size); +__attribute__((alloc_size(2),noinline)) void *ztryrealloc(void *ptr, size_t size); void zfree(void *ptr); void *zmalloc_usable(size_t size, size_t *usable); void *zcalloc_usable(size_t size, size_t *usable); diff --git a/tests/support/util.tcl b/tests/support/util.tcl index c98e7801b..a36003029 100644 --- a/tests/support/util.tcl +++ b/tests/support/util.tcl @@ -637,7 +637,7 @@ proc get_child_pid {idx} { } proc process_is_alive pid { - if {[catch {exec ps -p $pid} err]} { + if {[catch {exec ps -p $pid -f} err]} { return 0 } else { if {[string match "**" $err]} { return 0 }