-
-
Notifications
You must be signed in to change notification settings - Fork 14.4k
support c-variadic functions in rustc_const_eval
#150601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b2dcf7b
954e2c0
e4dffec
23fa1b4
b6654ef
b5aa67c
7caec1b
293ba18
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,8 +23,8 @@ use crate::fluent_generated as fluent; | |
| use crate::interpret::{ | ||
| self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, | ||
| GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, | ||
| compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, | ||
| throw_ub_custom, throw_unsup, throw_unsup_format, | ||
| compile_time_machine, err_inval, err_unsup_format, interp_ok, throw_exhaust, throw_inval, | ||
| throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format, | ||
| }; | ||
|
|
||
| /// When hitting this many interpreted terminators we emit a deny by default lint | ||
|
|
@@ -586,6 +586,58 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { | |
| } | ||
| } | ||
|
|
||
| sym::va_arg => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this implementation in the const_eval machine, and not the shared interpreter that Miri also uses? |
||
| let ptr_size = ecx.tcx.data_layout.pointer_size(); | ||
|
|
||
| // The only argument is a `&mut VaList`. | ||
| let ap_ref = ecx.read_pointer(&args[0])?; | ||
|
|
||
| // The first bytes of the `VaList` value store a pointer. The `AllocId` of this | ||
| // pointer is a key into a global map of variable argument lists. The offset is | ||
| // used as the index of the argument to read. | ||
| let va_list_ptr = { | ||
| let alloc = ecx | ||
| .get_ptr_alloc(ap_ref, ptr_size)? | ||
| .expect("va_list storage should not be a ZST"); | ||
| let scalar = alloc.read_pointer(Size::ZERO)?; | ||
| scalar.to_pointer(ecx)? | ||
| }; | ||
|
|
||
| let (prov, offset) = va_list_ptr.into_raw_parts(); | ||
| let alloc_id = prov.unwrap().alloc_id(); | ||
| let index = offset.bytes_usize(); | ||
|
|
||
| // Update the offset in this `VaList` value so that a subsequent call to `va_arg` | ||
| // reads the next argument. | ||
| let new_va_list_ptr = va_list_ptr.wrapping_offset(Size::from_bytes(1), ecx); | ||
| let addr = Scalar::from_maybe_pointer(new_va_list_ptr, ecx); | ||
| let mut alloc = ecx | ||
| .get_ptr_alloc_mut(ap_ref, ptr_size)? | ||
| .expect("va_list storage should not be a ZST"); | ||
| alloc.write_ptr_sized(Size::ZERO, addr)?; | ||
|
Comment on lines
+610
to
+617
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With this implementation, if I use a copy of the old pointer to call va_arg again, that UB will not be detected I think? Looks like there are some UB-catching tests missing. |
||
|
|
||
| let arguments = ecx.memory.va_list_map.get(&alloc_id).ok_or_else(|| { | ||
| err_unsup_format!("va_arg on unknown va_list allocation {:?}", alloc_id) | ||
| })?; | ||
|
|
||
| let Some(src_mplace) = arguments.get(index).cloned() else { | ||
| throw_ub!(VaArgOutOfBounds) | ||
| }; | ||
|
|
||
| // NOTE: In C some type conversions are allowed (e.g. casting between signed and | ||
| // unsigned integers). For now we require c-variadic arguments to be read with the | ||
| // exact type they were passed as. | ||
| if src_mplace.layout.ty != dest.layout.ty { | ||
| throw_unsup_format!( | ||
| "va_arg type mismatch: requested `{}`, but next argument is `{}`", | ||
| dest.layout.ty, | ||
| src_mplace.layout.ty | ||
| ); | ||
| } | ||
|
|
||
| ecx.copy_op(&src_mplace, dest)?; | ||
| } | ||
|
|
||
| _ => { | ||
| // We haven't handled the intrinsic, let's see if we can use a fallback body. | ||
| if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new line seems misplaced wrt the comment.