diff --git a/ubuntu-latest/Dockerfile b/ubuntu-latest/Dockerfile index 91b75d1..ae5f4c9 100644 --- a/ubuntu-latest/Dockerfile +++ b/ubuntu-latest/Dockerfile @@ -77,8 +77,28 @@ RUN opam init --yes --auto-setup && opam install --confirm-level=unsafe-yes --de # install ajv for CBOM validation RUN npm -g install ajv ajv-cli +# set up Kyberslash patch for Valgrind-based constant-time testing +COPY valgrind-try-patch-20250805.txt /tmp/ +COPY valgrind-varlat-patch-20250805.txt /tmp/ +COPY valgrind-varlat-sup-block.txt /tmp/ + +RUN git clone git://sourceware.org/git/valgrind.git /tmp/valgrind_varlat_src && \ + cd /tmp/valgrind_varlat_src && \ + git checkout 112f1080b7c21e37dfce0a2e589d0dc7aa115afa && \ + git apply /tmp/valgrind-try-patch-20250805.txt && \ + git apply /tmp/valgrind-varlat-patch-20250805.txt && \ + git apply /tmp/valgrind-varlat-sup-block.txt && \ + ./autogen.sh && \ + ./configure --prefix=/opt/valgrind_varlat && \ + make -j"$(nproc)" && \ + make install && \ + mv /opt/valgrind_varlat/bin/valgrind /opt/valgrind_varlat/bin/valgrind_varlat && \ + cd / && rm -rf /tmp/valgrind_varlat_src /tmp/*.txt + +ENV PATH="/opt/valgrind_varlat/bin:${PATH}" + # set JAVA_HOME for liboqs-java builds ENV JAVA_HOME="/usr/lib/jvm/default-java" # Activate if we want to test specific OpenSSL3 versions: -# RUN cd /root && git clone --depth 1 --branch openssl-3.0.7 https://github.com/openssl/openssl.git && cd openssl && LDFLAGS="-Wl,-rpath -Wl,/usr/local/openssl3/lib64" ./config --prefix=/usr/local/openssl3 && make -j && make install +# RUN cd /root && git clone --depth 1 --branch openssl-3.0.7 https://github.com/openssl/openssl.git && cd openssl && LDFLAGS="-Wl,-rpath -Wl,/usr/local/openssl3/lib64" ./config --prefix=/usr/local/openssl3 && make -j && make install \ No newline at end of file diff --git a/ubuntu-latest/valgrind-try-patch-20250805.txt b/ubuntu-latest/valgrind-try-patch-20250805.txt new file mode 100644 index 0000000..395d41c --- /dev/null +++ b/ubuntu-latest/valgrind-try-patch-20250805.txt @@ -0,0 +1,1578 @@ +diff --git a/coregrind/m_commandline.c b/coregrind/m_commandline.c +index e9fdb9bb4..4e120db0d 100644 +--- a/coregrind/m_commandline.c ++++ b/coregrind/m_commandline.c +@@ -41,7 +41,7 @@ + + /* Add a string to an expandable array of strings. */ + +-static void add_string ( XArray* /* of HChar* */xa, HChar* str ) ++static void add_string ( XArray* /* of HChar* */xa, const HChar* str ) + { + (void) VG_(addToXA)( xa, (void*)(&str) ); + } +@@ -93,8 +93,9 @@ static HChar* read_dot_valgrindrc ( const HChar* dir ) + + // Add args from a string into VG_(args_for_valgrind), splitting the + // string at whitespace and adding each component as a separate arg. ++// If try is set: add --try before each arg. + +-static void add_args_from_string ( HChar* s ) ++static void add_args_from_string ( HChar* s, Bool try ) + { + HChar* tmp; + HChar* cp = s; +@@ -120,6 +121,7 @@ static void add_args_from_string ( HChar* s ) + } + if (out < cp) *out++ = '\0'; + if ( *cp != 0 ) *cp++ = '\0'; // terminate if not the last ++ if (try) add_string( VG_(args_for_valgrind), "--try" ); + add_string( VG_(args_for_valgrind), tmp ); + } + } +@@ -131,6 +133,7 @@ static void add_args_from_string ( HChar* s ) + The resulting arg list is the concatenation of the following: + - contents of ~/.valgrindrc + - contents of $VALGRIND_OPTS ++ - contents of $VALGRIND_TRY_OPTS with --try included + - contents of ./.valgrindrc + - args from the command line + in the stated order. +@@ -157,7 +160,7 @@ static void add_args_from_string ( HChar* s ) + args-for-v are then copied into tmp_xarray. + + if args-for-v does not include --command-line-only=yes: +- contents of ~/.valgrindrc, $VALGRIND_OPTS and ./.valgrindrc ++ contents of ~/.valgrindrc, $VALGRIND_OPTS, $VALGRIND_TRY_OPTS and ./.valgrindrc + are copied into VG_(args_for_valgrind). + else + VG_(args_for_valgrind) is made empty. +@@ -223,7 +226,7 @@ void VG_(split_up_argv)( Int argc, HChar** argv ) + add_string( VG_(args_for_client), argv[i] ); + } + +- /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS and ++ /* Get extra args from ~/.valgrindrc, $VALGRIND_OPTS, $VALGRIND_TRY_OPTS and + ./.valgrindrc into VG_(args_for_valgrind). */ + if (augment) { + // read_dot_valgrindrc() allocates the return value with +@@ -233,6 +236,8 @@ void VG_(split_up_argv)( Int argc, HChar** argv ) + HChar* f1_clo = home ? read_dot_valgrindrc( home ) : NULL; + HChar* env_clo = VG_(strdup)( "commandline.sua.4", + VG_(getenv)(VALGRIND_OPTS) ); ++ HChar* env_try_clo = VG_(strdup)( "commandline.sua.5", ++ VG_(getenv)(VALGRIND_TRY_OPTS) ); + HChar* f2_clo = NULL; + + // Don't read ./.valgrindrc if "." is the same as "$HOME", else its +@@ -244,9 +249,10 @@ void VG_(split_up_argv)( Int argc, HChar** argv ) + ? NULL : read_dot_valgrindrc(".") ); + } + +- if (f1_clo) add_args_from_string( f1_clo ); +- if (env_clo) add_args_from_string( env_clo ); +- if (f2_clo) add_args_from_string( f2_clo ); ++ if (f1_clo) add_args_from_string( f1_clo, False ); ++ if (env_clo) add_args_from_string( env_clo, False ); ++ if (env_try_clo) add_args_from_string( env_try_clo, True ); ++ if (f2_clo) add_args_from_string( f2_clo, False ); + } + + /* .. and record how many extras we got. */ +diff --git a/coregrind/m_main.c b/coregrind/m_main.c +index f7fd20dba..7a35b7b6d 100644 +--- a/coregrind/m_main.c ++++ b/coregrind/m_main.c +@@ -289,7 +289,8 @@ static void usage_NORETURN ( int need_help ) + " --sym-offsets=yes|no show syms in form 'name+offset'? [no]\n" + " --progress-interval= report progress every \n" + " CPU seconds [0, meaning disabled]\n" +-" --command-line-only=no|yes only use command line options [no]\n\n" ++" --command-line-only=no|yes only use command line options [no]\n" ++" --try skip next option if option is unsupported\n\n" + " Vex options for all Valgrind tools:\n" + " --vex-iropt-verbosity=<0..9> [0]\n" + " --vex-iropt-level=<0..2> [2]\n" +@@ -333,7 +334,7 @@ static void usage_NORETURN ( int need_help ) + + const HChar usage3[] = + "\n" +-" Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, ./.valgrindrc\n" ++" Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, $VALGRIND_TRY_OPTS, ./.valgrindrc\n" + "\n" + " %s is %s\n" + " Valgrind is Copyright (C) 2000-2024, and GNU GPL'd, by Julian Seward et al.\n" +@@ -429,6 +430,10 @@ struct process_option_state { + VgLogTo xml_to; // Where is XML output to be sent? + Int tmp_log_fd; + Int tmp_xml_fd; ++ ++ /* For cloP: True if immediately preceding option was --try. */ ++ /* For other modes: Irrelevant. */ ++ Bool try; + }; + + static void process_option (Clo_Mode mode, +@@ -438,6 +443,7 @@ static void process_option (Clo_Mode mode, + Int toolname_len = VG_(strlen)(VG_(clo_toolname)); + HChar* colon = arg; + UInt ix = 0; ++ Bool prevtry = pos->try; + + /* Constants for parsing PX control flags. */ + const HChar* pxStrings[5] +@@ -448,6 +454,7 @@ static void process_option (Clo_Mode mode, + VexRegUpdAllregsAtMemAccess, VexRegUpdAllregsAtEachInsn, 0/*inval*/ }; + + VG_(set_Clo_Mode) (mode); ++ pos->try = False; + + // Look for a colon in the option name. + while (*colon && *colon != ':' && *colon != '=') +@@ -921,14 +928,17 @@ static void process_option (Clo_Mode mode, + else if VG_XACT_CLO(arg, "--resync-filter=verbose", + VG_(clo_resync_filter), 2) {} + ++ else if VG_XACT_CLO(arg, "--try", pos->try, True) {} + else if ( VG_(Clo_Mode)() != cloE // tool does not have Early options + && !VG_(Clo_Recognised) () + && (! VG_(needs).command_line_options + || ! VG_TDICT_CALL(tool_process_cmd_line_option, arg) )) { + if (VG_(Clo_Mode)() == cloH) + ; +- else if (VG_(Clo_Mode)() == cloP && !VG_(Clo_Recognised) ()) +- VG_(fmsg_unknown_option)(arg); ++ else if (VG_(Clo_Mode)() == cloP && !VG_(Clo_Recognised) ()) { ++ if (!prevtry) ++ VG_(fmsg_unknown_option)(arg); ++ } + else if (VG_(Clo_Mode)() == cloD && !VG_(Clo_Recognised) ()) + VG_(umsg)("Ignoring dynamic change to unrecognised option %s\n", arg); + } +@@ -962,7 +972,7 @@ static void early_process_cmd_line_options ( /*OUT*/Int* need_help ) + UInt i; + HChar* str; + struct process_option_state pos +- = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1}; ++ = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1, False}; + + vg_assert( VG_(args_for_valgrind) ); + +@@ -1003,7 +1013,7 @@ void main_process_cmd_line_options( void ) + { + Int i; + struct process_option_state pos +- = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1}; ++ = {0, 0, False, False, VgLogTo_Fd, VgLogTo_Fd, 2, -1, False}; + + /* Check for sane path in ./configure --prefix=... */ + if (VG_LIBDIR[0] != '/') +diff --git a/coregrind/pub_core_libcproc.h b/coregrind/pub_core_libcproc.h +index 488aaf0ca..5b580a474 100644 +--- a/coregrind/pub_core_libcproc.h ++++ b/coregrind/pub_core_libcproc.h +@@ -53,6 +53,9 @@ + is no quoting mechanism. */ + #define VALGRIND_OPTS "VALGRIND_OPTS" + ++/* Same as VALGRIND_OPTS but puts --try before each option. */ ++#define VALGRIND_TRY_OPTS "VALGRIND_TRY_OPTS" ++ + /* The full name of Valgrind's stage1 (launcher) executable. This is + set by stage1 and read by stage2, and is used for recursive + invocations of Valgrind on child processes. +diff --git a/docs/xml/manual-core.xml b/docs/xml/manual-core.xml +index 9ab09b51b..7d07d93fc 100644 +--- a/docs/xml/manual-core.xml ++++ b/docs/xml/manual-core.xml +@@ -2839,7 +2839,7 @@ Valgrind itself, then you should use the options + + Setting Default Options + +-Note that Valgrind also reads options from three places: ++Note that Valgrind also reads options from four places: + + + +@@ -2851,6 +2851,13 @@ Valgrind itself, then you should use the options + $VALGRIND_OPTS + + ++ ++ Starting with Valgrind 3.26: The environment variable ++ $VALGRIND_TRY_OPTS ++ (see below for the difference from ++ $VALGRIND_OPTS) ++ ++ + + The file ./.valgrindrc + +@@ -2873,7 +2880,8 @@ your user account. + + + Any tool-specific options put in +-$VALGRIND_OPTS or the ++$VALGRIND_OPTS or ++$VALGRIND_TRY_OPTS or the + .valgrindrc files should be + prefixed with the tool name and a colon. For example, if you + want Memcheck to always do leak checking, you can put the +@@ -2888,6 +2896,51 @@ part, this will cause problems if you select other tools that + don't understand + . + ++Starting with Valgrind 3.26, ++$VALGRIND_TRY_OPTS ++is handled the same way as ++$VALGRIND_OPTS ++except that unsupported options in ++$VALGRIND_TRY_OPTS ++are skipped rather than stopping Valgrind. ++This makes ++$VALGRIND_TRY_OPTS ++suitable for best-effort ++"please use this option if it is available" scripts. ++ ++Starting with Valgrind 3.26, there is also a ++ ++option that, if it immediately precedes an unsupported option, ++will cause the unsupported option ++to be skipped rather than stopping Valgrind. ++The advantage of ++ ++over ++$VALGRIND_TRY_OPTS ++is that, in situations where the order of options is important, ++ ++can be inserted at any point in the option list, ++whereas ++$VALGRIND_TRY_OPTS ++is always handled after ++$VALGRIND_OPTS. ++The disadvantage of ++ ++is that it will stop Valgrind 3.25 and earlier. ++ ++If ++--command-line-only=yes ++appears on the command line ++then all of the above default-option mechanisms are ignored. ++Furthermore, the options ++--command-line-only, ++--profile-heap, ++--core-redzone-size, ++--redzone-size, ++and ++--aspace-minaddr ++are usable only on the command line ++and not via the default-option mechanisms. + + + +diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am +index 91d58b48b..633c036c3 100644 +--- a/memcheck/tests/Makefile.am ++++ b/memcheck/tests/Makefile.am +@@ -472,7 +472,8 @@ EXTRA_DIST = \ + wrapmallocstatic.vgtest wrapmallocstatic.stdout.exp \ + wrapmallocstatic.stderr.exp \ + writev1.stderr.exp writev1.stderr.exp-solaris writev1.vgtest \ +- xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc ++ xml1.stderr.exp xml1.stdout.exp xml1.vgtest xml1.stderr.exp-s390x-mvc \ ++ xml1_env.stderr.exp xml1_env.stdout.exp xml1_env.vgtest xml1_env.stderr.exp-s390x-mvc + + check_PROGRAMS = \ + accounting \ +diff --git a/memcheck/tests/xml1_env.stderr.exp b/memcheck/tests/xml1_env.stderr.exp +new file mode 100644 +index 000000000..8ff61a531 +--- /dev/null ++++ b/memcheck/tests/xml1_env.stderr.exp +@@ -0,0 +1,440 @@ ++ ++ ++ ++ ++6 ++memcheck ++ ++ ++ ... ++ ... ++ ... ++ ... ++ ++ ++... ++... ++memcheck ++ ++ ++ ... ++ ++ ./xml1 ++ ++ ++ ++ ++ RUNNING ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidRead ++ Invalid read of size N ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is 0 bytes after a block of size 40 alloc'd ++ ++ ++ 0x........ ++ ... ++ malloc ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ UninitCondition ++ Conditional jump or move depends on uninitialised value(s) ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ UninitValue ++ Use of uninitialised value of size N ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidFree ++ Invalid free() / delete / delete[] / realloc() ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is 0 bytes inside a block of size 40 free'd ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidFree ++ Invalid free() / delete / delete[] / realloc() ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is on thread 1's stack ++ in frame #1, created by frame3 (xml1.c:7) ++ ++ ++ ++ 0x........ ++ ... ++ SyscallParam ++ Syscall param exit(status) contains uninitialised byte(s) ++ ++ ++ ++ FINISHED ++ ++ ++ ++... ++ ++ ++ 0x........ ++ ... ++ Leak_DefinitelyLost ++ ++ 396 bytes in 1 blocks are definitely lost in loss record ... of ... ++ 396 ++ 1 ++ ++ ++ ++ 0x........ ++ ... ++ malloc ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++... ++ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ++... ++ ++... ++ ++ +diff --git a/memcheck/tests/xml1_env.stderr.exp-s390x-mvc b/memcheck/tests/xml1_env.stderr.exp-s390x-mvc +new file mode 100644 +index 000000000..e1abac28a +--- /dev/null ++++ b/memcheck/tests/xml1_env.stderr.exp-s390x-mvc +@@ -0,0 +1,436 @@ ++ ++ ++ ++ ++4 ++memcheck ++ ++ ++ ... ++ ... ++ ... ++ ... ++ ++ ++... ++... ++memcheck ++ ++ ++ ... ++ ++ ./xml1 ++ ++ ++ ++ ++ RUNNING ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidRead ++ Invalid read of size 1 ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is 0 bytes after a block of size 40 alloc'd ++ ++ ++ 0x........ ++ ... ++ malloc ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ UninitCondition ++ Conditional jump or move depends on uninitialised value(s) ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ UninitValue ++ Use of uninitialised value of size N ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidFree ++ Invalid free() / delete / delete[] / realloc() ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is 0 bytes inside a block of size 40 free'd ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ 0x........ ++ ... ++ InvalidFree ++ Invalid free() / delete / delete[] / realloc() ++ ++ ++ 0x........ ++ ... ++ free ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ Address 0x........ is on thread 1's stack ++ in frame #1, created by frame3 (xml1.c:7) ++ ++ ++ ++ 0x........ ++ ... ++ SyscallParam ++ Syscall param exit(status) contains uninitialised byte(s) ++ ++ ++ ++ ++ FINISHED ++ ++ ++ ++ ++ 0x........ ++ ... ++ Leak_DefinitelyLost ++ ++ 396 bytes in 1 blocks are definitely lost in loss record ... of ... ++ 396 ++ 1 ++ ++ ++ ++ 0x........ ++ ... ++ malloc ++ ... ++ vg_replace_malloc.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame3 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame2 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ frame1 ++ ... ++ xml1.c ++ ... ++ ++ ++ 0x........ ++ ... ++ main ++ ... ++ xml1.c ++ ... ++ ++ ++ ++ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ... ++ 0x........ ++ ++ ++ ++... ++ ++ ++ +diff --git a/memcheck/tests/xml1_env.stdout.exp b/memcheck/tests/xml1_env.stdout.exp +new file mode 100644 +index 000000000..9397eece6 +--- /dev/null ++++ b/memcheck/tests/xml1_env.stdout.exp +@@ -0,0 +1 @@ ++hello from frame3(). The answer is not 42. +diff --git a/memcheck/tests/xml1_env.vgtest b/memcheck/tests/xml1_env.vgtest +new file mode 100644 +index 000000000..6b6cd8aab +--- /dev/null ++++ b/memcheck/tests/xml1_env.vgtest +@@ -0,0 +1,4 @@ ++prog: xml1 ++vgopts: --command-line-only=no ++env: VALGRIND_TRY_OPTS='--xml=yes --xml-fd=2 --log-file=/dev/null --keep-stacktraces=alloc-then-free' ++stderr_filter: filter_xml +diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am +index 716ce000d..9961b80d8 100644 +--- a/none/tests/Makefile.am ++++ b/none/tests/Makefile.am +@@ -88,6 +88,7 @@ dist_noinst_SCRIPTS = \ + filter_fdleak \ + filter_ioctl_moans \ + filter_none_discards \ ++ filter_optlist \ + filter_stderr \ + filter_timestamp \ + filter_xml \ +@@ -134,6 +135,15 @@ EXTRA_DIST = \ + double_close_range_xml.vgtest \ + double_close_range_sup.stderr.exp double_close_range_sup.vgtest \ + empty-exe.vgtest empty-exe.stderr.exp \ ++ env1.stderr.exp env1.vgtest try1.stderr.exp try1.vgtest \ ++ env2.stderr.exp env2.vgtest try2.stderr.exp try2.vgtest \ ++ env3.stderr.exp env3.vgtest try3.stderr.exp try3.vgtest \ ++ env4.stderr.exp env4.vgtest try4.stderr.exp try4.vgtest \ ++ env5.stderr.exp env5.vgtest \ ++ env6.stderr.exp env6.vgtest \ ++ trytry.stderr.exp trytry.vgtest \ ++ trytry2.stderr.exp trytry2.vgtest \ ++ trytry3.stderr.exp trytry3.vgtest \ + exec-sigmask.vgtest exec-sigmask.stdout.exp \ + exec-sigmask.stdout.exp2 exec-sigmask.stdout.exp3 \ + exec-sigmask.stdout.exp-solaris exec-sigmask.stderr.exp \ +@@ -253,6 +263,10 @@ EXTRA_DIST = \ + threadederrno.vgtest \ + timer_delete.vgtest timer_delete.stderr.exp \ + timestamp.stderr.exp timestamp.vgtest \ ++ timestamp_env.stderr.exp timestamp_env.vgtest \ ++ timestamp_env21.stderr.exp timestamp_env21.vgtest \ ++ timestamp_env22.stderr.exp timestamp_env22.vgtest \ ++ timestamp_envoverride.stderr.exp timestamp_envoverride.vgtest \ + tls.vgtest tls.stderr.exp tls.stdout.exp \ + track-fds-exec-children.vgtest track-fds-exec-children.stderr.exp \ + unit_debuglog.stderr.exp unit_debuglog.vgtest \ +diff --git a/none/tests/cmdline1.stdout.exp b/none/tests/cmdline1.stdout.exp +index 5d3ea0569..3bd3d1afc 100644 +--- a/none/tests/cmdline1.stdout.exp ++++ b/none/tests/cmdline1.stdout.exp +@@ -169,7 +169,7 @@ usage: valgrind [options] prog-and-args + user options for Nulgrind: + (none) + +- Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, ./.valgrindrc ++ Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, $VALGRIND_TRY_OPTS, ./.valgrindrc + + Nulgrind is Copyright (C) 2000, and GNU GPL'd, by Nicholas Nethercote et al. + Valgrind is Copyright (C) 2000, and GNU GPL'd, by Julian Seward et al. +diff --git a/none/tests/cmdline2.stdout.exp b/none/tests/cmdline2.stdout.exp +index 618c43acb..0ca1ddb34 100644 +--- a/none/tests/cmdline2.stdout.exp ++++ b/none/tests/cmdline2.stdout.exp +@@ -201,6 +201,7 @@ usage: valgrind [options] prog-and-args + --progress-interval= report progress every + CPU seconds [0, meaning disabled] + --command-line-only=no|yes only use command line options [no] ++ --try skip next option if option is unsupported + + Vex options for all Valgrind tools: + --vex-iropt-verbosity=<0..9> [0] +@@ -245,7 +246,7 @@ usage: valgrind [options] prog-and-args + debugging options for Nulgrind: + (none) + +- Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, ./.valgrindrc ++ Extra options read from ~/.valgrindrc, $VALGRIND_OPTS, $VALGRIND_TRY_OPTS, ./.valgrindrc + + Nulgrind is Copyright (C) 2000, and GNU GPL'd, by Nicholas Nethercote et al. + Valgrind is Copyright (C) 2000, and GNU GPL'd, by Julian Seward et al. +diff --git a/none/tests/env1.stderr.exp b/none/tests/env1.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/none/tests/env1.vgtest b/none/tests/env1.vgtest +new file mode 100644 +index 000000000..10925d78d +--- /dev/null ++++ b/none/tests/env1.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS=--bad-bad-option=yes ++vgopts: -q --command-line-only=no ++prog: ../../tests/true +diff --git a/none/tests/env2.stderr.exp b/none/tests/env2.stderr.exp +new file mode 100644 +index 000000000..139597f9c +--- /dev/null ++++ b/none/tests/env2.stderr.exp +@@ -0,0 +1,2 @@ ++ ++ +diff --git a/none/tests/env2.vgtest b/none/tests/env2.vgtest +new file mode 100644 +index 000000000..102d99e67 +--- /dev/null ++++ b/none/tests/env2.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS=--trace-children=no ++vgopts: --command-line-only=no ++prog: ../../tests/true +diff --git a/none/tests/env3.stderr.exp b/none/tests/env3.stderr.exp +new file mode 100644 +index 000000000..139597f9c +--- /dev/null ++++ b/none/tests/env3.stderr.exp +@@ -0,0 +1,2 @@ ++ ++ +diff --git a/none/tests/env3.vgtest b/none/tests/env3.vgtest +new file mode 100644 +index 000000000..9a43a3ebd +--- /dev/null ++++ b/none/tests/env3.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS=--trace-children=yes ++vgopts: --command-line-only=no ++prog: ../../tests/true +diff --git a/none/tests/env4.stderr.exp b/none/tests/env4.stderr.exp +new file mode 100644 +index 000000000..fb3624035 +--- /dev/null ++++ b/none/tests/env4.stderr.exp +@@ -0,0 +1,3 @@ ++valgrind: Bad option: --trace-children=1 ++valgrind: Invalid boolean value '1' (should be 'yes' or 'no') ++valgrind: Use --help for more information or consult the user manual. +diff --git a/none/tests/env4.vgtest b/none/tests/env4.vgtest +new file mode 100644 +index 000000000..7794bd74b +--- /dev/null ++++ b/none/tests/env4.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS=--trace-children=1 ++vgopts: --command-line-only=no ++prog: ../../tests/true +diff --git a/none/tests/env5.stderr.exp b/none/tests/env5.stderr.exp +new file mode 100644 +index 000000000..139597f9c +--- /dev/null ++++ b/none/tests/env5.stderr.exp +@@ -0,0 +1,2 @@ ++ ++ +diff --git a/none/tests/env5.vgtest b/none/tests/env5.vgtest +new file mode 100644 +index 000000000..5e2ce8a41 +--- /dev/null ++++ b/none/tests/env5.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS=--trace-children=1 ++vgopts: --command-line-only=yes ++prog: ../../tests/true +diff --git a/none/tests/env6.stderr.exp b/none/tests/env6.stderr.exp +new file mode 100644 +index 000000000..59c75a7f5 +--- /dev/null ++++ b/none/tests/env6.stderr.exp +@@ -0,0 +1,12 @@ ++ --try ++ --gen-suppressions=no ++ --try ++ --trace-children=yes ++ --try ++ -q ++ --command-line-only=yes ++ --memcheck:leak-check=no ++ --tool=none ++ --command-line-only=no ++ --verbose ++ --verbose +diff --git a/none/tests/env6.vgtest b/none/tests/env6.vgtest +new file mode 100644 +index 000000000..d45479d9f +--- /dev/null ++++ b/none/tests/env6.vgtest +@@ -0,0 +1,4 @@ ++env: VALGRIND_TRY_OPTS='--gen-suppressions=no --trace-children=yes -q' ++vgopts: --command-line-only=no --verbose --verbose ++prog: ../../tests/true ++stderr_filter: filter_optlist +diff --git a/none/tests/filter_optlist b/none/tests/filter_optlist +new file mode 100755 +index 000000000..39639a198 +--- /dev/null ++++ b/none/tests/filter_optlist +@@ -0,0 +1,11 @@ ++#! /bin/sh ++ ++dir=`dirname $0` ++ ++$dir/filter_stderr | ++awk ' ++ BEGIN { printing = 0 } ++ /^Valgrind options:/ { printing = 1; next } ++ /^ / { if (printing) print; next } ++ { printing = 0 } ++' +diff --git a/none/tests/timestamp_env.stderr.exp b/none/tests/timestamp_env.stderr.exp +new file mode 100644 +index 000000000..00a5083ae +--- /dev/null ++++ b/none/tests/timestamp_env.stderr.exp +@@ -0,0 +1,2 @@ ++00:00:00:XX:YYY ++00:00:00:XX:YYY +diff --git a/none/tests/timestamp_env.vgtest b/none/tests/timestamp_env.vgtest +new file mode 100644 +index 000000000..fe5b20e3b +--- /dev/null ++++ b/none/tests/timestamp_env.vgtest +@@ -0,0 +1,4 @@ ++env: VALGRIND_TRY_OPTS=--time-stamp=yes ++vgopts: --command-line-only=no ++prog: timestamp ++stderr_filter: filter_timestamp +diff --git a/none/tests/timestamp_env21.stderr.exp b/none/tests/timestamp_env21.stderr.exp +new file mode 100644 +index 000000000..00a5083ae +--- /dev/null ++++ b/none/tests/timestamp_env21.stderr.exp +@@ -0,0 +1,2 @@ ++00:00:00:XX:YYY ++00:00:00:XX:YYY +diff --git a/none/tests/timestamp_env21.vgtest b/none/tests/timestamp_env21.vgtest +new file mode 100644 +index 000000000..aa6e76688 +--- /dev/null ++++ b/none/tests/timestamp_env21.vgtest +@@ -0,0 +1,4 @@ ++env: VALGRIND_TRY_OPTS='--time-stamp=yes --trace-children=yes' ++vgopts: --command-line-only=no ++prog: timestamp ++stderr_filter: filter_timestamp +diff --git a/none/tests/timestamp_env22.stderr.exp b/none/tests/timestamp_env22.stderr.exp +new file mode 100644 +index 000000000..00a5083ae +--- /dev/null ++++ b/none/tests/timestamp_env22.stderr.exp +@@ -0,0 +1,2 @@ ++00:00:00:XX:YYY ++00:00:00:XX:YYY +diff --git a/none/tests/timestamp_env22.vgtest b/none/tests/timestamp_env22.vgtest +new file mode 100644 +index 000000000..cb628ac8d +--- /dev/null ++++ b/none/tests/timestamp_env22.vgtest +@@ -0,0 +1,4 @@ ++env: VALGRIND_TRY_OPTS='--show-below-main=no --time-stamp=yes' ++vgopts: --command-line-only=no ++prog: timestamp ++stderr_filter: filter_timestamp +diff --git a/none/tests/timestamp_envoverride.stderr.exp b/none/tests/timestamp_envoverride.stderr.exp +new file mode 100644 +index 000000000..00a5083ae +--- /dev/null ++++ b/none/tests/timestamp_envoverride.stderr.exp +@@ -0,0 +1,2 @@ ++00:00:00:XX:YYY ++00:00:00:XX:YYY +diff --git a/none/tests/timestamp_envoverride.vgtest b/none/tests/timestamp_envoverride.vgtest +new file mode 100644 +index 000000000..c77b52762 +--- /dev/null ++++ b/none/tests/timestamp_envoverride.vgtest +@@ -0,0 +1,4 @@ ++env: VALGRIND_TRY_OPTS=--time-stamp=no ++vgopts: --time-stamp=yes --command-line-only=no ++prog: timestamp ++stderr_filter: filter_timestamp +diff --git a/none/tests/try1.stderr.exp b/none/tests/try1.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/none/tests/try1.vgtest b/none/tests/try1.vgtest +new file mode 100644 +index 000000000..d00f79dfb +--- /dev/null ++++ b/none/tests/try1.vgtest +@@ -0,0 +1,2 @@ ++vgopts: -q --try --bad-bad-option=yes ++prog: ../../tests/true +diff --git a/none/tests/try2.stderr.exp b/none/tests/try2.stderr.exp +new file mode 100644 +index 000000000..139597f9c +--- /dev/null ++++ b/none/tests/try2.stderr.exp +@@ -0,0 +1,2 @@ ++ ++ +diff --git a/none/tests/try2.vgtest b/none/tests/try2.vgtest +new file mode 100644 +index 000000000..ce763273c +--- /dev/null ++++ b/none/tests/try2.vgtest +@@ -0,0 +1,2 @@ ++vgopts: --try --trace-children=no ++prog: ../../tests/true +diff --git a/none/tests/try3.stderr.exp b/none/tests/try3.stderr.exp +new file mode 100644 +index 000000000..139597f9c +--- /dev/null ++++ b/none/tests/try3.stderr.exp +@@ -0,0 +1,2 @@ ++ ++ +diff --git a/none/tests/try3.vgtest b/none/tests/try3.vgtest +new file mode 100644 +index 000000000..ce763273c +--- /dev/null ++++ b/none/tests/try3.vgtest +@@ -0,0 +1,2 @@ ++vgopts: --try --trace-children=no ++prog: ../../tests/true +diff --git a/none/tests/try4.stderr.exp b/none/tests/try4.stderr.exp +new file mode 100644 +index 000000000..fb3624035 +--- /dev/null ++++ b/none/tests/try4.stderr.exp +@@ -0,0 +1,3 @@ ++valgrind: Bad option: --trace-children=1 ++valgrind: Invalid boolean value '1' (should be 'yes' or 'no') ++valgrind: Use --help for more information or consult the user manual. +diff --git a/none/tests/try4.vgtest b/none/tests/try4.vgtest +new file mode 100644 +index 000000000..21bb392e9 +--- /dev/null ++++ b/none/tests/try4.vgtest +@@ -0,0 +1,2 @@ ++vgopts: --try --trace-children=1 ++prog: ../../tests/true +diff --git a/none/tests/trytry.stderr.exp b/none/tests/trytry.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/none/tests/trytry.vgtest b/none/tests/trytry.vgtest +new file mode 100644 +index 000000000..b638148ed +--- /dev/null ++++ b/none/tests/trytry.vgtest +@@ -0,0 +1,2 @@ ++vgopts: -q --try --try --bad-bad-option ++prog: ../../tests/true +diff --git a/none/tests/trytry2.stderr.exp b/none/tests/trytry2.stderr.exp +new file mode 100644 +index 000000000..879e12a28 +--- /dev/null ++++ b/none/tests/trytry2.stderr.exp +@@ -0,0 +1,2 @@ ++valgrind: Unknown option: --bad-bad-option ++valgrind: Use --help for more information or consult the user manual. +diff --git a/none/tests/trytry2.vgtest b/none/tests/trytry2.vgtest +new file mode 100644 +index 000000000..cb5335456 +--- /dev/null ++++ b/none/tests/trytry2.vgtest +@@ -0,0 +1,2 @@ ++vgopts: -q --try --try --bad-bad-option --bad-bad-option ++prog: ../../tests/true +diff --git a/none/tests/trytry3.stderr.exp b/none/tests/trytry3.stderr.exp +new file mode 100644 +index 000000000..4dac4a198 +--- /dev/null ++++ b/none/tests/trytry3.stderr.exp +@@ -0,0 +1,14 @@ ++ --command-line-only=yes ++ --memcheck:leak-check=no ++ --tool=none ++ --try ++ --gen-suppressions=no ++ --try ++ --trace-children=yes ++ --try ++ -q ++ --try ++ --try ++ --bad-bad-option ++ --verbose ++ --verbose +diff --git a/none/tests/trytry3.vgtest b/none/tests/trytry3.vgtest +new file mode 100644 +index 000000000..b065fd0e9 +--- /dev/null ++++ b/none/tests/trytry3.vgtest +@@ -0,0 +1,3 @@ ++vgopts: --try --gen-suppressions=no --try --trace-children=yes --try -q --try --try --bad-bad-option --verbose --verbose ++prog: ../../tests/true ++stderr_filter: filter_optlist diff --git a/ubuntu-latest/valgrind-varlat-patch-20250805.txt b/ubuntu-latest/valgrind-varlat-patch-20250805.txt new file mode 100644 index 0000000..de4021f --- /dev/null +++ b/ubuntu-latest/valgrind-varlat-patch-20250805.txt @@ -0,0 +1,909 @@ +diff --git a/.gitignore b/.gitignore +index e48a2ab0e..812e8f11f 100644 +--- a/.gitignore ++++ b/.gitignore +@@ -1042,6 +1042,8 @@ + /memcheck/tests/varinfo5so.so + /memcheck/tests/varinfo6 + /memcheck/tests/varinforestrict ++/memcheck/tests/varlat ++/memcheck/tests/varlat2 + /memcheck/tests/vcpu_bz2 + /memcheck/tests/vcpu_fbench + /memcheck/tests/vcpu_fnfns +diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c +index a708b3f85..8d163cd90 100644 +--- a/memcheck/mc_errors.c ++++ b/memcheck/mc_errors.c +@@ -94,11 +94,14 @@ struct _MC_Error { + // Use of an undefined value: + // - as a pointer in a load or store + // - as a jump target ++ // - (VARLAT mode) as an operand in a variable-latency instruction + struct { + SizeT szB; // size of value in bytes + // Origin info + UInt otag; // origin tag + ExeContext* origin_ec; // filled in later ++ // VARLAT mode ++ Bool isLatency; // if issue is variable-latency instruction + } Value; + + // Use of an undefined value in a conditional branch or move. +@@ -489,8 +492,13 @@ void MC_(pp_Error) ( const Error* err ) + MC_(any_value_errors) = True; + if (xml) { + emit( " UninitValue\n" ); +- emit( " Use of uninitialised value of size %lu\n", +- extra->Err.Value.szB ); ++ if (extra->Err.Value.isLatency) ++ emit( " Variable-latency instruction operand" ++ " of size %lu is secret/uninitialised\n", ++ extra->Err.Value.szB ); ++ else ++ emit( " Use of uninitialised value of size %lu\n", ++ extra->Err.Value.szB ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (extra->Err.Value.origin_ec) + mc_pp_origin( extra->Err.Value.origin_ec, +@@ -498,8 +506,13 @@ void MC_(pp_Error) ( const Error* err ) + } else { + /* Could also show extra->Err.Cond.otag if debugging origin + tracking */ +- emit( "Use of uninitialised value of size %lu\n", +- extra->Err.Value.szB ); ++ if (extra->Err.Value.isLatency) ++ emit( "Variable-latency instruction operand" ++ " of size %lu is secret/uninitialised\n", ++ extra->Err.Value.szB ); ++ else ++ emit( "Use of uninitialised value of size %lu\n", ++ extra->Err.Value.szB ); + VG_(pp_ExeContext)( VG_(get_error_where)(err) ); + if (extra->Err.Value.origin_ec) + mc_pp_origin( extra->Err.Value.origin_ec, +@@ -926,6 +939,20 @@ void MC_(record_value_error) ( ThreadId tid, Int szB, UInt otag ) + extra.Err.Value.szB = szB; + extra.Err.Value.otag = otag; + extra.Err.Value.origin_ec = NULL; /* Filled in later */ ++ extra.Err.Value.isLatency = False; ++ VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra ); ++} ++ ++void MC_(record_varlat_value_error) ( ThreadId tid, Int szB, UInt otag ) ++{ ++ MC_Error extra; ++ tl_assert( MC_(clo_mc_level) >= 2 ); ++ if (otag > 0) ++ tl_assert( MC_(clo_mc_level) == 3 ); ++ extra.Err.Value.szB = szB; ++ extra.Err.Value.otag = otag; ++ extra.Err.Value.origin_ec = NULL; /* Filled in later */ ++ extra.Err.Value.isLatency = True; + VG_(maybe_record_error)( tid, Err_Value, /*addr*/0, /*s*/NULL, &extra ); + } + +diff --git a/memcheck/mc_include.h b/memcheck/mc_include.h +index acc595a74..2578cccb0 100644 +--- a/memcheck/mc_include.h ++++ b/memcheck/mc_include.h +@@ -525,6 +525,10 @@ void MC_(pp_LossRecord)(UInt n_this_record, UInt n_total_records, + rerun with --track-origins=yes might help. */ + extern Bool MC_(any_value_errors); + ++/* Are we running in VARLAT mode, where variable-latency operations ++ on uninitialised (or secret) values are considered as errors ? */ ++extern Bool MC_(clo_variable_latency_errors); ++ + /* Standard functions for error and suppressions as required by the + core/tool iface */ + Bool MC_(eq_Error) ( VgRes res, const Error* e1, const Error* e2 ); +@@ -552,6 +556,7 @@ void MC_(record_address_error) ( ThreadId tid, Addr a, Int szB, + Bool isWrite ); + void MC_(record_cond_error) ( ThreadId tid, UInt otag ); + void MC_(record_value_error) ( ThreadId tid, Int szB, UInt otag ); ++void MC_(record_varlat_value_error) ( ThreadId tid, Int szB, UInt otag ); + void MC_(record_jump_error) ( ThreadId tid, Addr a ); + + void MC_(record_free_error) ( ThreadId tid, Addr a ); +@@ -773,6 +778,10 @@ VG_REGPARM(1) void MC_(helperc_value_check8_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check4_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check1_fail_w_o) ( UWord ); + VG_REGPARM(1) void MC_(helperc_value_check0_fail_w_o) ( UWord ); ++VG_REGPARM(2) void MC_(helperc_value_checkN_varlat_fail_w_o) ( HWord, UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check8_varlat_fail_w_o) ( UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check4_varlat_fail_w_o) ( UWord ); ++VG_REGPARM(1) void MC_(helperc_value_check1_varlat_fail_w_o) ( UWord ); + + /* And call these ones instead to report an uninitialised value error + but with no origin available. */ +@@ -781,6 +790,10 @@ VG_REGPARM(0) void MC_(helperc_value_check8_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check4_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check1_fail_no_o) ( void ); + VG_REGPARM(0) void MC_(helperc_value_check0_fail_no_o) ( void ); ++VG_REGPARM(1) void MC_(helperc_value_checkN_varlat_fail_no_o) ( HWord ); ++VG_REGPARM(0) void MC_(helperc_value_check8_varlat_fail_no_o) ( void ); ++VG_REGPARM(0) void MC_(helperc_value_check4_varlat_fail_no_o) ( void ); ++VG_REGPARM(0) void MC_(helperc_value_check1_varlat_fail_no_o) ( void ); + + /* V-bits load/store helpers */ + VG_REGPARM(1) void MC_(helperc_STOREV64be) ( Addr, ULong ); +diff --git a/memcheck/mc_main.c b/memcheck/mc_main.c +index 626d481d2..49f835929 100644 +--- a/memcheck/mc_main.c ++++ b/memcheck/mc_main.c +@@ -5770,6 +5770,27 @@ void MC_(helperc_value_checkN_fail_w_o) ( HWord sz, UWord origin ) { + MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, (UInt)origin ); + } + ++VG_REGPARM(1) ++void MC_(helperc_value_check1_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 1, (UInt)origin ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_check4_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 4, (UInt)origin ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_check8_varlat_fail_w_o) ( UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 8, (UInt)origin ); ++} ++ ++VG_REGPARM(2) ++void MC_(helperc_value_checkN_varlat_fail_w_o) ( HWord sz, UWord origin ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), (Int)sz, ++ (UInt)origin ); ++} ++ + /* ... and these when an origin isn't available. */ + + VG_REGPARM(0) +@@ -5797,6 +5818,27 @@ void MC_(helperc_value_checkN_fail_no_o) ( HWord sz ) { + MC_(record_value_error) ( VG_(get_running_tid)(), (Int)sz, 0/*origin*/ ); + } + ++VG_REGPARM(0) ++void MC_(helperc_value_check1_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 1, 0/*origin*/ ); ++} ++ ++VG_REGPARM(0) ++void MC_(helperc_value_check4_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 4, 0/*origin*/ ); ++} ++ ++VG_REGPARM(0) ++void MC_(helperc_value_check8_varlat_fail_no_o) ( void ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), 8, 0/*origin*/ ); ++} ++ ++VG_REGPARM(1) ++void MC_(helperc_value_checkN_varlat_fail_no_o) ( HWord sz ) { ++ MC_(record_varlat_value_error) ( VG_(get_running_tid)(), (Int)sz, ++ 0/*origin*/ ); ++} ++ + + /*------------------------------------------------------------*/ + /*--- Metadata get/set functions, for client requests. ---*/ +@@ -6064,6 +6106,7 @@ UInt MC_(clo_leak_check_heuristics) = H2S(LchStdString) + | H2S( LchMultipleInheritance); + Bool MC_(clo_xtree_leak) = False; + const HChar* MC_(clo_xtree_leak_file) = "xtleak.kcg.%p"; ++Bool MC_(clo_variable_latency_errors) = False; + Bool MC_(clo_workaround_gcc296_bugs) = False; + Int MC_(clo_malloc_fill) = -1; + Int MC_(clo_free_fill) = -1; +@@ -6135,6 +6178,8 @@ static Bool mc_process_cmd_line_options(const HChar* arg) + else if VG_USET_CLOM(cloPD, arg, "--leak-check-heuristics", + MC_(parse_leak_heuristics_tokens), + MC_(clo_leak_check_heuristics)) {} ++ else if VG_BOOL_CLOM(cloPD, arg, "--variable-latency-errors", ++ MC_(clo_variable_latency_errors)) {} + else if (VG_BOOL_CLOM(cloPD, arg, "--show-reachable", tmp_show)) { + if (tmp_show) { + MC_(clo_show_leak_kinds) = MC_(all_Reachedness)(); +@@ -6313,6 +6358,7 @@ static void mc_print_usage(void) + " --xtree-leak=no|yes output leak result in xtree format? [no]\n" + " --xtree-leak-file= xtree leak report file [xtleak.kcg.%%p]\n" + " --undef-value-errors=no|yes check for undefined value errors [yes]\n" ++" --variable-latency-errors=no|yes check for variable latency errors [no]\n" + " --track-origins=no|yes show origins of undefined values? [no]\n" + " --partial-loads-ok=no|yes too hard to explain here; see manual [yes]\n" + " --expensive-definedness-checks=no|auto|yes\n" +diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c +index b4e499cc0..2d93f2d18 100644 +--- a/memcheck/mc_translate.c ++++ b/memcheck/mc_translate.c +@@ -1593,8 +1593,13 @@ static void setHelperAnns ( MCEnv* mce, IRDirty* di ) { + + This routine does not generate code to check the definedness of + |guard|. The caller is assumed to have taken care of that already. ++ ++ If varlatLatency is set, then this function emits complaints for ++ VARLAT mode rather than for the usual branches etc. + */ +-static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) ++static void complainIfUndefinedOrVariableLatency ( MCEnv* mce, IRAtom* atom, ++ IRExpr *guard, ++ Bool varlatLatency ) + { + IRAtom* vatom; + IRType ty; +@@ -1664,39 +1669,69 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + break; + case 1: + if (origin) { +- fn = &MC_(helperc_value_check1_fail_w_o); +- nm = "MC_(helperc_value_check1_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check1_fail_w_o); ++ nm = "MC_(helperc_value_check1_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check1_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check1_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check1_fail_no_o); +- nm = "MC_(helperc_value_check1_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check1_fail_no_o); ++ nm = "MC_(helperc_value_check1_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check1_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check1_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } + break; + case 4: + if (origin) { +- fn = &MC_(helperc_value_check4_fail_w_o); +- nm = "MC_(helperc_value_check4_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check4_fail_w_o); ++ nm = "MC_(helperc_value_check4_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check4_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check4_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check4_fail_no_o); +- nm = "MC_(helperc_value_check4_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check4_fail_no_o); ++ nm = "MC_(helperc_value_check4_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check4_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check4_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } + break; + case 8: + if (origin) { +- fn = &MC_(helperc_value_check8_fail_w_o); +- nm = "MC_(helperc_value_check8_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check8_fail_w_o); ++ nm = "MC_(helperc_value_check8_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_check8_varlat_fail_w_o); ++ nm = "MC_(helperc_value_check8_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_1(origin); + nargs = 1; + } else { +- fn = &MC_(helperc_value_check8_fail_no_o); +- nm = "MC_(helperc_value_check8_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_check8_fail_no_o); ++ nm = "MC_(helperc_value_check8_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_check8_varlat_fail_no_o); ++ nm = "MC_(helperc_value_check8_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_0(); + nargs = 0; + } +@@ -1704,13 +1739,23 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + case 2: + case 16: + if (origin) { +- fn = &MC_(helperc_value_checkN_fail_w_o); +- nm = "MC_(helperc_value_checkN_fail_w_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_checkN_fail_w_o); ++ nm = "MC_(helperc_value_checkN_fail_w_o)"; ++ } else { ++ fn = &MC_(helperc_value_checkN_varlat_fail_w_o); ++ nm = "MC_(helperc_value_checkN_varlat_fail_w_o)"; ++ } + args = mkIRExprVec_2( mkIRExpr_HWord( sz ), origin); + nargs = 2; + } else { +- fn = &MC_(helperc_value_checkN_fail_no_o); +- nm = "MC_(helperc_value_checkN_fail_no_o)"; ++ if (!varlatLatency) { ++ fn = &MC_(helperc_value_checkN_fail_no_o); ++ nm = "MC_(helperc_value_checkN_fail_no_o)"; ++ } else { ++ fn = &MC_(helperc_value_checkN_varlat_fail_no_o); ++ nm = "MC_(helperc_value_checkN_varlat_fail_no_o)"; ++ } + args = mkIRExprVec_1( mkIRExpr_HWord( sz ) ); + nargs = 1; + } +@@ -1771,6 +1816,17 @@ static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) + } + } + ++static void complainIfUndefined ( MCEnv* mce, IRAtom* atom, IRExpr *guard ) ++{ ++ complainIfUndefinedOrVariableLatency(mce, atom, guard, False); ++} ++ ++static void complainIfVariableLatency ( MCEnv* mce, IRAtom* atom ) ++{ ++ if (MC_(clo_variable_latency_errors)) ++ complainIfUndefinedOrVariableLatency(mce, atom, NULL, True); ++} ++ + + /*------------------------------------------------------------*/ + /*--- Shadowing PUTs/GETs, and indexed variants thereof ---*/ +@@ -3511,14 +3567,19 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + case Iop_Yl2xF64: + case Iop_Yl2xp1F64: + case Iop_AtanF64: +- case Iop_PRemF64: +- case Iop_PRem1F64: + case Iop_QuantizeD64: + /* I32(rm) x F64/D64 x F64/D64 -> F64/D64 */ + return mkLazy3(mce, Ity_I64, vatom1, vatom2, vatom3); ++ case Iop_PRemF64: ++ case Iop_PRem1F64: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return mkLazy3(mce, Ity_I64, vatom1, vatom2, vatom3); + case Iop_PRemC3210F64: + case Iop_PRem1C3210F64: + /* I32(rm) x F64 x F64 -> I32 */ ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return mkLazy3(mce, Ity_I32, vatom1, vatom2, vatom3); + case Iop_AddF32: + case Iop_SubF32: +@@ -3572,21 +3633,33 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + case Iop_Add64Fx2: + case Iop_Sub64Fx2: + case Iop_Mul64Fx2: +- case Iop_Div64Fx2: + case Iop_Scale2_64Fx2: + return binary64Fx2_w_rm(mce, vatom1, vatom2, vatom3); + ++ case Iop_Div64Fx2: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return binary64Fx2_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Add32Fx4: + case Iop_Sub32Fx4: + case Iop_Mul32Fx4: +- case Iop_Div32Fx4: + case Iop_Scale2_32Fx4: +- return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ ++ case Iop_Div32Fx4: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); ++ return binary32Fx4_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_Add64Fx4: + case Iop_Sub64Fx4: + case Iop_Mul64Fx4: ++ return binary64Fx4_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Div64Fx4: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return binary64Fx4_w_rm(mce, vatom1, vatom2, vatom3); + + /* TODO: remaining versions of 16x4 FP ops when more of the half-precision +@@ -3594,12 +3667,16 @@ IRAtom* expr2vbits_Triop ( MCEnv* mce, + */ + case Iop_Add16Fx8: + case Iop_Sub16Fx8: +- return binary16Fx8_w_rm(mce, vatom1, vatom2, vatom3); ++ return binary16Fx8_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_Add32Fx8: + case Iop_Sub32Fx8: + case Iop_Mul32Fx8: ++ return binary32Fx8_w_rm(mce, vatom1, vatom2, vatom3); ++ + case Iop_Div32Fx8: ++ complainIfVariableLatency(mce, atom2); ++ complainIfVariableLatency(mce, atom3); + return binary32Fx8_w_rm(mce, vatom1, vatom2, vatom3); + + case Iop_F32x4_2toQ16x8: +@@ -3913,11 +3990,15 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_I32StoF32x4: + case Iop_F32toI32Sx4: ++ return unary16Fx8_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt16Fx8: ++ complainIfVariableLatency(mce, atom2); + return unary16Fx8_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt32Fx4: ++ complainIfVariableLatency(mce, atom2); + return unary32Fx4_w_rm(mce, vatom1, vatom2); + case Iop_Sqrt64Fx2: ++ complainIfVariableLatency(mce, atom2); + return unary64Fx2_w_rm(mce, vatom1, vatom2); + + case Iop_ShrN8x16: +@@ -4153,6 +4234,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_ModU128: + case Iop_ModS128: + /* I128 x I128 -> I128 */ ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_V128, vatom1, vatom2); + + case Iop_QNarrowBin64Sto32Sx4: +@@ -4184,7 +4267,6 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Mul64F0x2: + case Iop_Min64F0x2: + case Iop_Max64F0x2: +- case Iop_Div64F0x2: + case Iop_CmpLT64F0x2: + case Iop_CmpLE64F0x2: + case Iop_CmpEQ64F0x2: +@@ -4192,6 +4274,11 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Add64F0x2: + return binary64F0x2(mce, vatom1, vatom2); + ++ case Iop_Div64F0x2: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); ++ return binary64F0x2(mce, vatom1, vatom2); ++ + case Iop_Min32Fx4: + case Iop_Max32Fx4: + case Iop_CmpLT32Fx4: +@@ -4220,7 +4307,6 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Mul32F0x4: + case Iop_Min32F0x4: + case Iop_Max32F0x4: +- case Iop_Div32F0x4: + case Iop_CmpLT32F0x4: + case Iop_CmpLE32F0x4: + case Iop_CmpEQ32F0x4: +@@ -4228,6 +4314,11 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_Add32F0x4: + return binary32F0x4(mce, vatom1, vatom2); + ++ case Iop_Div32F0x4: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); ++ return binary32F0x4(mce, vatom1, vatom2); ++ + case Iop_QShlNsatSU8x16: + case Iop_QShlNsatUU8x16: + case Iop_QShlNsatSS8x16: +@@ -4531,11 +4622,14 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + case Iop_CosF64: + case Iop_TanF64: + case Iop_2xm1F64: +- case Iop_SqrtF64: + case Iop_RecpExpF64: + /* I32(rm) x I64/F64 -> I64/F64 */ + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + ++ case Iop_SqrtF64: ++ complainIfVariableLatency(mce, atom2); ++ return mkLazy2(mce, Ity_I64, vatom1, vatom2); ++ + case Iop_ShlD64: + case Iop_ShrD64: + case Iop_RoundD64toInt: +@@ -4589,16 +4683,21 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_SqrtF16: + /* I32(rm) x F16 -> F16 */ ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I16, vatom1, vatom2); + + case Iop_RoundF32toInt: +- case Iop_SqrtF32: + case Iop_RecpExpF32: + /* I32(rm) x I32/F32 -> I32/F32 */ + return mkLazy2(mce, Ity_I32, vatom1, vatom2); + ++ case Iop_SqrtF32: ++ complainIfVariableLatency(mce, atom2); ++ return mkLazy2(mce, Ity_I32, vatom1, vatom2); ++ + case Iop_SqrtF128: + /* I32(rm) x F128 -> F128 */ ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I128, vatom1, vatom2); + + case Iop_I32StoF32: +@@ -4687,10 +4786,14 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU64to32: + case Iop_DivModS64to32: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + + case Iop_DivModU128to64: + case Iop_DivModS128to64: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I128, vatom1, vatom2); + + case Iop_8HLto16: +@@ -4702,6 +4805,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU64to64: + case Iop_DivModS64to64: { ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + IRAtom* vTmp64 = mkLazy2(mce, Ity_I64, vatom1, vatom2); + return assignNew('V', mce, Ity_I128, + binop(Iop_64HLto128, vTmp64, vTmp64)); +@@ -4717,6 +4822,8 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + + case Iop_DivModU32to32: + case Iop_DivModS32to32: { ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + IRAtom* vTmp32 = mkLazy2(mce, Ity_I32, vatom1, vatom2); + return assignNew('V', mce, Ity_I64, + binop(Iop_32HLto64, vTmp32, vTmp32)); +@@ -4746,18 +4853,24 @@ IRAtom* expr2vbits_Binop ( MCEnv* mce, + } + + case Iop_Sad8Ux4: /* maybe we could do better? ftm, do mkLazy2. */ ++ case Iop_QAdd32S: /* could probably do better */ ++ case Iop_QSub32S: /* could probably do better */ ++ return mkLazy2(mce, Ity_I32, vatom1, vatom2); ++ + case Iop_DivS32: + case Iop_DivU32: + case Iop_DivU32E: + case Iop_DivS32E: +- case Iop_QAdd32S: /* could probably do better */ +- case Iop_QSub32S: /* could probably do better */ ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I32, vatom1, vatom2); + + case Iop_DivS64: + case Iop_DivU64: + case Iop_DivS64E: + case Iop_DivU64E: ++ complainIfVariableLatency(mce, atom1); ++ complainIfVariableLatency(mce, atom2); + return mkLazy2(mce, Ity_I64, vatom1, vatom2); + + case Iop_Add32: +@@ -5163,14 +5276,19 @@ IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom ) + return unary64Fx2(mce, vatom); + + case Iop_Sqrt64F0x2: ++ complainIfVariableLatency(mce, atom); + return unary64F0x2(mce, vatom); + + case Iop_Sqrt32Fx8: ++ complainIfVariableLatency(mce, atom); ++ return unary32Fx8(mce, vatom); ++ + case Iop_RSqrtEst32Fx8: + case Iop_RecipEst32Fx8: + return unary32Fx8(mce, vatom); + + case Iop_Sqrt64Fx4: ++ complainIfVariableLatency(mce, atom); + return unary64Fx4(mce, vatom); + + case Iop_RecipEst32Fx4: +@@ -5200,6 +5318,9 @@ IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom ) + return unary32Fx2(mce, vatom); + + case Iop_Sqrt32F0x4: ++ complainIfVariableLatency(mce, atom); ++ return unary32F0x4(mce, vatom); ++ + case Iop_RSqrtEst32F0x4: + case Iop_RecipEst32F0x4: + return unary32F0x4(mce, vatom); +@@ -8044,19 +8165,25 @@ Bool check_or_add ( Pairs* tidyingEnv, IRExpr* guard, void* entry ) + static Bool is_helperc_value_checkN_fail ( const HChar* name ) + { + /* This is expensive because it happens a lot. We are checking to +- see whether |name| is one of the following 8 strings: ++ see whether |name| is one of the following 14 strings: + + MC_(helperc_value_check8_fail_no_o) + MC_(helperc_value_check4_fail_no_o) + MC_(helperc_value_check0_fail_no_o) + MC_(helperc_value_check1_fail_no_o) + MC_(helperc_value_check8_fail_w_o) ++ MC_(helperc_value_check4_fail_w_o) + MC_(helperc_value_check0_fail_w_o) + MC_(helperc_value_check1_fail_w_o) +- MC_(helperc_value_check4_fail_w_o) ++ MC_(helperc_value_check8_varlat_fail_no_o) ++ MC_(helperc_value_check4_varlat_fail_no_o) ++ MC_(helperc_value_check1_varlat_fail_no_o) ++ MC_(helperc_value_check8_varlat_fail_w_o) ++ MC_(helperc_value_check4_varlat_fail_w_o) ++ MC_(helperc_value_check1_varlat_fail_w_o) + + To speed it up, check the common prefix just once, rather than +- all 8 times. ++ all 14 times. + */ + const HChar* prefix = "MC_(helperc_value_check"; + +@@ -8081,7 +8208,13 @@ static Bool is_helperc_value_checkN_fail ( const HChar* name ) + || 0==VG_(strcmp)(name, "8_fail_w_o)") + || 0==VG_(strcmp)(name, "4_fail_w_o)") + || 0==VG_(strcmp)(name, "0_fail_w_o)") +- || 0==VG_(strcmp)(name, "1_fail_w_o)"); ++ || 0==VG_(strcmp)(name, "1_fail_w_o)") ++ || 0==VG_(strcmp)(name, "8_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "4_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "1_varlat_fail_no_o)") ++ || 0==VG_(strcmp)(name, "8_varlat_fail_w_o)") ++ || 0==VG_(strcmp)(name, "4_varlat_fail_w_o)") ++ || 0==VG_(strcmp)(name, "1_varlat_fail_w_o)"); + } + + IRSB* MC_(final_tidy) ( IRSB* sb_in ) +@@ -8147,7 +8280,7 @@ void MC_(do_instrumentation_startup_checks)( void ) + # define CHECK(_expected, _string) \ + tl_assert((_expected) == is_helperc_value_checkN_fail(_string)) + +- /* It should identify these 8, and no others, as targets. */ ++ /* It should identify these 14, and no others, as targets. */ + CHECK(True, "MC_(helperc_value_check8_fail_no_o)"); + CHECK(True, "MC_(helperc_value_check4_fail_no_o)"); + CHECK(True, "MC_(helperc_value_check0_fail_no_o)"); +@@ -8156,6 +8289,12 @@ void MC_(do_instrumentation_startup_checks)( void ) + CHECK(True, "MC_(helperc_value_check0_fail_w_o)"); + CHECK(True, "MC_(helperc_value_check1_fail_w_o)"); + CHECK(True, "MC_(helperc_value_check4_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check8_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check4_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check1_varlat_fail_no_o)"); ++ CHECK(True, "MC_(helperc_value_check8_varlat_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check1_varlat_fail_w_o)"); ++ CHECK(True, "MC_(helperc_value_check4_varlat_fail_w_o)"); + + /* Ad-hoc selection of other strings gathered via a quick test. */ + CHECK(False, "amd64g_dirtyhelper_CPUID_avx2"); +diff --git a/memcheck/tests/Makefile.am b/memcheck/tests/Makefile.am +index 633c036c3..11f440b2a 100644 +--- a/memcheck/tests/Makefile.am ++++ b/memcheck/tests/Makefile.am +@@ -448,6 +448,14 @@ EXTRA_DIST = \ + varinfo6.vgtest varinfo6.stdout.exp varinfo6.stderr.exp \ + varinfo6.stderr.exp-ppc64 \ + varinforestrict.vgtest varinforestrict.stderr.exp \ ++ varlat.vgtest varlat.stderr.exp \ ++ varlat-env.vgtest varlat-env.stderr.exp \ ++ varlat-no.vgtest varlat-no.stderr.exp \ ++ varlat-yes.vgtest varlat-yes.stderr.exp \ ++ varlat2.vgtest varlat2.stderr.exp \ ++ varlat2-env.vgtest varlat2-env.stderr.exp \ ++ varlat2-no.vgtest varlat2-no.stderr.exp \ ++ varlat2-yes.vgtest varlat2-yes.stderr.exp \ + vcpu_bz2.stdout.exp vcpu_bz2.stderr.exp vcpu_bz2.vgtest \ + vcpu_fbench.stdout.exp vcpu_fbench.stderr.exp vcpu_fbench.vgtest \ + vcpu_fnfns.stdout.exp vcpu_fnfns.stdout.exp-glibc28-amd64 \ +@@ -563,6 +571,7 @@ check_PROGRAMS = \ + varinfo1 varinfo2 varinfo3 varinfo4 \ + varinfo5 varinfo5so.so varinfo6 \ + varinforestrict \ ++ varlat varlat2 \ + vcpu_fbench vcpu_fnfns \ + wcs \ + wcscat \ +@@ -881,6 +890,9 @@ else + endif + varinforestrict_CFLAGS = $(AM_CFLAGS) -O0 -g @FLAG_W_NO_MAYBE_UNINITIALIZED@ + ++varlat_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ ++varlat2_CFLAGS = $(AM_CFLAGS) @FLAG_W_NO_UNINITIALIZED@ ++ + # Build shared object for wrap7 + wrap7_SOURCES = wrap7.c + wrap7_DEPENDENCIES = wrap7so.so +diff --git a/memcheck/tests/varlat-env.stderr.exp b/memcheck/tests/varlat-env.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat-env.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat-env.vgtest b/memcheck/tests/varlat-env.vgtest +new file mode 100644 +index 000000000..1c0dffbb5 +--- /dev/null ++++ b/memcheck/tests/varlat-env.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS='--memcheck:variable-latency-errors=yes' ++prog: varlat ++vgopts: -q --command-line-only=no +diff --git a/memcheck/tests/varlat-no.stderr.exp b/memcheck/tests/varlat-no.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/memcheck/tests/varlat-no.vgtest b/memcheck/tests/varlat-no.vgtest +new file mode 100644 +index 000000000..ed5fe4495 +--- /dev/null ++++ b/memcheck/tests/varlat-no.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q +diff --git a/memcheck/tests/varlat-yes.stderr.exp b/memcheck/tests/varlat-yes.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat-yes.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat-yes.vgtest b/memcheck/tests/varlat-yes.vgtest +new file mode 100644 +index 000000000..57a4d9d8e +--- /dev/null ++++ b/memcheck/tests/varlat-yes.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q --variable-latency-errors=yes +diff --git a/memcheck/tests/varlat.c b/memcheck/tests/varlat.c +new file mode 100644 +index 000000000..98ae12dcb +--- /dev/null ++++ b/memcheck/tests/varlat.c +@@ -0,0 +1,16 @@ ++#include ++ ++volatile int storage; ++ ++void storage_init(char c) ++{ ++ storage = 100/(13|c); ++} ++ ++int main() ++{ ++ volatile char *x = malloc(1); ++ storage_init(x[0]); ++ free(x); ++ return 0; ++} +diff --git a/memcheck/tests/varlat.stderr.exp b/memcheck/tests/varlat.stderr.exp +new file mode 100644 +index 000000000..e69de29bb +diff --git a/memcheck/tests/varlat.vgtest b/memcheck/tests/varlat.vgtest +new file mode 100644 +index 000000000..6b55ac8f8 +--- /dev/null ++++ b/memcheck/tests/varlat.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat ++vgopts: -q --variable-latency-errors=no +diff --git a/memcheck/tests/varlat2-env.stderr.exp b/memcheck/tests/varlat2-env.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-env.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-env.vgtest b/memcheck/tests/varlat2-env.vgtest +new file mode 100644 +index 000000000..8ade43b2f +--- /dev/null ++++ b/memcheck/tests/varlat2-env.vgtest +@@ -0,0 +1,3 @@ ++env: VALGRIND_TRY_OPTS='--memcheck:variable-latency-errors=yes' ++prog: varlat2 ++vgopts: -q --command-line-only=no +diff --git a/memcheck/tests/varlat2-no.stderr.exp b/memcheck/tests/varlat2-no.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-no.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-no.vgtest b/memcheck/tests/varlat2-no.vgtest +new file mode 100644 +index 000000000..e608f987c +--- /dev/null ++++ b/memcheck/tests/varlat2-no.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q +diff --git a/memcheck/tests/varlat2-yes.stderr.exp b/memcheck/tests/varlat2-yes.stderr.exp +new file mode 100644 +index 000000000..5393cd2dc +--- /dev/null ++++ b/memcheck/tests/varlat2-yes.stderr.exp +@@ -0,0 +1,3 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ ... ++ +diff --git a/memcheck/tests/varlat2-yes.vgtest b/memcheck/tests/varlat2-yes.vgtest +new file mode 100644 +index 000000000..d4c908305 +--- /dev/null ++++ b/memcheck/tests/varlat2-yes.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q --variable-latency-errors=yes +diff --git a/memcheck/tests/varlat2.c b/memcheck/tests/varlat2.c +new file mode 100644 +index 000000000..7f4c9c1dd +--- /dev/null ++++ b/memcheck/tests/varlat2.c +@@ -0,0 +1,18 @@ ++#include ++#include "valgrind.h" ++ ++volatile int storage; ++ ++void storage_init(char c) ++{ ++ storage = 100/(13|c); ++} ++ ++int main() ++{ ++ volatile char *x = malloc(1); ++ VALGRIND_CLO_CHANGE("--variable-latency-errors=yes"); ++ storage_init(x[0]); ++ free(x); ++ return 0; ++} +diff --git a/memcheck/tests/varlat2.stderr.exp b/memcheck/tests/varlat2.stderr.exp +new file mode 100644 +index 000000000..1e7a51a5d +--- /dev/null ++++ b/memcheck/tests/varlat2.stderr.exp +@@ -0,0 +1,4 @@ ++Variable-latency instruction operand of size 4 is secret/uninitialised ++ at 0x........: storage_init (varlat2.c:8) ++ by 0x........: main (varlat2.c:15) ++ +diff --git a/memcheck/tests/varlat2.vgtest b/memcheck/tests/varlat2.vgtest +new file mode 100644 +index 000000000..4ef2fad30 +--- /dev/null ++++ b/memcheck/tests/varlat2.vgtest +@@ -0,0 +1,2 @@ ++prog: varlat2 ++vgopts: -q --variable-latency-errors=no diff --git a/ubuntu-latest/valgrind-varlat-sup-block.txt b/ubuntu-latest/valgrind-varlat-sup-block.txt new file mode 100644 index 0000000..465ae90 --- /dev/null +++ b/ubuntu-latest/valgrind-varlat-sup-block.txt @@ -0,0 +1,23 @@ +diff --git a/memcheck/mc_errors.c b/memcheck/mc_errors.c +index 8d163cd90..0e7eaab8f 100644 +--- a/memcheck/mc_errors.c ++++ b/memcheck/mc_errors.c +@@ -1913,6 +1913,18 @@ SizeT MC_(get_extra_suppression_info) ( const Error* err, + return VG_(snprintf) (buf, nBuf, "%s(%s)", + extra->Err.FishyValue.function_name, + extra->Err.FishyValue.argument_name); ++ ++ } else if (Err_Value == ekind) { ++ /* For variable-latency (VARLAT) errors, add an extra line ++ in the generated suppression template so users can see ++ that this undefined-value is a variable-latency operand. */ ++ MC_Error* extra = VG_(get_error_extra)(err); ++ if (extra && extra->Err.Value.isLatency) { ++ return VG_(snprintf) (buf, nBuf, "variable-latency: yes"); ++ } else { ++ buf[0] = '\0'; ++ return 0; ++ } + } else { + buf[0] = '\0'; + return 0;