1
Fork 0

Fix codegen with explicit allocation byte access

This commit is contained in:
Andreas Molzer 2019-08-14 04:40:03 +02:00
parent 7b941e368f
commit df58fcffbc

View file

@ -35,11 +35,21 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
assert_eq!(offset as usize as u64, offset); assert_eq!(offset as usize as u64, offset);
let offset = offset as usize; let offset = offset as usize;
if offset > next_offset { if offset > next_offset {
llvals.push(cx.const_bytes(&alloc.bytes[next_offset..offset])); // This `inspect` is okay since we have check that it is not within a relocation, it is
// within the bounds of the allocation, and it doesn't affect interpreter execution (we
// inspect the result after interpreter execution). Any undef byte is replaced with
// some arbitrary byte value.
//
// FIXME: relay undef bytes to codegen as undef const bytes
let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(next_offset..offset);
llvals.push(cx.const_bytes(bytes));
} }
let ptr_offset = read_target_uint( let ptr_offset = read_target_uint(
dl.endian, dl.endian,
&alloc.bytes[offset..(offset + pointer_size)], // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
// affect interpreter execution (we inspect the result after interpreter execution),
// and we properly interpret the relocation as a relocation pointer offset.
alloc.inspect_with_undef_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64;
llvals.push(cx.scalar_to_backend( llvals.push(cx.scalar_to_backend(
Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(), Pointer::new(alloc_id, Size::from_bytes(ptr_offset)).into(),
@ -51,8 +61,16 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll
)); ));
next_offset = offset + pointer_size; next_offset = offset + pointer_size;
} }
if alloc.bytes.len() >= next_offset { if alloc.len() >= next_offset {
llvals.push(cx.const_bytes(&alloc.bytes[next_offset ..])); let range = next_offset..alloc.len();
// This `inspect` is okay since we have check that it is after all relocations, it is
// within the bounds of the allocation, and it doesn't affect interpreter execution (we
// inspect the result after interpreter execution). Any undef byte is replaced with some
// arbitrary byte value.
//
// FIXME: relay undef bytes to codegen as undef const bytes
let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(range);
llvals.push(cx.const_bytes(bytes));
} }
cx.const_struct(&llvals, true) cx.const_struct(&llvals, true)
@ -437,7 +455,23 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
// //
// We could remove this hack whenever we decide to drop macOS 10.10 support. // We could remove this hack whenever we decide to drop macOS 10.10 support.
if self.tcx.sess.target.target.options.is_like_osx { if self.tcx.sess.target.target.options.is_like_osx {
let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { assert_eq!(alloc.relocations.len(), 0);
let is_zeroed = {
// Treats undefined bytes as if they were defined with the byte value that
// happens to be currently assigned in mir. This is valid since reading
// undef bytes may yield arbitrary values.
//
// FIXME: ignore undef bytes even with representation `!= 0`.
//
// The `inspect` method is okay here because we checked relocations, and
// because we are doing this access to inspect the final interpreter state
// (not as part of the interpreter execution).
alloc.inspect_with_undef_and_ptr_outside_interpreter(0..alloc.len())
.iter()
.all(|b| *b == 0)
};
let sect_name = if is_zeroed {
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0")
} else { } else {
CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0")
@ -456,10 +490,17 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> {
section.as_str().as_ptr() as *const _, section.as_str().as_ptr() as *const _,
section.as_str().len() as c_uint, section.as_str().len() as c_uint,
); );
assert!(alloc.relocations.is_empty());
// The `inspect` method is okay here because we checked relocations, and
// because we are doing this access to inspect the final interpreter state (not
// as part of the interpreter execution).
let bytes = alloc.inspect_with_undef_and_ptr_outside_interpreter(
0..alloc.len());
let alloc = llvm::LLVMMDStringInContext( let alloc = llvm::LLVMMDStringInContext(
self.llcx, self.llcx,
alloc.bytes.as_ptr() as *const _, bytes.as_ptr() as *const _,
alloc.bytes.len() as c_uint, bytes.len() as c_uint,
); );
let data = [section, alloc]; let data = [section, alloc];
let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2); let meta = llvm::LLVMMDNodeInContext(self.llcx, data.as_ptr(), 2);