diff --git a/.gitignore b/.gitignore index 08598edbf..ac05b679a 100644 --- a/.gitignore +++ b/.gitignore @@ -1037,6 +1037,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 abd5d6888..f29524d2a 100644 --- a/memcheck/mc_main.c +++ b/memcheck/mc_main.c @@ -37,6 +37,7 @@ #include "pub_tool_libcbase.h" #include "pub_tool_libcassert.h" #include "pub_tool_libcprint.h" +#include "pub_tool_libcproc.h" // for VG_(getenv) #include "pub_tool_machine.h" #include "pub_tool_mallocfree.h" #include "pub_tool_options.h" @@ -5770,6 +5771,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 +5819,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 +6107,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 +6179,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 +6359,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" @@ -6340,6 +6387,15 @@ static void mc_print_debug_usage(void) ); } +// VALGRIND_BESTEFFORT_* environment variables +// are set by programs that are hoping for the features +// but would like to proceed in any case, +// even with valgrind versions not having the features. +static void mc_besteffort_init(void) +{ + if (VG_(getenv)("VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS") != NULL) + MC_(clo_variable_latency_errors) = True; +} /*------------------------------------------------------------*/ /*--- Client blocks ---*/ @@ -8551,6 +8607,10 @@ static Bool mc_mark_unaddressable_for_watchpoint (PointKind kind, Bool insert, static void mc_pre_clo_init(void) { + // Handle best-effort environment variables early + // so that they can influence handling of everything else. + mc_besteffort_init(); + VG_(details_name) ("Memcheck"); VG_(details_version) (NULL); VG_(details_description) ("a memory error detector"); diff --git a/memcheck/mc_translate.c b/memcheck/mc_translate.c index 05e6d59af..4e3f83770 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 19ac76730..2012be681 100644 --- a/memcheck/tests/Makefile.am +++ b/memcheck/tests/Makefile.am @@ -437,6 +437,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 \ @@ -547,6 +555,7 @@ check_PROGRAMS = \ varinfo1 varinfo2 varinfo3 varinfo4 \ varinfo5 varinfo5so.so varinfo6 \ varinforestrict \ + varlat varlat2 \ vcpu_fbench vcpu_fnfns \ wcs \ xml1 \ @@ -855,6 +864,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..945670ac3 --- /dev/null +++ b/memcheck/tests/varlat-env.vgtest @@ -0,0 +1,3 @@ +prog: varlat +vgopts: -q +env: VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS=1 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..80fa2e688 --- /dev/null +++ b/memcheck/tests/varlat.c @@ -0,0 +1,16 @@ +#include + +volatile int storage; + +void storage_init(char c) +{ + storage = 100/(1|c); +} + +int main() +{ + 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..6fa74525c --- /dev/null +++ b/memcheck/tests/varlat2-env.vgtest @@ -0,0 +1,3 @@ +prog: varlat2 +vgopts: -q +env: VALGRIND_BESTEFFORT_VARIABLE_LATENCY_ERRORS=1 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..689260a2b --- /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/(1|c); +} + +int main() +{ + 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