diff --git a/src/tools/miri/src/intrinsics/x86/avx.rs b/src/tools/miri/src/intrinsics/x86/avx.rs index 89aa2e8ae0664..ee0a4abca468f 100644 --- a/src/tools/miri/src/intrinsics/x86/avx.rs +++ b/src/tools/miri/src/intrinsics/x86/avx.rs @@ -15,8 +15,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); - this.expect_target_feature_for_intrinsic(link_name, "avx")?; + let ecx = self.eval_context_mut(); + ecx.expect_target_feature_for_intrinsic(link_name, "avx")?; // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx.").unwrap(); @@ -27,7 +27,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps.256" | "max.ps.256" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.ps.256" => FloatBinOp::Min, @@ -35,11 +35,11 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement _mm256_min_pd and _mm256_max_pd functions. "min.pd.256" | "max.pd.256" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.pd.256" => FloatBinOp::Min, @@ -47,26 +47,26 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement the _mm256_round_ps function. // Rounds the elements of `op` according to `rounding`. "round.ps.256" => { - let [op, rounding] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op, rounding] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - round_all::(this, op, rounding, dest)?; + round_all::(ecx, op, rounding, dest)?; } // Used to implement the _mm256_round_pd function. // Rounds the elements of `op` according to `rounding`. "round.pd.256" => { - let [op, rounding] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op, rounding] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - round_all::(this, op, rounding, dest)?; + round_all::(ecx, op, rounding, dest)?; } // Used to implement _mm256_{rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps.256" | "rsqrt.ps.256" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "rcp.ps.256" => FloatUnaryOp::Rcp, @@ -74,43 +74,43 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - unary_op_ps(this, which, op, dest)?; + unary_op_ps(ecx, which, op, dest)?; } // Used to implement the _mm256_dp_ps function. "dp.ps.256" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - conditional_dot_product(this, left, right, imm, dest)?; + conditional_dot_product(ecx, left, right, imm, dest)?; } // Used to implement the _mm256_cmp_ps function. // Performs a comparison operation on each component of `left` // and `right`. For each component, returns 0 if false or u32::MAX // if true. "cmp.ps.256" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement the _mm256_cmp_pd function. // Performs a comparison operation on each component of `left` // and `right`. For each component, returns 0 if false or u64::MAX // if true. "cmp.pd.256" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement the _mm256_cvtps_epi32, _mm256_cvttps_epi32, _mm256_cvtpd_epi32 // and _mm256_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvt.ps2dq.256" | "cvtt.ps2dq.256" | "cvt.pd2dq.256" | "cvtt.pd2dq.256" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let rnd = match unprefixed_name { // "current SSE rounding mode", assume nearest @@ -120,7 +120,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - convert_float_to_int(this, op, rnd, dest)?; + convert_float_to_int(ecx, op, rnd, dest)?; } // Used to implement the _mm_permutevar_ps and _mm256_permutevar_ps functions. // Shuffles 32-bit floats from `data` using `control` as control. Each 128-bit @@ -128,30 +128,27 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // sequence of 4-element arrays, and we shuffle each of these arrays, where // `control` determines which element of the current `data` array is written. "vpermilvar.ps" | "vpermilvar.ps.256" => { - let [data, control] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [data, control] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (data, data_len) = this.project_to_simd(data)?; - let (control, control_len) = this.project_to_simd(control)?; - let (dest, dest_len) = this.project_to_simd(dest)?; + let (data, data_len) = ecx.project_to_simd(data)?; + let (control, control_len) = ecx.project_to_simd(control)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; assert_eq!(dest_len, data_len); assert_eq!(dest_len, control_len); for i in 0..dest_len { - let control = this.project_index(&control, i)?; + let control = ecx.project_index(&control, i)?; // Each 128-bit chunk is shuffled independently. Since each chunk contains // four 32-bit elements, only two bits from `control` are used. To read the // value from the current chunk, add the destination index truncated to a multiple // of 4. let chunk_base = i & !0b11; - let src_i = u64::from(this.read_scalar(&control)?.to_u32()? & 0b11) + let src_i = u64::from(ecx.read_scalar(&control)?.to_u32()? & 0b11) .strict_add(chunk_base); - this.copy_op( - &this.project_index(&data, src_i)?, - &this.project_index(&dest, i)?, - )?; + ecx.copy_op(&ecx.project_index(&data, src_i)?, &ecx.project_index(&dest, i)?)?; } } // Used to implement the _mm_permutevar_pd and _mm256_permutevar_pd functions. @@ -161,17 +158,17 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // where `right` determines which element of the current `left` array is // written. "vpermilvar.pd" | "vpermilvar.pd.256" => { - let [data, control] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [data, control] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (data, data_len) = this.project_to_simd(data)?; - let (control, control_len) = this.project_to_simd(control)?; - let (dest, dest_len) = this.project_to_simd(dest)?; + let (data, data_len) = ecx.project_to_simd(data)?; + let (control, control_len) = ecx.project_to_simd(control)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; assert_eq!(dest_len, data_len); assert_eq!(dest_len, control_len); for i in 0..dest_len { - let control = this.project_index(&control, i)?; + let control = ecx.project_index(&control, i)?; // Each 128-bit chunk is shuffled independently. Since each chunk contains // two 64-bit elements, only the second bit from `control` is used (yes, the @@ -179,12 +176,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // chunk, add the destination index truncated to a multiple of 2. let chunk_base = i & !1; let src_i = - ((this.read_scalar(&control)?.to_u64()? >> 1) & 1).strict_add(chunk_base); + ((ecx.read_scalar(&control)?.to_u64()? >> 1) & 1).strict_add(chunk_base); - this.copy_op( - &this.project_index(&data, src_i)?, - &this.project_index(&dest, i)?, - )?; + ecx.copy_op(&ecx.project_index(&data, src_i)?, &ecx.project_index(&dest, i)?)?; } } // Used to implement the _mm256_lddqu_si256 function. @@ -193,22 +187,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the data crosses a cache line, but for Miri this is just a regular // unaligned read. "ldu.dq.256" => { - let [src_ptr] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - let src_ptr = this.read_pointer(src_ptr)?; - let dest = dest.force_mplace(this)?; + let [src_ptr] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + let src_ptr = ecx.read_pointer(src_ptr)?; + let dest = dest.force_mplace(ecx)?; // Unaligned copy, which is what we want. - this.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; + ecx.mem_copy(src_ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true)?; } // Used to implement the _mm256_testnzc_si256 function. // Tests `op & mask != 0 && op & mask != mask` "ptestnzc.256" => { - let [op, mask] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op, mask] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (all_zero, masked_set) = test_bits_masked(this, op, mask)?; + let (all_zero, masked_set) = test_bits_masked(ecx, op, mask)?; let res = !all_zero && !masked_set; - this.write_scalar(Scalar::from_i32(res.into()), dest)?; + ecx.write_scalar(Scalar::from_i32(res.into()), dest)?; } // Used to implement the _mm256_testz_pd, _mm256_testc_pd, _mm256_testnzc_pd // _mm_testnzc_pd, _mm256_testz_ps, _mm256_testc_ps, _mm256_testnzc_ps and @@ -219,9 +213,9 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Return `direct` (testz), `negated` (testc) or `!direct & !negated` (testnzc) "vtestz.pd.256" | "vtestc.pd.256" | "vtestnzc.pd.256" | "vtestnzc.pd" | "vtestz.ps.256" | "vtestc.ps.256" | "vtestnzc.ps.256" | "vtestnzc.ps" => { - let [op, mask] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op, mask] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (direct, negated) = test_high_bits_masked(this, op, mask)?; + let (direct, negated) = test_high_bits_masked(ecx, op, mask)?; let res = match unprefixed_name { "vtestz.pd.256" | "vtestz.ps.256" => direct, "vtestc.pd.256" | "vtestc.ps.256" => negated, @@ -230,7 +224,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - this.write_scalar(Scalar::from_i32(res.into()), dest)?; + ecx.write_scalar(Scalar::from_i32(res.into()), dest)?; } // Used to implement the `_mm256_zeroupper` and `_mm256_zeroall` functions. // These function clear out the upper 128 bits of all avx registers or @@ -241,7 +235,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // compiler, making these functions no-ops. // The only thing that needs to be ensured is the correct calling convention. - let [] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/intrinsics/x86/avx2.rs b/src/tools/miri/src/intrinsics/x86/avx2.rs index 6b49b61138839..fe83e95f4c155 100644 --- a/src/tools/miri/src/intrinsics/x86/avx2.rs +++ b/src/tools/miri/src/intrinsics/x86/avx2.rs @@ -14,8 +14,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); - this.expect_target_feature_for_intrinsic(link_name, "avx2")?; + let ecx = self.eval_context_mut(); + ecx.expect_target_feature_for_intrinsic(link_name, "avx2")?; // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.avx2.").unwrap(); @@ -23,13 +23,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm256_avg_epu8 and _mm256_avg_epu16 functions. // Averages packed unsigned 8/16-bit integers in `left` and `right`. "pavg.b" | "pavg.w" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pavg(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pavg(ecx, left, right, dest)?; } // Used to implement the _mm256_mulhi_epi16 and _mm256_mulhi_epu16 functions. "pmulh.w" | "pmulhu.w" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmulh(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pmulh(ecx, left, right, dest)?; } // Used to implement `_mm{,_mask}_{i32,i64}gather_{epi32,epi64,pd,ps}` functions // Gathers elements from `slice` using `offsets * scale` as indices. @@ -40,14 +40,14 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "gather.d.pd.256" | "gather.q.pd" | "gather.q.pd.256" | "gather.d.ps" | "gather.d.ps.256" | "gather.q.ps" | "gather.q.ps.256" => { let [src, slice, offsets, mask, scale] = - this.check_shim_sig_llvm_intrinsic(link_name, args)?; + ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; assert_eq!(dest.layout, src.layout); - let (src, _) = this.project_to_simd(src)?; - let (offsets, offsets_len) = this.project_to_simd(offsets)?; - let (mask, mask_len) = this.project_to_simd(mask)?; - let (dest, dest_len) = this.project_to_simd(dest)?; + let (src, _) = ecx.project_to_simd(src)?; + let (offsets, offsets_len) = ecx.project_to_simd(offsets)?; + let (mask, mask_len) = ecx.project_to_simd(mask)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; // There are cases like dest: i32x4, offsets: i64x2 // If dest has more elements than offset, extra dest elements are filled with zero. @@ -56,46 +56,46 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { assert_eq!(dest_len, mask_len); - let mask_item_size = mask.layout.field(this, 0).size; + let mask_item_size = mask.layout.field(ecx, 0).size; let high_bit_offset = mask_item_size.bits().strict_sub(1); - let scale = this.read_scalar(scale)?.to_i8()?; + let scale = ecx.read_scalar(scale)?.to_i8()?; if !matches!(scale, 1 | 2 | 4 | 8) { panic!("invalid gather scale {scale}"); } let scale = i64::from(scale); - let slice = this.read_pointer(slice)?; + let slice = ecx.read_pointer(slice)?; for i in 0..actual_len { - let mask = this.project_index(&mask, i)?; - let dest = this.project_index(&dest, i)?; + let mask = ecx.project_index(&mask, i)?; + let dest = ecx.project_index(&dest, i)?; - if this.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { - let offset = this.project_index(&offsets, i)?; + if ecx.read_scalar(&mask)?.to_uint(mask_item_size)? >> high_bit_offset != 0 { + let offset = ecx.project_index(&offsets, i)?; let offset = - i64::try_from(this.read_scalar(&offset)?.to_int(offset.layout.size)?) + i64::try_from(ecx.read_scalar(&offset)?.to_int(offset.layout.size)?) .unwrap(); - let ptr = slice.wrapping_signed_offset(offset.strict_mul(scale), &this.tcx); + let ptr = slice.wrapping_signed_offset(offset.strict_mul(scale), &ecx.tcx); // Unaligned copy, which is what we want. - this.mem_copy( + ecx.mem_copy( ptr, dest.ptr(), dest.layout.size, /*nonoverlapping*/ true, )?; } else { - this.copy_op(&this.project_index(&src, i)?, &dest)?; + ecx.copy_op(&ecx.project_index(&src, i)?, &dest)?; } } for i in actual_len..dest_len { - let dest = this.project_index(&dest, i)?; - this.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; + let dest = ecx.project_index(&dest, i)?; + ecx.write_scalar(Scalar::from_int(0, dest.layout.size), &dest)?; } } // Used to implement the _mm256_maddubs_epi16 function. "pmadd.ub.sw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmaddbw(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pmaddbw(ecx, left, right, dest)?; } // Used to implement the _mm256_mpsadbw_epu8 function. // Compute the sum of absolute differences of quadruplets of unsigned @@ -104,8 +104,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // offsets specified in `imm`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mpsadbw_epu8 "mpsadbw" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - mpsadbw(this, left, right, imm, dest)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + mpsadbw(ecx, left, right, imm, dest)?; } // Used to implement the _mm256_mulhrs_epi16 function. // Multiplies packed 16-bit signed integer values, truncates the 32-bit @@ -114,53 +114,53 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 1 and then taking the bits `1..=16`. // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mulhrs_epi16 "pmul.hr.sw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmulhrsw(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pmulhrsw(ecx, left, right, dest)?; } // Used to implement the _mm256_packs_epi16 function. // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - packsswb(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + packsswb(ecx, left, right, dest)?; } // Used to implement the _mm256_packs_epi32 function. // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - packssdw(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + packssdw(ecx, left, right, dest)?; } // Used to implement the _mm256_packus_epi16 function. // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - packuswb(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + packuswb(ecx, left, right, dest)?; } // Used to implement the _mm256_packus_epi32 function. // Concatenates two 32-bit signed integer vectors and converts // the result to a 16-bit unsigned integer vector with saturation. "packusdw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - packusdw(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + packusdw(ecx, left, right, dest)?; } // Used to implement _mm256_permutevar8x32_epi32 and _mm256_permutevar8x32_ps. "permd" | "permps" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - permute(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + permute(ecx, left, right, dest)?; } // Used to implement the _mm256_sad_epu8 function. "psad.bw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - psadbw(this, left, right, dest)? + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + psadbw(ecx, left, right, dest)? } // Used to implement the _mm256_shuffle_epi8 intrinsic. // Shuffles bytes from `left` using `right` as pattern. // Each 128-bit block is shuffled independently. "pshuf.b" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pshufb(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pshufb(ecx, left, right, dest)?; } // Used to implement the _mm256_sign_epi{8,16,32} functions. // Negates elements from `left` when the corresponding element in @@ -168,8 +168,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is written to the corresponding output element. // Basically, we multiply `left` with `right.signum()`. "psign.b" | "psign.w" | "psign.d" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - psign(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + psign(ecx, left, right, dest)?; } // Used to implement the _mm256_{sll,srl,sra}_epi{16,32,64} functions // (except _mm256_sra_epi64, which is not available in AVX2). @@ -181,7 +181,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -190,22 +190,22 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - shift_simd_by_scalar(this, left, right, which, dest)?; + shift_simd_by_scalar(ecx, left, right, which, dest)?; } // Used to implement the _mm256_madd_epi16 function. // Multiplies packed signed 16-bit integers in `left` and `right`, producing // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmaddwd(this, left, right, dest)?; + pmaddwd(ecx, left, right, dest)?; } // Used to implement the _mm{,256}_{sllv,srlv,srav}_epi{32,64} functions // (except _mm{,256}_srav_epi64, which are not available in AVX2). "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" | "psrlv.d" | "psrlv.d.256" | "psrlv.q" | "psrlv.q.256" | "psrav.d" | "psrav.d.256" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "psllv.d" | "psllv.d.256" | "psllv.q" | "psllv.q.256" => ShiftOp::Left, @@ -214,7 +214,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - shift_simd_by_simd(this, left, right, which, dest)?; + shift_simd_by_simd(ecx, left, right, which, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), diff --git a/src/tools/miri/src/intrinsics/x86/mod.rs b/src/tools/miri/src/intrinsics/x86/mod.rs index 0c82a70bf96ef..3d99eed671f58 100644 --- a/src/tools/miri/src/intrinsics/x86/mod.rs +++ b/src/tools/miri/src/intrinsics/x86/mod.rs @@ -31,7 +31,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.").unwrap(); match unprefixed_name { @@ -41,20 +41,20 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/addcarry-u32-addcarry-u64.html // https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-8/subborrow-u32-subborrow-u64.html "addcarry.32" | "addcarry.64" | "subborrow.32" | "subborrow.64" => { - if unprefixed_name.ends_with("64") && this.tcx.sess.target.arch != Arch::X86_64 { + if unprefixed_name.ends_with("64") && ecx.tcx.sess.target.arch != Arch::X86_64 { return interp_ok(EmulateItemResult::NotSupported); } - let [cb_in, a, b] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [cb_in, a, b] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let op = if unprefixed_name.starts_with("add") { mir::BinOp::AddWithOverflow } else { mir::BinOp::SubWithOverflow }; - let (sum, cb_out) = carrying_add(this, cb_in, a, b, op)?; - this.write_scalar(cb_out, &this.project_field(dest, FieldIdx::ZERO)?)?; - this.write_immediate(*sum, &this.project_field(dest, FieldIdx::ONE)?)?; + let (sum, cb_out) = carrying_add(ecx, cb_in, a, b, op)?; + ecx.write_scalar(cb_out, &ecx.project_field(dest, FieldIdx::ZERO)?)?; + ecx.write_immediate(*sum, &ecx.project_field(dest, FieldIdx::ONE)?)?; } // Used to implement the `_mm_pause` function. @@ -63,87 +63,87 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // the instruction behaves like a no-op, so it is always safe to call the // intrinsic. "sse2.pause" => { - let [] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; // Only exhibit the spin-loop hint behavior when SSE2 is enabled. - if this.tcx.sess.internal_target_features.contains(&Symbol::intern("sse2")) { - this.yield_active_thread(); + if ecx.tcx.sess.internal_target_features.contains(&Symbol::intern("sse2")) { + ecx.yield_active_thread(); } } "pclmulqdq" | "pclmulqdq.256" | "pclmulqdq.512" => { let mut len = 2; // in units of 64bits - this.expect_target_feature_for_intrinsic(link_name, "pclmulqdq")?; + ecx.expect_target_feature_for_intrinsic(link_name, "pclmulqdq")?; if unprefixed_name.ends_with(".256") { - this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + ecx.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; len = 4; } else if unprefixed_name.ends_with(".512") { - this.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; - this.expect_target_feature_for_intrinsic(link_name, "avx512f")?; + ecx.expect_target_feature_for_intrinsic(link_name, "vpclmulqdq")?; + ecx.expect_target_feature_for_intrinsic(link_name, "avx512f")?; len = 8; } - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - pclmulqdq(this, left, right, imm, dest, len)?; + pclmulqdq(ecx, left, right, imm, dest, len)?; } name if name.starts_with("bmi.") => { - return bmi::EvalContextExt::emulate_x86_bmi_intrinsic(this, link_name, args, dest); + return bmi::EvalContextExt::emulate_x86_bmi_intrinsic(ecx, link_name, args, dest); } // The GFNI extension does not get its own namespace. // Check for instruction names instead. name if name.starts_with("vgf2p8affine") || name.starts_with("vgf2p8mulb") => { return gfni::EvalContextExt::emulate_x86_gfni_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("sha") => { - return sha::EvalContextExt::emulate_x86_sha_intrinsic(this, link_name, args, dest); + return sha::EvalContextExt::emulate_x86_sha_intrinsic(ecx, link_name, args, dest); } name if name.starts_with("sse.") => { - return sse::EvalContextExt::emulate_x86_sse_intrinsic(this, link_name, args, dest); + return sse::EvalContextExt::emulate_x86_sse_intrinsic(ecx, link_name, args, dest); } name if name.starts_with("sse2.") => { return sse2::EvalContextExt::emulate_x86_sse2_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("sse3.") => { return sse3::EvalContextExt::emulate_x86_sse3_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("ssse3.") => { return ssse3::EvalContextExt::emulate_x86_ssse3_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("sse41.") => { return sse41::EvalContextExt::emulate_x86_sse41_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("sse42.") => { return sse42::EvalContextExt::emulate_x86_sse42_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("aesni.") => { return aesni::EvalContextExt::emulate_x86_aesni_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("avx.") => { - return avx::EvalContextExt::emulate_x86_avx_intrinsic(this, link_name, args, dest); + return avx::EvalContextExt::emulate_x86_avx_intrinsic(ecx, link_name, args, dest); } name if name.starts_with("avx2.") => { return avx2::EvalContextExt::emulate_x86_avx2_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } name if name.starts_with("avx512.") => { return avx512::EvalContextExt::emulate_x86_avx512_intrinsic( - this, link_name, args, dest, + ecx, link_name, args, dest, ); } diff --git a/src/tools/miri/src/intrinsics/x86/sse.rs b/src/tools/miri/src/intrinsics/x86/sse.rs index 29d8f7ef53e48..09e36dd218204 100644 --- a/src/tools/miri/src/intrinsics/x86/sse.rs +++ b/src/tools/miri/src/intrinsics/x86/sse.rs @@ -15,8 +15,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); - this.expect_target_feature_for_intrinsic(link_name, "sse")?; + let ecx = self.eval_context_mut(); + ecx.expect_target_feature_for_intrinsic(link_name, "sse")?; // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse.").unwrap(); // All these intrinsics operate on 128-bit (f32x4) SIMD vectors unless stated otherwise. @@ -30,7 +30,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Performs the operations on the first component of `left` and // `right` and copies the remaining components from `left`. "min.ss" | "max.ss" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.ss" => FloatBinOp::Min, @@ -38,7 +38,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_first::(this, which, left, right, dest)?; + bin_op_simd_float_first::(ecx, which, left, right, dest)?; } // Used to implement _mm_min_ps and _mm_max_ps functions. // Note that the semantics are a bit different from Rust simd_min @@ -46,7 +46,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.ps" | "max.ps" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.ps" => FloatBinOp::Min, @@ -54,13 +54,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement _mm_{rcp,rsqrt}_ss functions. // Performs the operations on the first component of `op` and // copies the remaining components from `op`. "rcp.ss" | "rsqrt.ss" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "rcp.ss" => FloatUnaryOp::Rcp, @@ -68,12 +68,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - unary_op_ss(this, which, op, dest)?; + unary_op_ss(ecx, which, op, dest)?; } // Used to implement _mm_{sqrt,rcp,rsqrt}_ps functions. // Performs the operations on all components of `op`. "rcp.ps" | "rsqrt.ps" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "rcp.ps" => FloatUnaryOp::Rcp, @@ -81,7 +81,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - unary_op_ps(this, which, op, dest)?; + unary_op_ps(ecx, which, op, dest)?; } // Used to implement the _mm_cmp*_ss functions. // Performs a comparison operation on the first component of `left` @@ -92,12 +92,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ss are SSE functions // with hard-coded operations. "cmp.ss" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_first::(this, which, left, right, dest)?; + bin_op_simd_float_first::(ecx, which, left, right, dest)?; } // Used to implement the _mm_cmp*_ps functions. // Performs a comparison operation on each component of `left` @@ -108,12 +108,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_ps are SSE functions // with hard-coded operations. "cmp.ps" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_ss functions. // Compares the first component of `left` and `right` and returns @@ -121,15 +121,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.ss" | "comilt.ss" | "comile.ss" | "comigt.ss" | "comige.ss" | "comineq.ss" | "ucomieq.ss" | "ucomilt.ss" | "ucomile.ss" | "ucomigt.ss" | "ucomige.ss" | "ucomineq.ss" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; + let (left, left_len) = ecx.project_to_simd(left)?; + let (right, right_len) = ecx.project_to_simd(right)?; assert_eq!(left_len, right_len); - let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f32()?; - let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f32()?; + let left = ecx.read_scalar(&ecx.project_index(&left, 0)?)?.to_f32()?; + let right = ecx.read_scalar(&ecx.project_index(&right, 0)?)?.to_f32()?; // The difference between the com* and ucom* variants is signaling // of exceptions when either argument is a quiet NaN. We do not // support accessing the SSE status register from miri (or from Rust, @@ -143,16 +143,16 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comineq.ss" | "ucomineq.ss" => left != right, _ => unreachable!(), }; - this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?; + ecx.write_scalar(Scalar::from_i32(i32::from(res)), dest)?; } // Use to implement the _mm_cvtss_si32, _mm_cvttss_si32, // _mm_cvtss_si64 and _mm_cvttss_si64 functions. // Converts the first component of `op` from f32 to i32/i64. "cvtss2si" | "cvttss2si" | "cvtss2si64" | "cvttss2si64" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (op, _) = this.project_to_simd(op)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + let (op, _) = ecx.project_to_simd(op)?; - let op = this.read_immediate(&this.project_index(&op, 0)?)?; + let op = ecx.read_immediate(&ecx.project_index(&op, 0)?)?; let rnd = match unprefixed_name { // "current SSE rounding mode", assume nearest @@ -164,12 +164,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { + let res = ecx.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_immediate(*res, dest)?; + ecx.write_immediate(*res, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/intrinsics/x86/sse2.rs b/src/tools/miri/src/intrinsics/x86/sse2.rs index e3dcdf6c248c4..bfd92bfd74c9f 100644 --- a/src/tools/miri/src/intrinsics/x86/sse2.rs +++ b/src/tools/miri/src/intrinsics/x86/sse2.rs @@ -15,8 +15,8 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); - this.expect_target_feature_for_intrinsic(link_name, "sse2")?; + let ecx = self.eval_context_mut(); + ecx.expect_target_feature_for_intrinsic(link_name, "sse2")?; // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.x86.sse2.").unwrap(); @@ -35,15 +35,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Used to implement the _mm_avg_epu8 and _mm_avg_epu16 functions. // Averages packed unsigned 8/16-bit integers in `left` and `right`. "pavg.b" | "pavg.w" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - pavg(this, left, right, dest)?; + pavg(ecx, left, right, dest)?; } // Used to implement the _mm_sad_epu8 function. "psad.bw" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - psadbw(this, left, right, dest)? + psadbw(ecx, left, right, dest)? } // Used to implement the _mm_{sll,srl,sra}_epi{16,32,64} functions // (except _mm_sra_epi64, which is not available in SSE2). @@ -55,7 +55,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // is copied to remaining bits. "psll.w" | "psrl.w" | "psra.w" | "psll.d" | "psrl.d" | "psra.d" | "psll.q" | "psrl.q" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "psll.w" | "psll.d" | "psll.q" => ShiftOp::Left, @@ -64,16 +64,16 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - shift_simd_by_scalar(this, left, right, which, dest)?; + shift_simd_by_scalar(ecx, left, right, which, dest)?; } // Used to implement the _mm_cvtps_epi32, _mm_cvttps_epi32, _mm_cvtpd_epi32 // and _mm_cvttpd_epi32 functions. // Converts packed f32/f64 to packed i32. "cvtps2dq" | "cvttps2dq" | "cvtpd2dq" | "cvttpd2dq" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (op_len, _) = op.layout.ty.simd_size_and_type(*this.tcx); - let (dest_len, _) = dest.layout.ty.simd_size_and_type(*this.tcx); + let (op_len, _) = op.layout.ty.simd_size_and_type(*ecx.tcx); + let (dest_len, _) = dest.layout.ty.simd_size_and_type(*ecx.tcx); match unprefixed_name { "cvtps2dq" | "cvttps2dq" => { // f32x4 to i32x4 conversion @@ -101,31 +101,31 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - convert_float_to_int(this, op, rnd, dest)?; + convert_float_to_int(ecx, op, rnd, dest)?; } // Used to implement the _mm_packs_epi16 function. // Converts two 16-bit integer vectors to a single 8-bit integer // vector with signed saturation. "packsswb.128" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - packsswb(this, left, right, dest)?; + packsswb(ecx, left, right, dest)?; } // Used to implement the _mm_packus_epi16 function. // Converts two 16-bit signed integer vectors to a single 8-bit // unsigned integer vector with saturation. "packuswb.128" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - packuswb(this, left, right, dest)?; + packuswb(ecx, left, right, dest)?; } // Used to implement the _mm_packs_epi32 function. // Converts two 32-bit integer vectors to a single 16-bit integer // vector with signed saturation. "packssdw.128" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - packssdw(this, left, right, dest)?; + packssdw(ecx, left, right, dest)?; } // Used to implement _mm_min_sd and _mm_max_sd functions. // Note that the semantics are a bit different from Rust simd_min @@ -133,7 +133,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.sd" | "max.sd" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.sd" => FloatBinOp::Min, @@ -141,7 +141,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_first::(this, which, left, right, dest)?; + bin_op_simd_float_first::(ecx, which, left, right, dest)?; } // Used to implement _mm_min_pd and _mm_max_pd functions. // Note that the semantics are a bit different from Rust simd_min @@ -149,7 +149,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // matches the IEEE min/max operations, while x86 has different // semantics. "min.pd" | "max.pd" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = match unprefixed_name { "min.pd" => FloatBinOp::Min, @@ -157,7 +157,7 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement the _mm_cmp*_sd functions. // Performs a comparison operation on the first component of `left` @@ -168,12 +168,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_sd are SSE2 functions // with hard-coded operations. "cmp.sd" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_first::(this, which, left, right, dest)?; + bin_op_simd_float_first::(ecx, which, left, right, dest)?; } // Used to implement the _mm_cmp*_pd functions. // Performs a comparison operation on each component of `left` @@ -184,12 +184,12 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // _mm_cmp{eq,lt,le,gt,ge,neq,nlt,nle,ngt,nge,ord,unord}_pd are SSE2 functions // with hard-coded operations. "cmp.pd" => { - let [left, right, imm] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right, imm] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; let which = - FloatBinOp::cmp_from_imm(this, this.read_scalar(imm)?.to_i8()?, link_name)?; + FloatBinOp::cmp_from_imm(ecx, ecx.read_scalar(imm)?.to_i8()?, link_name)?; - bin_op_simd_float_all::(this, which, left, right, dest)?; + bin_op_simd_float_all::(ecx, which, left, right, dest)?; } // Used to implement _mm_{,u}comi{eq,lt,le,gt,ge,neq}_sd functions. // Compares the first component of `left` and `right` and returns @@ -197,15 +197,15 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comieq.sd" | "comilt.sd" | "comile.sd" | "comigt.sd" | "comige.sd" | "comineq.sd" | "ucomieq.sd" | "ucomilt.sd" | "ucomile.sd" | "ucomigt.sd" | "ucomige.sd" | "ucomineq.sd" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; + let (left, left_len) = ecx.project_to_simd(left)?; + let (right, right_len) = ecx.project_to_simd(right)?; assert_eq!(left_len, right_len); - let left = this.read_scalar(&this.project_index(&left, 0)?)?.to_f64()?; - let right = this.read_scalar(&this.project_index(&right, 0)?)?.to_f64()?; + let left = ecx.read_scalar(&ecx.project_index(&left, 0)?)?.to_f64()?; + let right = ecx.read_scalar(&ecx.project_index(&right, 0)?)?.to_f64()?; // The difference between the com* and ucom* variants is signaling // of exceptions when either argument is a quiet NaN. We do not // support accessing the SSE status register from miri (or from Rust, @@ -219,16 +219,16 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "comineq.sd" | "ucomineq.sd" => left != right, _ => unreachable!(), }; - this.write_scalar(Scalar::from_i32(i32::from(res)), dest)?; + ecx.write_scalar(Scalar::from_i32(i32::from(res)), dest)?; } // Use to implement the _mm_cvtsd_si32, _mm_cvttsd_si32, // _mm_cvtsd_si64 and _mm_cvttsd_si64 functions. // Converts the first component of `op` from f64 to i32/i64. "cvtsd2si" | "cvttsd2si" | "cvtsd2si64" | "cvttsd2si64" => { - let [op] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (op, _) = this.project_to_simd(op)?; + let [op] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + let (op, _) = ecx.project_to_simd(op)?; - let op = this.read_immediate(&this.project_index(&op, 0)?)?; + let op = ecx.read_immediate(&ecx.project_index(&op, 0)?)?; let rnd = match unprefixed_name { // "current SSE rounding mode", assume nearest @@ -240,34 +240,34 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => unreachable!(), }; - let res = this.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { + let res = ecx.float_to_int_checked(&op, dest.layout, rnd)?.unwrap_or_else(|| { // Fallback to minimum according to SSE semantics. ImmTy::from_int(dest.layout.size.signed_int_min(), dest.layout) }); - this.write_immediate(*res, dest)?; + ecx.write_immediate(*res, dest)?; } // Used to implement the _mm_cvtsd_ss function. // Converts the first f64 from `right` to f32 and copies the remaining // elements from `left` "cvtsd2ss" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, _) = this.project_to_simd(right)?; - let (dest, dest_len) = this.project_to_simd(dest)?; + let (left, left_len) = ecx.project_to_simd(left)?; + let (right, _) = ecx.project_to_simd(right)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; assert_eq!(dest_len, left_len); // Convert first element of `right` - let right0 = this.read_immediate(&this.project_index(&right, 0)?)?; - let dest0 = this.project_index(&dest, 0)?; - let res0 = this.float_to_float_or_int(&right0, dest0.layout)?; - this.write_immediate(*res0, &dest0)?; + let right0 = ecx.read_immediate(&ecx.project_index(&right, 0)?)?; + let dest0 = ecx.project_index(&dest, 0)?; + let res0 = ecx.float_to_float_or_int(&right0, dest0.layout)?; + ecx.write_immediate(*res0, &dest0)?; // Copy remaining from `left` for i in 1..dest_len { - this.copy_op(&this.project_index(&left, i)?, &this.project_index(&dest, i)?)?; + ecx.copy_op(&ecx.project_index(&left, i)?, &ecx.project_index(&dest, i)?)?; } } // Used to implement the _mm_madd_epi16 function. @@ -275,13 +275,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // intermediate signed 32-bit integers. Horizontally add adjacent pairs of // intermediate 32-bit integers, and pack the results in `dest`. "pmadd.wd" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmaddwd(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pmaddwd(ecx, left, right, dest)?; } // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions. "pmulh.w" | "pmulhu.w" => { - let [left, right] = this.check_shim_sig_llvm_intrinsic(link_name, args)?; - pmulh(this, left, right, dest)?; + let [left, right] = ecx.check_shim_sig_llvm_intrinsic(link_name, args)?; + pmulh(ecx, left, right, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), } diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs index f8afa78bc5bd1..2125c8bfbf98f 100644 --- a/src/tools/miri/src/operator.rs +++ b/src/tools/miri/src/operator.rs @@ -18,13 +18,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx>> { use rustc_middle::mir::BinOp::*; - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); interp_ok(match bin_op { Eq | Ne | Lt | Le | Gt | Ge => { assert_eq!(left.layout.backend_repr, right.layout.backend_repr); // types can differ, e.g. fn ptrs with different `for` - let size = this.pointer_size(); + let size = ecx.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. let left = match **left { @@ -46,34 +46,34 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Ge => left >= right, _ => bug!(), }; - ImmTy::from_bool(res, *this.tcx) + ImmTy::from_bool(res, *ecx.tcx) } // Some more operations are possible with atomics. // The RHS must be `usize`. Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_raw_ptr()); - assert_eq!(right.layout.ty, this.tcx.types.usize); - let ptr = left.to_scalar().to_pointer(this); + assert_eq!(right.layout.ty, ecx.tcx.types.usize); + let ptr = left.to_scalar().to_pointer(ecx); // We do the actual operation with usize-typed scalars. - let left = ImmTy::from_uint(ptr.addr().bytes(), this.machine.layouts.usize); - let result = this.binary_op(bin_op, &left, right)?; + let left = ImmTy::from_uint(ptr.addr().bytes(), ecx.machine.layouts.usize); + let result = ecx.binary_op(bin_op, &left, right)?; // Construct a new pointer with the provenance of `ptr` (the LHS). let result_ptr = Pointer::new( ptr.provenance, - Size::from_bytes(result.to_scalar().to_target_usize(this)?), + Size::from_bytes(result.to_scalar().to_target_usize(ecx)?), ); - ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, this), left.layout) + ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, ecx), left.layout) } - _ => span_bug!(this.cur_span(), "Invalid operator on pointers: {:?}", bin_op), + _ => span_bug!(ecx.cur_span(), "Invalid operator on pointers: {:?}", bin_op), }) } fn generate_nan, F2: Float>(&self, inputs: &[F1]) -> F2 { - let this = self.eval_context_ref(); - if !this.machine.float_nondet { + let ecx = self.eval_context_ref(); + if !ecx.machine.float_nondet { return F2::NAN; } @@ -90,7 +90,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { if f.is_nan() { Some(f) } else { None } } - let mut rand = this.machine.rng.borrow_mut(); + let mut rand = ecx.machine.rng.borrow_mut(); // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation. // On some targets there are more possibilities; for now we just generate those options that // are possible everywhere. @@ -117,12 +117,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn equal_float_min_max(&self, a: F, b: F) -> F { - let this = self.eval_context_ref(); - if !this.machine.float_nondet { + let ecx = self.eval_context_ref(); + if !ecx.machine.float_nondet { return a; } // Return one side non-deterministically. - let mut rand = this.machine.rng.borrow_mut(); + let mut rand = ecx.machine.rng.borrow_mut(); if rand.random() { a } else { b } } } diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs index d1022bacd583d..c2e4188c904b8 100644 --- a/src/tools/miri/src/provenance_gc.rs +++ b/src/tools/miri/src/provenance_gc.rs @@ -263,12 +263,12 @@ fn remove_unreachable_allocs<'tcx>(ecx: &mut MiriInterpCx<'tcx>, allocs: FxHashS impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { fn run_provenance_gc(&mut self) { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); // We collect all tags and AllocId from every part of the interpreter. let mut tags = FxHashSet::default(); let mut alloc_ids = FxHashSet::default(); - this.visit_provenance(&mut |id, tag| { + ecx.visit_provenance(&mut |id, tag| { if let Some(id) = id { alloc_ids.insert(id); } @@ -278,7 +278,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { }); // Based on this, clean up the interpreter state. - remove_unreachable_tags(this, tags); - remove_unreachable_allocs(this, alloc_ids); + remove_unreachable_tags(ecx, tags); + remove_unreachable_allocs(ecx, alloc_ids); } } diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs index aa45a6d9686a9..5976d70ce0e24 100644 --- a/src/tools/miri/src/shims/alloc.rs +++ b/src/tools/miri/src/shims/alloc.rs @@ -11,7 +11,7 @@ impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Returns the alignment that `malloc` would guarantee for requests of the given size. fn malloc_align(&self, size: u64) -> Align { - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); // The C standard says: "The pointer returned if the allocation succeeds is suitably aligned // so that it may be assigned to a pointer to any type of object with a fundamental // alignment requirement and size less than or equal to the size requested." @@ -19,8 +19,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // This is given by `alignof(max_align_t)`. The following list is taken from // `library/std/src/sys/alloc/mod.rs` (where this is called `MIN_ALIGN`) and should // be kept in sync. - let os = &this.tcx.sess.target.os; - let max_fundamental_align = match &this.tcx.sess.target.arch { + let os = &ecx.tcx.sess.target.os; + let max_fundamental_align = match &ecx.tcx.sess.target.arch { Arch::RiscV32 if matches!(os, Os::EspIdf | Os::Zkvm) => 4, Arch::Xtensa if matches!(os, Os::EspIdf) => 4, Arch::X86 @@ -87,11 +87,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Check some basic requirements for this allocation request: /// non-zero size, power-of-two alignment. fn check_rust_alloc_request(&self, size: u64, align: u64) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); if size == 0 { throw_ub_format!("creating allocation with size 0"); } - if size > this.max_size_of_val().bytes() { + if size > ecx.max_size_of_val().bytes() { throw_ub_format!("creating an allocation larger than half the address space"); } if let Err(e) = Align::from_bytes(align) { @@ -119,20 +119,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &PlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); match method { SpecialAllocatorMethod::Alloc | SpecialAllocatorMethod::AllocZeroed => { - let [size, align] = &this.check_shim_sig( + let [size, align] = &ecx.check_shim_sig( shim_sig!(extern "Rust" fn(usize, core::mem::Alignment) -> *()), (link_name, abi, args), )?; - let size = this.read_target_usize(size)?; - let align = this.read_target_usize(align)?; + let size = ecx.read_target_usize(size)?; + let align = ecx.read_target_usize(align)?; - this.check_rust_alloc_request(size, align)?; + ecx.check_rust_alloc_request(size, align)?; - let ptr = this.allocate_ptr( + let ptr = ecx.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), @@ -143,39 +143,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }, )?; - this.write_pointer(ptr, dest) + ecx.write_pointer(ptr, dest) } SpecialAllocatorMethod::Dealloc => { - let [ptr, old_size, align] = &this.check_shim_sig( + let [ptr, old_size, align] = &ecx.check_shim_sig( shim_sig!(extern "Rust" fn(*(), usize, core::mem::Alignment) -> ()), (link_name, abi, args), )?; - let ptr = this.read_pointer(ptr)?; - let old_size = this.read_target_usize(old_size)?; - let align = this.read_target_usize(align)?; + let ptr = ecx.read_pointer(ptr)?; + let old_size = ecx.read_target_usize(old_size)?; + let align = ecx.read_target_usize(align)?; // No need to check old_size/align; we anyway check that they match the allocation. - this.deallocate_ptr( + ecx.deallocate_ptr( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), ) } SpecialAllocatorMethod::Realloc => { - let [ptr, old_size, align, new_size] = &this.check_shim_sig( + let [ptr, old_size, align, new_size] = &ecx.check_shim_sig( shim_sig!(extern "Rust" fn(*(), usize, core::mem::Alignment, usize) -> *()), (link_name, abi, args), )?; - let ptr = this.read_pointer(ptr)?; - let old_size = this.read_target_usize(old_size)?; - let align = this.read_target_usize(align)?; - let new_size = this.read_target_usize(new_size)?; + let ptr = ecx.read_pointer(ptr)?; + let old_size = ecx.read_target_usize(old_size)?; + let align = ecx.read_target_usize(align)?; + let new_size = ecx.read_target_usize(new_size)?; // No need to check old_size; we anyway check that they match the allocation. - this.check_rust_alloc_request(new_size, align)?; + ecx.check_rust_alloc_request(new_size, align)?; let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.reallocate_ptr( + let new_ptr = ecx.reallocate_ptr( ptr, Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), @@ -183,16 +183,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { MiriMemoryKind::Rust.into(), AllocInit::Uninit, )?; - this.write_pointer(new_ptr, dest) + ecx.write_pointer(new_ptr, dest) } } } fn malloc(&mut self, size: u64, init: AllocInit) -> InterpResult<'tcx, Pointer> { - let this = self.eval_context_mut(); - let align = this.malloc_align(size); + let ecx = self.eval_context_mut(); + let align = ecx.malloc_align(size); let ptr = - this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?; + ecx.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?; interp_ok(ptr.into()) } @@ -202,39 +202,39 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { align: &OpTy<'tcx>, size: &OpTy<'tcx>, ) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - let memptr = this.deref_pointer(memptr)?; - let align = this.read_target_usize(align)?; - let size = this.read_target_usize(size)?; + let ecx = self.eval_context_mut(); + let memptr = ecx.deref_pointer(memptr)?; + let align = ecx.read_target_usize(align)?; + let size = ecx.read_target_usize(size)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). // But failure to adhere to this is not UB, it's an error condition. - if !align.is_power_of_two() || align < this.pointer_size().bytes() { - interp_ok(this.eval_libc("EINVAL")) + if !align.is_power_of_two() || align < ecx.pointer_size().bytes() { + interp_ok(ecx.eval_libc("EINVAL")) } else { - let ptr = this.allocate_ptr( + let ptr = ecx.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), AllocInit::Uninit, )?; - this.write_pointer(ptr, &memptr)?; + ecx.write_pointer(ptr, &memptr)?; interp_ok(Scalar::from_i32(0)) } } fn free(&mut self, ptr: Pointer) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - if !this.ptr_is_null(ptr)? { - this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?; + let ecx = self.eval_context_mut(); + if !ecx.ptr_is_null(ptr)? { + ecx.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?; } interp_ok(()) } fn realloc(&mut self, old_ptr: Pointer, new_size: u64) -> InterpResult<'tcx, Pointer> { - let this = self.eval_context_mut(); - let new_align = this.malloc_align(new_size); - if this.ptr_is_null(old_ptr)? { + let ecx = self.eval_context_mut(); + let new_align = ecx.malloc_align(new_size); + if ecx.ptr_is_null(old_ptr)? { // Here we must behave like `malloc`. self.malloc(new_size, AllocInit::Uninit) } else { @@ -243,7 +243,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // throw_ub_format!("`realloc` with a size of zero"); } else { - let new_ptr = this.reallocate_ptr( + let new_ptr = ecx.reallocate_ptr( old_ptr, None, Size::from_bytes(new_size), @@ -261,9 +261,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { align: &OpTy<'tcx>, size: &OpTy<'tcx>, ) -> InterpResult<'tcx, Pointer> { - let this = self.eval_context_mut(); - let align = this.read_target_usize(align)?; - let size = this.read_target_usize(size)?; + let ecx = self.eval_context_mut(); + let align = ecx.read_target_usize(align)?; + let size = ecx.read_target_usize(size)?; // Alignment must be a power of 2, and "supported by the implementation". // We decide that "supported by the implementation" means that the @@ -285,8 +285,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=aligned_alloc&apropos=0&sektion=3&manpath=FreeBSD+9-current&format=html match size.checked_rem(align) { Some(0) if align.is_power_of_two() => { - let align = align.max(this.malloc_align(size).bytes()); - let ptr = this.allocate_ptr( + let align = align.max(ecx.malloc_align(size).bytes()); + let ptr = ecx.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), diff --git a/src/tools/miri/src/shims/backtrace.rs b/src/tools/miri/src/shims/backtrace.rs index f7d369226704b..0dea1e812909d 100644 --- a/src/tools/miri/src/shims/backtrace.rs +++ b/src/tools/miri/src/shims/backtrace.rs @@ -14,18 +14,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let [flags] = &this - .check_shim_sig(shim_sig!(extern "Rust" fn(u64) -> usize), (link_name, abi, args))?; + let ecx = self.eval_context_mut(); + let [flags] = + &ecx.check_shim_sig(shim_sig!(extern "Rust" fn(u64) -> usize), (link_name, abi, args))?; - let flags = this.read_scalar(flags)?.to_u64()?; + let flags = ecx.read_scalar(flags)?.to_u64()?; if flags != 0 { throw_unsup_format!("unknown `miri_backtrace_size` flags {}", flags); } - let frame_count = this.active_thread_stack().len(); + let frame_count = ecx.active_thread_stack().len(); - this.write_scalar(Scalar::from_target_usize(frame_count.to_u64(), this), dest) + ecx.write_scalar(Scalar::from_target_usize(frame_count.to_u64(), ecx), dest) } fn handle_miri_get_backtrace( @@ -34,16 +34,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name: Symbol, args: &[OpTy<'tcx>], ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); - let [flags, buf] = &this + let [flags, buf] = &ecx .check_shim_sig(shim_sig!(extern "Rust" fn(u64, **()) -> ()), (link_name, abi, args))?; - let flags = this.read_scalar(flags)?.to_u64()?; - let buf_place = this.deref_pointer(buf)?; + let flags = ecx.read_scalar(flags)?.to_u64()?; + let buf_place = ecx.deref_pointer(buf)?; let mut data = Vec::new(); - for frame in this.active_thread_stack().iter().rev() { + for frame in ecx.active_thread_stack().iter().rev() { // Match behavior of debuginfo (`FunctionCx::adjusted_span_and_dbg_scope`). let span = hygiene::walk_chain_collapsed(frame.current_span(), frame.body().span); data.push((frame.instance(), span.lo())); @@ -58,8 +58,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // to reconstruct the needed frame information in `handle_miri_resolve_frame`. // Note that we never actually read or write anything from/to this pointer - // all of the data is represented by the pointer value itself. - let fn_ptr = this.fn_ptr(FnVal::Instance(instance)); - fn_ptr.wrapping_offset(Size::from_bytes(pos.0), this) + let fn_ptr = ecx.fn_ptr(FnVal::Instance(instance)); + fn_ptr.wrapping_offset(Size::from_bytes(pos.0), ecx) }) .collect(); @@ -69,8 +69,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } 1 => for (i, ptr) in ptrs.into_iter().enumerate() { - let op_place = this.project_c_array_field(&buf_place, i.to_u64())?; - this.write_pointer(ptr, &op_place)?; + let op_place = ecx.project_c_array_field(&buf_place, i.to_u64())?; + ecx.write_pointer(ptr, &op_place)?; }, _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), }; @@ -82,20 +82,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &self, ptr: &OpTy<'tcx>, ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); - let ptr = this.read_pointer(ptr)?; + let ptr = ecx.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. The offset encodes the span. - let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr, 0)?; + let (alloc_id, offset, _prov) = ecx.ptr_get_alloc_id(ptr, 0)?; // This has to be an actual global fn ptr, not a dlsym function. - let Some(GlobalAlloc::Function { instance, .. }) = this.tcx.try_get_global_alloc(alloc_id) + let Some(GlobalAlloc::Function { instance, .. }) = ecx.tcx.try_get_global_alloc(alloc_id) else { throw_ub_format!("expected static function pointer, found {:?}", ptr); }; let lo = - this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); + ecx.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); let name = instance.to_string(); let filename = lo.file.name.prefer_remapped_unconditionally().to_string(); @@ -110,22 +110,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); // FIXME: not nice to read the type from std but we don't have a good way to construct the // type here and now. ADTs need a DefId. - let [ptr, flags] = &this.check_shim_sig( + let [ptr, flags] = &ecx.check_shim_sig( shim_sig!(extern "Rust" fn(*_, u64) -> std::backtrace_rs::backtrace::miri::MiriFrame), (link_name, abi, args), )?; - let flags = this.read_scalar(flags)?.to_u64()?; + let flags = ecx.read_scalar(flags)?.to_u64()?; - let (fn_instance, lo, name, filename) = this.resolve_frame_pointer(ptr)?; + let (fn_instance, lo, name, filename) = ecx.resolve_frame_pointer(ptr)?; // Reconstruct the original function pointer, // which we pass to user code. - let fn_ptr = this.fn_ptr(FnVal::Instance(fn_instance)); + let fn_ptr = ecx.fn_ptr(FnVal::Instance(fn_instance)); // `u32` is not enough to fit line/colno, which can be `usize`. It seems unlikely that a // file would have more than 2^32 lines or columns, but whatever, just default to 0. @@ -146,27 +146,27 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { throw_unsup_format!("miri_resolve_frame: v0 is not supported any more"); } 1 => { - this.write_scalar( - Scalar::from_target_usize(name.len().to_u64(), this), - &this.project_field(dest, FieldIdx::from_u32(0))?, + ecx.write_scalar( + Scalar::from_target_usize(name.len().to_u64(), ecx), + &ecx.project_field(dest, FieldIdx::from_u32(0))?, )?; - this.write_scalar( - Scalar::from_target_usize(filename.len().to_u64(), this), - &this.project_field(dest, FieldIdx::from_u32(1))?, + ecx.write_scalar( + Scalar::from_target_usize(filename.len().to_u64(), ecx), + &ecx.project_field(dest, FieldIdx::from_u32(1))?, )?; } _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), } - this.write_scalar( + ecx.write_scalar( Scalar::from_u32(lineno), - &this.project_field(dest, FieldIdx::from_u32(2))?, + &ecx.project_field(dest, FieldIdx::from_u32(2))?, )?; - this.write_scalar( + ecx.write_scalar( Scalar::from_u32(colno), - &this.project_field(dest, FieldIdx::from_u32(3))?, + &ecx.project_field(dest, FieldIdx::from_u32(3))?, )?; - this.write_pointer(fn_ptr, &this.project_field(dest, FieldIdx::from_u32(4))?)?; + ecx.write_pointer(fn_ptr, &ecx.project_field(dest, FieldIdx::from_u32(4))?)?; interp_ok(()) } @@ -177,22 +177,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { link_name: Symbol, args: &[OpTy<'tcx>], ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); - let [ptr, flags, name_ptr, filename_ptr] = &this.check_shim_sig( + let [ptr, flags, name_ptr, filename_ptr] = &ecx.check_shim_sig( shim_sig!(extern "Rust" fn(*(), u64, *(), *()) -> ()), (link_name, abi, args), )?; - let flags = this.read_scalar(flags)?.to_u64()?; + let flags = ecx.read_scalar(flags)?.to_u64()?; if flags != 0 { throw_unsup_format!("unknown `miri_resolve_frame_names` flags {}", flags); } - let (_, _, name, filename) = this.resolve_frame_pointer(ptr)?; + let (_, _, name, filename) = ecx.resolve_frame_pointer(ptr)?; - this.write_bytes_ptr(this.read_pointer(name_ptr)?, name.bytes())?; - this.write_bytes_ptr(this.read_pointer(filename_ptr)?, filename.bytes())?; + ecx.write_bytes_ptr(ecx.read_pointer(name_ptr)?, name.bytes())?; + ecx.write_bytes_ptr(ecx.read_pointer(filename_ptr)?, filename.bytes())?; interp_ok(()) } diff --git a/src/tools/miri/src/shims/env.rs b/src/tools/miri/src/shims/env.rs index cfc94abb68989..b85685d844ada 100644 --- a/src/tools/miri/src/shims/env.rs +++ b/src/tools/miri/src/shims/env.rs @@ -95,36 +95,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Try to get an environment variable from the interpreted program's environment. This is /// useful for implementing shims which are documented to read from the environment. fn get_env_var(&mut self, name: &OsStr) -> InterpResult<'tcx, Option> { - let this = self.eval_context_ref(); - match &this.machine.env_vars { + let ecx = self.eval_context_ref(); + match &ecx.machine.env_vars { EnvVars::Uninit => interp_ok(None), - EnvVars::Unix(vars) => vars.get(this, name), + EnvVars::Unix(vars) => vars.get(ecx, name), EnvVars::Windows(vars) => vars.get(name), } } /// Get the process identifier. fn get_pid(&self) -> u32 { - let this = self.eval_context_ref(); - if this.machine.communicate() { std::process::id() } else { 1000 } + let ecx = self.eval_context_ref(); + if ecx.machine.communicate() { std::process::id() } else { 1000 } } /// Get an "OS" thread ID for any thread. fn get_tid(&self, thread: ThreadId) -> u32 { - let this = self.eval_context_ref(); - assert!(this.target_os_is_unix()); + let ecx = self.eval_context_ref(); + assert!(ecx.target_os_is_unix()); // On Linux, the main thread has PID == TID so we uphold this. For simplicity we do it // everywhere. That also ensures this ID is different from what is returned by // `pthread_self`. - this.get_pid().strict_add(thread.to_u32()) + ecx.get_pid().strict_add(thread.to_u32()) } /// Convert TID back to a `ThreadId`, or `None` if it is invalid or the thread has terminated. fn get_thread_id_from_linux_tid(&self, tid: u32) -> Option { - let this = self.eval_context_ref(); - assert_matches!(this.tcx.sess.target.os, Os::Linux | Os::Android); + let ecx = self.eval_context_ref(); + assert_matches!(ecx.tcx.sess.target.os, Os::Linux | Os::Android); // TID = PID + thread_index => index = TID - PID. - let id = tid.checked_sub(this.get_pid())?; - this.machine.threads.thread_id_try_from(id).ok() + let id = tid.checked_sub(ecx.get_pid())?; + ecx.machine.threads.thread_id_try_from(id).ok() } } diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index 5e344b3b266c1..b292565d449e8 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -732,7 +732,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { len: u64, read_cb: impl FnOnce(&mut [u8]) -> io::Result, ) -> InterpResult<'tcx, Result> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); let len = usize::saturating_cast_from(len); let mut bytes = vec![0; len]; @@ -742,7 +742,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If reading to `bytes` did not fail, we write those bytes to the buffer. // Crucially, if fewer than `bytes.len()` bytes were read, only write // that much into the output buffer! - this.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?; + ecx.write_bytes_ptr(ptr, bytes[..read_size].iter().copied())?; interp_ok(Ok(read_size.to_u64())) } Err(e) => interp_ok(Err(IoError::HostError(e))), @@ -756,10 +756,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { len: u64, write_cb: impl FnOnce(&[u8]) -> io::Result, ) -> InterpResult<'tcx, Result> { - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); let len = usize::saturating_cast_from(len); - let bytes = this.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; + let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; let result = write_cb(bytes); interp_ok(result.map_err(IoError::HostError).map(|written_size| written_size.to_u64())) } diff --git a/src/tools/miri/src/shims/math.rs b/src/tools/miri/src/shims/math.rs index f722d79c6e165..c72aeda67668a 100644 --- a/src/tools/miri/src/shims/math.rs +++ b/src/tools/miri/src/shims/math.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &[OpTy<'tcx>], dest: &MPlaceTy<'tcx>, ) -> InterpResult<'tcx, EmulateItemResult> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); // math functions (note that there are also intrinsics for some other functions) match link_name.as_str() { @@ -37,13 +37,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erff" | "erfcf" => { - let [f] = &this.check_shim_sig( + let [f] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f32) -> f32), (link_name, abi, args), )?; - let f = this.read_scalar(f)?.to_f32()?; + let f = ecx.read_scalar(f)?.to_f32()?; - let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + let res = math::fixed_float_value(ecx, link_name.as_str(), &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let f_host = f.to_host(); @@ -68,14 +68,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = res.to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. math::clamp_float_value(link_name.as_str(), res) }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[f]); + ecx.write_scalar(res, dest)?; } #[rustfmt::skip] | "_hypotf" @@ -83,14 +83,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2f" | "fdimf" => { - let [f1, f2] = &this.check_shim_sig( + let [f1, f2] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f32, f32) -> f32), (link_name, abi, args), )?; - let f1 = this.read_scalar(f1)?.to_f32()?; - let f2 = this.read_scalar(f2)?.to_f32()?; + let f1 = ecx.read_scalar(f1)?.to_f32()?; + let f2 = ecx.read_scalar(f2)?.to_f32()?; - let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]) + let res = math::fixed_float_value(ecx, link_name.as_str(), &[f1, f2]) .unwrap_or_else(|| { let res = match link_name.as_str() { // underscore case for windows, here and below @@ -104,14 +104,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. math::clamp_float_value(link_name.as_str(), res) }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[f1, f2]); + ecx.write_scalar(res, dest)?; } #[rustfmt::skip] | "cbrt" @@ -130,13 +130,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "erf" | "erfc" => { - let [f] = &this.check_shim_sig( + let [f] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f64) -> f64), (link_name, abi, args), )?; - let f = this.read_scalar(f)?.to_f64()?; + let f = ecx.read_scalar(f)?.to_f64()?; - let res = math::fixed_float_value(this, link_name.as_str(), &[f]).unwrap_or_else(|| { + let res = math::fixed_float_value(ecx, link_name.as_str(), &[f]).unwrap_or_else(|| { // Using host floats (but it's fine, these operations do not have // guaranteed precision). let f_host = f.to_host(); @@ -161,14 +161,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let res = res.to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. math::clamp_float_value(link_name.as_str(), res) }); - let res = this.adjust_nan(res, &[f]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[f]); + ecx.write_scalar(res, dest)?; } #[rustfmt::skip] | "_hypot" @@ -176,14 +176,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | "atan2" | "fdim" => { - let [f1, f2] = &this.check_shim_sig( + let [f1, f2] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f64, f64) -> f64), (link_name, abi, args), )?; - let f1 = this.read_scalar(f1)?.to_f64()?; - let f2 = this.read_scalar(f2)?.to_f64()?; + let f1 = ecx.read_scalar(f1)?.to_f64()?; + let f2 = ecx.read_scalar(f2)?.to_f64()?; - let res = math::fixed_float_value(this, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { + let res = math::fixed_float_value(ecx, link_name.as_str(), &[f1, f2]).unwrap_or_else(|| { let res = match link_name.as_str() { // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -196,75 +196,75 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. math::clamp_float_value(link_name.as_str(), res) }); - let res = this.adjust_nan(res, &[f1, f2]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[f1, f2]); + ecx.write_scalar(res, dest)?; } #[rustfmt::skip] | "_ldexp" | "ldexp" | "scalbn" => { - let [x, exp] = &this.check_shim_sig( + let [x, exp] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f64, i32) -> f64), (link_name, abi, args), )?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - let x = this.read_scalar(x)?.to_f64()?; - let exp = this.read_scalar(exp)?.to_i32()?; + let x = ecx.read_scalar(x)?.to_f64()?; + let exp = ecx.read_scalar(exp)?.to_i32()?; let res = x.scalbn(exp); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[x]); + ecx.write_scalar(res, dest)?; } "lgammaf_r" => { - let [x, signp] = &this.check_shim_sig( + let [x, signp] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f32, *i32) -> f32), (link_name, abi, args), )?; - let x = this.read_scalar(x)?.to_f32()?; - let signp = this.deref_pointer(signp)?; + let x = ecx.read_scalar(x)?.to_f32()?; + let signp = ecx.deref_pointer(signp)?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); - this.write_int(sign, &signp)?; + ecx.write_int(sign, &signp)?; let res = res.to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. let res = math::clamp_float_value(link_name.as_str(), res); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[x]); + ecx.write_scalar(res, dest)?; } "lgamma_r" => { - let [x, signp] = &this.check_shim_sig( + let [x, signp] = &ecx.check_shim_sig( shim_sig!(extern "C" fn(f64, *i32) -> f64), (link_name, abi, args), )?; - let x = this.read_scalar(x)?.to_f64()?; - let signp = this.deref_pointer(signp)?; + let x = ecx.read_scalar(x)?.to_f64()?; + let signp = ecx.deref_pointer(signp)?; // Using host floats (but it's fine, these operations do not have guaranteed precision). let (res, sign) = x.to_host().ln_gamma(); - this.write_int(sign, &signp)?; + ecx.write_int(sign, &signp)?; let res = res.to_soft(); // Apply a relative error of 4ULP to introduce some non-determinism // simulating imprecise implementations and optimizations. - let res = math::apply_random_float_error_ulp(this, res, 4); + let res = math::apply_random_float_error_ulp(ecx, res, 4); // Clamp the result to the guaranteed range of this function according to the C standard, // if any. let res = math::clamp_float_value(link_name.as_str(), res); - let res = this.adjust_nan(res, &[x]); - this.write_scalar(res, dest)?; + let res = ecx.adjust_nan(res, &[x]); + ecx.write_scalar(res, dest)?; } _ => return interp_ok(EmulateItemResult::NotSupported), diff --git a/src/tools/miri/src/shims/native_lib/mod.rs b/src/tools/miri/src/shims/native_lib/mod.rs index 1dd113766d6ad..b671092ccaf32 100644 --- a/src/tools/miri/src/shims/native_lib/mod.rs +++ b/src/tools/miri/src/shims/native_lib/mod.rs @@ -99,15 +99,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { args: &mut [OwnedArg], ret: (FfiType, Size), ) -> InterpResult<'tcx, (Box<[u8]>, Option)> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); #[cfg(target_os = "linux")] - let alloc = this.machine.allocator.as_ref().unwrap().clone(); + let alloc = ecx.machine.allocator.as_ref().unwrap().clone(); #[cfg(not(target_os = "linux"))] // Placeholder value. let alloc = (); // Expose InterpCx for use by closure callbacks. - this.machine.native_lib_ecx_interchange.set(ptr::from_mut(this).expose_provenance()); + ecx.machine.native_lib_ecx_interchange.set(ptr::from_mut(ecx).expose_provenance()); let res = trace::Supervisor::do_ffi(&alloc, || { use libffi::middle::{Arg, Cif, Ret}; @@ -120,7 +120,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { ret.into() }); - this.machine.native_lib_ecx_interchange.set(0); + ecx.machine.native_lib_ecx_interchange.set(0); res } @@ -129,9 +129,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// if it exists. The function must be in one of the shared object files specified: /// we do *not* return pointers to functions in dependencies of libraries. fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); // Try getting the function from one of the shared libraries. - for (lib, lib_path) in &this.machine.native_lib { + for (lib, lib_path) in &ecx.machine.native_lib { let Ok(func): Result, _> = (unsafe { lib.get(link_name.as_str().as_bytes()) }) else { @@ -179,7 +179,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { /// ordered sequentially by when the accesses happened, and the sizes are /// assumed to be exact. fn tracing_apply_accesses(&mut self, events: MemEvents) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); for evt in events.acc_events { let evt_rg = evt.get_range(); @@ -188,11 +188,11 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut rg = evt_rg.addr..evt_rg.end(); while let Some(curr) = rg.next() { let Some(alloc_id) = - this.alloc_id_from_addr(curr.to_u64(), rg.len().try_into().unwrap()) + ecx.alloc_id_from_addr(curr.to_u64(), rg.len().try_into().unwrap()) else { throw_ub_format!("Foreign code did an out-of-bounds access!") }; - let alloc = this.get_alloc_raw(alloc_id)?; + let alloc = ecx.get_alloc_raw(alloc_id)?; // The logical and physical address of the allocation coincide, so we can use // this instead of `addr_from_alloc_id`. let alloc_addr = alloc.get_bytes_unchecked_raw().addr(); @@ -211,17 +211,16 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { match evt { AccessEvent::Read(_) => { // If a provenance was read by the foreign code, expose it. - for (_prov_range, prov) in - alloc.provenance().get_range(overlap.into(), this) + for (_prov_range, prov) in alloc.provenance().get_range(overlap.into(), ecx) { - this.expose_provenance(prov)?; + ecx.expose_provenance(prov)?; } } AccessEvent::Write(_, certain) => { // Sometimes we aren't certain if a write happened, in which case we // only initialise that data if the allocation is mutable. if certain || alloc.mutability.is_mut() { - let (alloc, cx) = this.get_alloc_raw_mut(alloc_id)?; + let (alloc, cx) = ecx.get_alloc_raw_mut(alloc_id)?; alloc.process_native_write( &cx.tcx, Some(AllocRange { @@ -339,23 +338,23 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } fn ffi_ret_to_mem(&mut self, v: Box<[u8]>, dest: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); let len = v.len(); - this.write_bytes_ptr(dest.ptr(), v)?; + ecx.write_bytes_ptr(dest.ptr(), v)?; if len == 0 { return interp_ok(()); } // We have no idea which provenance these bytes have, so we reset it to wildcard. - let tcx = this.tcx; - let (alloc_id, offset, _) = this.ptr_try_get_alloc_id(dest.ptr(), 0).unwrap(); - let alloc = this.get_alloc_raw_mut(alloc_id)?.0; + let tcx = ecx.tcx; + let (alloc_id, offset, _) = ecx.ptr_try_get_alloc_id(dest.ptr(), 0).unwrap(); + let alloc = ecx.get_alloc_raw_mut(alloc_id)?.0; alloc.process_native_write(&tcx, Some(alloc_range(offset, dest.layout.size))); // Run the validation that would usually be part of `return`, also to reset // any provenance and padding that would not survive the return. - if MiriMachine::enforce_validity(this, dest.layout) { - this.validate_place( + if MiriMachine::enforce_validity(ecx, dest.layout) { + ecx.validate_place( &dest.clone().into(), - MiriMachine::enforce_validity_recursively(this, dest.layout), + MiriMachine::enforce_validity_recursively(ecx, dest.layout), /*reset_provenance_and_padding*/ true, )?; } @@ -369,7 +368,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { adt_def: ty::AdtDef<'tcx>, args: ty::GenericArgs<'tcx>, ) -> Result> { - let this = self.eval_context_ref(); + let ecx = self.eval_context_ref(); // TODO: unions, etc. if !adt_def.is_struct() { return Err(orig_ty); @@ -381,10 +380,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { let mut fields = vec![]; for field in &adt_def.non_enum_variant().fields { - let layout = this - .layout_of(field.ty(*this.tcx, args).skip_norm_wip()) - .map_err(|_err| orig_ty)?; - fields.push(this.ty_to_ffitype(layout)?); + let layout = + ecx.layout_of(field.ty(*ecx.tcx, args).skip_norm_wip()).map_err(|_err| orig_ty)?; + fields.push(ecx.ty_to_ffitype(layout)?); } Ok(FfiType::structure(fields)) diff --git a/src/tools/miri/src/shims/readiness.rs b/src/tools/miri/src/shims/readiness.rs index 71a47e9f52a6a..691c3f676284e 100644 --- a/src/tools/miri/src/shims/readiness.rs +++ b/src/tools/miri/src/shims/readiness.rs @@ -455,7 +455,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { fd: DynFileDescriptionRef, flags: ReadinessUpdateFlags, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); let fd_id = fd.id(); let watched = fd.readiness_watched().unwrap(); @@ -463,7 +463,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { // We capture a vector clock even if there is nobody watching, since someone might get // interested in the future and then synchronize with this event. // FIXME: currently we do this even if the readiness did not change! - this.release_clock(|clock| { + ecx.release_clock(|clock| { watched.ready_clock.borrow_mut().join(clock); })?; } @@ -479,7 +479,7 @@ pub trait EvalContextExt<'tcx>: MiriInterpCxExt<'tcx> { let active_readiness = fd.readiness(); for watcher in watchers { - this.update_readiness( + ecx.update_readiness( &watcher, active_readiness, flags.contains(ReadinessUpdateFlags::FORCE_EDGE), @@ -515,7 +515,7 @@ pub trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { &mut dyn FnMut(ReadinessInterestKey, &mut ReadinessInterest) -> InterpResult<'tcx>, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let ecx = self.eval_context_mut(); let mut ready = watcher.ready.borrow_mut(); for_each_interest(&mut |key, interest| { let new_readiness = interest.relevant & active; @@ -544,7 +544,7 @@ pub trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { && let Some(thread_id) = watcher.queue.borrow_mut().pop_front() { drop(ready); - this.unblock_thread(thread_id, BlockReason::Readiness)?; + ecx.unblock_thread(thread_id, BlockReason::Readiness)?; ready = watcher.ready.borrow_mut(); } interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 314bb4ee878a6..c6169fb7fdfe8 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -16,6 +16,7 @@ use self::shims::unix::netbsd::foreign_items as netbsd; use self::shims::unix::solarish::foreign_items as solarish; use crate::shims::alloc::EvalContextExt as _; use crate::shims::cpu_affinity::EvalContextExt as _; +use crate::shims::files::FD_LIMIT; use crate::shims::unix::*; use crate::{shim_sig, *}; @@ -66,11 +67,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // 512 seems to be a reasonable default. The value is not critical, in // the sense that getpwuid_r takes and checks the buffer length. ("_SC_GETPW_R_SIZE_MAX", |_ecx| 512), - // Miri doesn't have a fixed limit on FDs, but we may be limited in terms of how - // many *host* FDs we can open. Just use some arbitrary, pretty big value; - // this can be adjusted if it causes problems. - // The spec imposes a minimum of `_POSIX_OPEN_MAX` (20). - ("_SC_OPEN_MAX", |_ecx| 2_i32.pow(16).into()), + // We only hand out FDs in `0..FD_LIMIT`, making `FD_LIMIT` the max + // number of open FDs. + ("_SC_OPEN_MAX", |_ecx| FD_LIMIT.into()), // Our hard-coded hostname is just 4 bytes so we don't need anything big here. ("_SC_HOST_NAME_MAX", |_ecx| 255), ]; diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 325be5526e1c2..5d7615b7473d3 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1182,14 +1182,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ("stx_mask", mask.into()), ("stx_mode", metadata.mode.into()), ("stx_blksize", metadata.blksize.unwrap_or(0).into()), - ("stx_attributes", 0), ("stx_nlink", metadata.nlink.unwrap_or(0).into()), ("stx_uid", metadata.uid.unwrap_or(0).into()), ("stx_gid", metadata.gid.unwrap_or(0).into()), ("stx_ino", metadata.ino.unwrap_or(0).into()), ("stx_size", metadata.size.into()), ("stx_blocks", metadata.blocks.unwrap_or(0).into()), + // These fields do not seem to have a bit in `mask`, they are "always present", + // so we make sure they get initialized. ("stx_attributes_mask", 0), + ("stx_attributes", 0), ("stx_rdev_major", 0), ("stx_rdev_minor", 0), ("stx_dev_major", 0), @@ -1230,6 +1232,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { &this.project_field_named(&statxbuf, "stx_mtime")?, )?; + // The remaining fields have a mask bit associated with them, a bit that we do not + // set. Therefore we also do not initialize them. + interp_ok(Scalar::from_i32(0)) } diff --git a/src/tools/miri/src/shims/unix/linux_like/syscall.rs b/src/tools/miri/src/shims/unix/linux_like/syscall.rs index 88486f91e71c8..5535a129a7811 100644 --- a/src/tools/miri/src/shims/unix/linux_like/syscall.rs +++ b/src/tools/miri/src/shims/unix/linux_like/syscall.rs @@ -39,7 +39,6 @@ pub fn syscall<'tcx>( let sys_gettid = ecx.eval_libc("SYS_gettid").to_target_usize(ecx)?; let sys_accept4 = ecx.eval_libc("SYS_accept4").to_target_usize(ecx)?; let sys_copy_file_range = ecx.eval_libc("SYS_copy_file_range").to_target_usize(ecx)?; - let sys_splice = ecx.eval_libc("SYS_splice").to_target_usize(ecx)?; // FIXME: Do these all have direct tests (#3179)? match ecx.read_target_usize(&op)? { @@ -96,13 +95,11 @@ pub fn syscall<'tcx>( )?; ecx.linux_copy_file_range(fd_in, off_in, fd_out, off_out, len, flags, dest)?; } - num if num == sys_splice => { - // Force std to use a fallback path. + _ => { + // ENOSYS for unknown syscalls. That matches us returning null for all + // unknown weak symbols. ecx.set_errno_and_return_neg1(LibcError("ENOSYS"), dest)?; } - num => { - throw_unsup_format!("syscall: unsupported syscall number {num}"); - } }; interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/poll.rs b/src/tools/miri/src/shims/unix/poll.rs index 92929a790bdec..14689ce6e84f4 100644 --- a/src/tools/miri/src/shims/unix/poll.rs +++ b/src/tools/miri/src/shims/unix/poll.rs @@ -4,7 +4,7 @@ use std::time::Duration; use rustc_target::spec::Os; -use crate::shims::files::FdNum; +use crate::shims::files::{FD_LIMIT, FdNum}; use crate::*; /// An interest into a file descriptor together with its @@ -32,8 +32,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx> { let ecx = self.eval_context_mut(); - let nfds: u64 = ecx.read_scalar(nfds)?.to_int(nfds.layout.size)?.try_into().unwrap(); + let nfds: u64 = ecx.read_scalar(nfds)?.to_uint(nfds.layout.size)?.try_into().unwrap(); let timeout = ecx.read_scalar(timeout)?.to_i32()?; + + // Return `EINVAL`` if `nfds` is greater than `FD_LIMIT`. + if nfds > u64::try_from(FD_LIMIT).unwrap() { + return ecx.set_errno_and_return_neg1(LibcError("EINVAL"), dest); + } let fds_arr = ecx.deref_pointer(fds)?; // The provided interests indexed by the file descriptor they're for. diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs index 08d3c8ec1190d..55644d8b6f0f4 100644 --- a/src/tools/miri/src/shims/unix/socket.rs +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -720,9 +720,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let level = this.read_scalar(level)?.to_i32()?; let option_name = this.read_scalar(option_name)?.to_i32()?; let option_value_ptr = this.read_pointer(option_value)?; - let socklen_layout = this.libc_ty_layout("socklen_t"); - let option_len: u64 = - this.read_scalar(option_len)?.to_int(socklen_layout.size)?.try_into().unwrap(); + let Some(option_len) = this.read_socklen(option_len)? else { + return this.set_errno_and_return_neg1_i32(LibcError("EINVAL")); + }; // Check that the buffer has (at least) the given size. this.check_ptr_access( @@ -785,11 +785,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let socklen_layout = this.libc_ty_layout("socklen_t"); let option_len_ptr_mplace = this.ptr_to_mplace(option_len_ptr, socklen_layout); - let option_len: usize = this - .read_scalar(&option_len_ptr_mplace)? - .to_int(socklen_layout.size)? - .try_into() - .unwrap(); + let Some(option_len) = this.read_socklen(&option_len_ptr_mplace)? else { + return this.set_errno_and_return_neg1_i32(LibcError("EINVAL")); + }; // Check that the buffer has (at least) the given size. this.check_ptr_access( diff --git a/src/tools/miri/src/shims/unix/socket_address.rs b/src/tools/miri/src/shims/unix/socket_address.rs index 9e002b86f3ea9..154e3c60c3dfd 100644 --- a/src/tools/miri/src/shims/unix/socket_address.rs +++ b/src/tools/miri/src/shims/unix/socket_address.rs @@ -122,6 +122,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.free_address_infos(res_ptr) } + /// Read a `socklen_t` value. Returns `None` if it does not fit into a `u64`, e.g. if it + /// is negative, which is possible on targets where `socklen_t` is signed. + fn read_socklen( + &self, + op: &impl Projectable<'tcx, Provenance>, + ) -> InterpResult<'tcx, Option> { + let ecx = self.eval_context_ref(); + + let layout = op.layout(); + let scalar = ecx.read_scalar(op)?; + let len = if layout.backend_repr.is_signed() { + u64::try_from(scalar.to_int(layout.size)?).ok() + } else { + u64::try_from(scalar.to_uint(layout.size)?).ok() + }; + interp_ok(len) + } + /// Attempt to turn an address and length operand into a standard library socket address. /// /// Returns an IO error should the address length not match the address family length. @@ -135,8 +153,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // We only support address lengths which can be stored in a u64 since the // size of a layout is also stored in a u64. - let address_len: u64 = - this.read_scalar(address_len)?.to_int(address_len.layout.size)?.try_into().unwrap(); + let Some(address_len) = this.read_socklen(address_len)? else { + return interp_ok(Err(LibcError("EINVAL"))); + }; let address = this.deref_pointer(address)?; // Ensure the pointer is actually dereferenceable for that length. diff --git a/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.rs b/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.rs index f9ba1d7517aae..f407aeeac08c7 100644 --- a/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.rs +++ b/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.rs @@ -6,8 +6,10 @@ fn main() { assert!(sockfd >= 0); // The buffer is large enough for the value, but the length claims it is much larger. + // Use the largest possible length; Miri used to ICE here because it read `socklen_t` + // as a signed integer. let mut val: libc::c_int = 0; - let mut len: libc::socklen_t = 1024; + let mut len = libc::socklen_t::MAX; unsafe { libc::getsockopt( //~^ERROR: memory access failed diff --git a/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.stderr b/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.stderr index ce3042e68f3a1..6ed807a649d83 100644 --- a/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.stderr +++ b/src/tools/miri/tests/fail-dep/libc/getsockopt_buffer_too_small.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: memory access failed: attempting to access 1024 bytes, but got ALLOC which is only 4 bytes from the end of the allocation +error: Undefined Behavior: memory access failed: attempting to access 4294967295 bytes, but got ALLOC which is only 4 bytes from the end of the allocation --> tests/fail-dep/libc/getsockopt_buffer_too_small.rs:LL:CC | LL | / libc::getsockopt( diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs index 4b5c61ec88adc..63b4ad8928314 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_read_twice.rs @@ -1,7 +1,6 @@ //@ignore-target: windows # No libc socketpair on Windows //@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock -//@require-annotations-for-level: error use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs index 7b2de39c304d3..ff1214987e061 100644 --- a/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_block_write_twice.rs @@ -1,7 +1,6 @@ //@ignore-target: windows # No libc socketpair on Windows //@compile-flags: -Zmiri-deterministic-concurrency //@error-in-other-file: deadlock -//@require-annotations-for-level: error use std::thread; diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs new file mode 100644 index 0000000000000..8892a3ecdd655 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs @@ -0,0 +1,29 @@ +//@ignore-target: windows # No libc socketpair on Windows +//@compile-flags: -Zmiri-fixed-schedule +//@error-in-other-file: deadlock +//@error-in-other-file: deadlock + +use std::thread; + +#[path = "../../utils/libc.rs"] +mod libc_utils; +use libc_utils::*; + +/// Test that `close` unblocks reads on the other FD. +fn main() { + let mut fds = [-1, -1]; + errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); + + let thread1 = thread::spawn(move || { + // This read will be blocked because the buffer is already full. + read_to_end(fds[0]).unwrap(); + }); + let thread2 = thread::spawn(move || { + thread::yield_now(); // thread1 should go first + // Close the FD thread1 is waiting on. This does NOT unblock thread1! + // (That matches the behavior on native Linux.) + errno_check(unsafe { libc::close(fds[0]) }); + }); + thread1.join().unwrap(); + thread2.join().unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.stderr new file mode 100644 index 0000000000000..79008f501f213 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair_fd_closed_while_blocked.stderr @@ -0,0 +1,43 @@ +error: the evaluated program deadlocked + --> RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + | +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + | ^ thread got stuck here + | + = note: this is on thread `main` + = note: stack backtrace: + 0: std::sys::thread::PLATFORM::Thread::join + at RUSTLIB/std/src/sys/thread/PLATFORM.rs:LL:CC + 1: std::thread::lifecycle::JoinInner::<'_, ()>::join + at RUSTLIB/std/src/thread/lifecycle.rs:LL:CC + 2: std::thread::JoinHandle::<()>::join + at RUSTLIB/std/src/thread/join_handle.rs:LL:CC + 3: main + at tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs:LL:CC + +error: the evaluated program deadlocked + --> tests/fail-dep/libc/../../utils/libc.rs:LL:CC + | +LL | let res = errno_result(unsafe { libc::read(fd, spare.as_mut_ptr().cast(), spare.len()) })?; + | ^ thread got stuck here + | + = note: this is on thread `unnamed-ID` + = note: stack backtrace: + 0: libc_utils::read_to_end + at tests/fail-dep/libc/../../utils/libc.rs:LL:CC + 1: main::{closure#0} + at tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs:LL:CC +note: the last function in that backtrace got called indirectly due to this code + --> tests/fail-dep/libc/socketpair_fd_closed_while_blocked.rs:LL:CC + | +LL | let thread1 = thread::spawn(move || { + | ___________________^ +LL | | // This read will be blocked because the buffer is already full. +LL | | read_to_end(fds[0]).unwrap(); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 2 previous errors + diff --git a/src/tools/miri/tests/pass-dep/libc/poll.rs b/src/tools/miri/tests/pass-dep/libc/poll.rs index bcc2d334beb9f..0d55129ee2d39 100644 --- a/src/tools/miri/tests/pass-dep/libc/poll.rs +++ b/src/tools/miri/tests/pass-dep/libc/poll.rs @@ -29,6 +29,7 @@ fn main() { test_poll_negative_fd_interest(); test_poll_invalid_non_negative_fd_interest(); test_poll_zero_timeout(); + test_poll_nfds_too_big(); test_readiness_event_after_poll_blocked(); test_poll_race(); } @@ -171,6 +172,15 @@ fn test_poll_zero_timeout() { assert!(before.elapsed() < Duration::from_millis(100)) } +/// Test that `poll` fails with EINVAL when `nfds` is larger than the open file limit. +/// Miri used to ICE here because it read `nfds` as a signed integer. +fn test_poll_nfds_too_big() { + let err = unsafe { + errno_result(libc::poll(std::ptr::null_mut(), libc::nfds_t::MAX, 0)).unwrap_err() + }; + assert_eq!(err.raw_os_error(), Some(libc::EINVAL)); +} + /// Before Miri would ICE when /// any file description readiness is updated after a `poll` invocation has /// blocked. diff --git a/src/tools/miri/tests/pass-dep/libc/socketpair.rs b/src/tools/miri/tests/pass-dep/libc/socketpair.rs index 0638beb2d6c22..a560bdfdc9c42 100644 --- a/src/tools/miri/tests/pass-dep/libc/socketpair.rs +++ b/src/tools/miri/tests/pass-dep/libc/socketpair.rs @@ -241,7 +241,7 @@ fn test_write_unblocked_by_other_socket_close() { write_all(fds[0], &arr1).unwrap(); let thread1 = thread::spawn(move || { - // The write below will be blocked because the buffer is already full. + // This write belo will be blocked because the buffer is already full. write_all(fds[0], b"abc").unwrap_err() }); let thread2 = thread::spawn(move || { @@ -262,7 +262,7 @@ fn test_read_unblocked_by_other_socket_close() { errno_check(unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }); let thread1 = thread::spawn(move || { - // The write below will be blocked because the buffer is already full. + // This read will be blocked because the buffer is empty. read_to_end(fds[0]).unwrap() }); let thread2 = thread::spawn(move || { diff --git a/src/tools/miri/tests/pass-dep/libc/sysconf.rs b/src/tools/miri/tests/pass-dep/libc/sysconf.rs index b832b3033b76e..68f01db3ed14a 100644 --- a/src/tools/miri/tests/pass-dep/libc/sysconf.rs +++ b/src/tools/miri/tests/pass-dep/libc/sysconf.rs @@ -10,7 +10,7 @@ fn test_sysconfbasic() { let gwmax = libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX); assert!(gwmax >= 512); let omax = libc::sysconf(libc::_SC_OPEN_MAX); - assert_eq!(omax, 65536); + assert_eq!(omax, 524288); } }