diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-08-04 15:08:30 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-08-04 15:08:30 +0800 |
commit | e14473dcce910959a3f6a3c0c683456ab0f9dd1a (patch) | |
tree | 9463451f3f755bee4bcd2e652c3b04a8daa88dc5 | |
parent | 982826e4b309979bee8fe10f6ff537b4922e6316 (diff) | |
download | mrust-e14473dcce910959a3f6a3c0c683456ab0f9dd1a.tar.gz |
Standalone MIRI - Restructure so `0` is never a valid pointer value
-rw-r--r-- | src/trans/codegen_mmir.cpp | 19 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 6 | ||||
-rw-r--r-- | tools/standalone_miri/miri.cpp | 124 | ||||
-rw-r--r-- | tools/standalone_miri/miri.hpp | 2 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 38 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 3 |
6 files changed, 105 insertions, 87 deletions
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 2224b78f..c88915c6 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -18,6 +18,8 @@ namespace { + size_t PTR_BASE = 0x1000; // See matching value in standalone_miri value.hpp + template<typename T> struct Fmt { @@ -109,6 +111,9 @@ namespace TU_ARM(e, ItemAddr, v) { os << "ADDROF " << *v; } break; + TU_ARM(e, Const, v) { + BUG(Span(), "Stray named constant in MIR after cleanup - " << e); + } break; default: os << e; break; @@ -904,7 +909,7 @@ namespace { ASSERT_BUG(sp, lit.is_String(), ty << " not Literal::String - " << lit); const auto& s = lit.as_String(); - putsize(0); + putsize(PTR_BASE + 0); putsize(s.size()); out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s)); break; @@ -918,7 +923,7 @@ namespace TU_MATCH_HDRA( (lit), { ) TU_ARMA(BorrowPath, le) { - putsize(0); + putsize(PTR_BASE); out_relocations.push_back(Reloc::new_named(base_ofs, 8, &le)); if( is_unsized ) { @@ -930,7 +935,7 @@ namespace TU_ARMA(Integer, le) { ASSERT_BUG(sp, le == 0, "Pointer from integer not 0"); ASSERT_BUG(sp, ty.m_data.is_Pointer(), "Borrow from integer"); - putsize(0); + putsize(le); if( is_unsized ) { putsize(0); @@ -938,7 +943,7 @@ namespace } TU_ARMA(String, le) { const auto& s = lit.as_String(); - putsize(0); + putsize(PTR_BASE); putsize(s.size()); out_relocations.push_back(Reloc::new_bytes(base_ofs, 8, s)); } @@ -948,7 +953,7 @@ namespace } break; case ::HIR::TypeRef::Data::TAG_Function: ASSERT_BUG(sp, lit.is_BorrowPath(), ty << " not Literal::BorrowPath - " << lit); - putsize(0); + putsize(PTR_BASE); out_relocations.push_back(Reloc::new_named(base_ofs, 8, &lit.as_BorrowPath())); break; TU_ARM(ty.m_data, Array, te) { @@ -1021,7 +1026,7 @@ namespace m_of << "static " << p << ": " << vtable_ty << " = \""; // - Data // Drop - emit_str_usize(0); + emit_str_usize(PTR_BASE); // Align emit_str_usize(align); // Size @@ -1029,7 +1034,7 @@ namespace // Methods for(unsigned int i = 0; i < trait.m_value_indexes.size(); i ++ ) { - emit_str_usize(0); + emit_str_usize(PTR_BASE); } m_of << "\" {"; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index c603d5f1..ad5a978e 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -73,18 +73,18 @@ int main(int argc, const char* argv[]) // Create argc/argv based on input arguments auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE, "argv"); - argv_alloc->write_usize(0 * POINTER_SIZE, 0); + argv_alloc->write_usize(0 * POINTER_SIZE, Allocation::PTR_BASE); argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(opts.infile.c_str(), opts.infile.size() + 1)) }); for(size_t i = 0; i < opts.args.size(); i ++) { - argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0); + argv_alloc->write_usize((1 + i) * POINTER_SIZE, Allocation::PTR_BASE); argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(opts.args[0], ::std::strlen(opts.args[0]) + 1)) }); } // Construct argc/argv values auto val_argc = Value::new_isize(1 + opts.args.size()); auto argv_ty = ::HIR::TypeRef(RawType::I8).wrap(TypeWrapper::Ty::Pointer, 0 ).wrap(TypeWrapper::Ty::Pointer, 0); - auto val_argv = Value::new_pointer(argv_ty, 0, RelocationPtr::new_alloc(argv_alloc)); + auto val_argv = Value::new_pointer(argv_ty, Allocation::PTR_BASE, RelocationPtr::new_alloc(argv_alloc)); // Catch various exceptions from the interpreter try diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 674c7e6d..04dc13ba 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -374,8 +374,12 @@ struct MirHelpers ty = ptr_ty.get_inner(); LOG_DEBUG("Deref - " << vr << " into " << ty); - LOG_ASSERT(vr.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty); + LOG_ASSERT(vr.m_size >= POINTER_SIZE, "Deref pointer isn't large enough to be a pointer"); + // TODO: Move the metadata machinery into `deref` (or at least the logic needed to get the value size) + //auto inner_val = vr.deref(0, ty); size_t ofs = vr.read_usize(0); + LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Dereferencing invalid pointer"); + ofs -= Allocation::PTR_BASE; auto alloc = vr.get_relocation(0); // There MUST be a relocation at this point with a valid allocation. @@ -518,7 +522,7 @@ struct MirHelpers TU_ARM(c, Bytes, ce) { ty = ::HIR::TypeRef(RawType::U8).wrap(TypeWrapper::Ty::Slice, 0).wrap(TypeWrapper::Ty::Borrow, 0); Value val = Value(ty); - val.write_ptr(0, 0, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(ce.data(), ce.size()))); + val.write_ptr(0, Allocation::PTR_BASE + 0, RelocationPtr::new_ffi(FFIPointer::new_const_bytes(ce.data(), ce.size()))); val.write_usize(POINTER_SIZE, ce.size()); LOG_DEBUG(c << " = " << val); return val; @@ -526,7 +530,7 @@ struct MirHelpers TU_ARM(c, StaticString, ce) { ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0); Value val = Value(ty); - val.write_ptr(0, 0, RelocationPtr::new_string(&ce)); + val.write_ptr(0, Allocation::PTR_BASE + 0, RelocationPtr::new_string(&ce)); val.write_usize(POINTER_SIZE, ce.size()); LOG_DEBUG(c << " = " << val); return val; @@ -540,7 +544,7 @@ struct MirHelpers } if( const auto* s = this->thread.m_modtree.get_static_opt(*ce) ) { ty = s->ty.wrapped(TypeWrapper::Ty::Borrow, 0); - return Value::new_pointer(ty, 0, RelocationPtr::new_alloc(s->val.allocation)); + return Value::new_pointer(ty, Allocation::PTR_BASE + 0, RelocationPtr::new_alloc(s->val.allocation)); } LOG_ERROR("Constant::ItemAddr - " << *ce << " - not found"); } break; @@ -677,7 +681,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) // Create the pointer (can this just store into the target?) new_val = Value(dst_ty); - new_val.write_ptr(0, ofs, ::std::move(alloc)); + new_val.write_ptr(0, Allocation::PTR_BASE + ofs, ::std::move(alloc)); // - Add metadata if required if( meta != RawType::Unreachable ) { @@ -1438,7 +1442,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2); - auto ptr_val = Value::new_pointer(ptr_ty, ofs, ::std::move(alloc)); + auto ptr_val = Value::new_pointer(ptr_ty, Allocation::PTR_BASE + ofs, ::std::move(alloc)); if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) ) { @@ -1619,10 +1623,9 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_DEBUG("> Indirect call " << v); // TODO: Assert type // TODO: Assert offset/content. - assert(v.read_usize(0) == 0); + LOG_ASSERT(v.read_usize(0) == Allocation::PTR_BASE, "Function pointer value invalid - " << v); fcn_alloc_ptr = v.get_relocation(0); - if( !fcn_alloc_ptr ) - LOG_FATAL("Calling value with no relocation - " << v); + LOG_ASSERT(fcn_alloc_ptr, "Calling value with no relocation - " << v); LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer"); fcn_p = &fcn_alloc_ptr.fcn(); } @@ -1815,19 +1818,19 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 ); // TODO: Use the alignment when making an allocation? - rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(::std::move(alloc))); + rv = Value::new_pointer(rty, Allocation::PTR_BASE, RelocationPtr::new_alloc(::std::move(alloc))); } else if( link_name == "__rust_reallocate" || link_name == "__rust_realloc" ) { LOG_ASSERT(args.at(0).allocation, "__rust_reallocate first argument doesn't have an allocation"); auto alloc_ptr = args.at(0).get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); - LOG_ASSERT(ptr_ofs == 0, "__rust_reallocate with offset pointer"); auto oldsize = args.at(1).read_usize(0); // NOTE: The ordering here depends on the rust version (1.19 has: old, new, align - 1.29 has: old, align, new) auto align = args.at(true /*1.29*/ ? 2 : 3).read_usize(0); auto newsize = args.at(true /*1.29*/ ? 3 : 2).read_usize(0); LOG_DEBUG("__rust_reallocate(ptr=" << alloc_ptr << ", oldsize=" << oldsize << ", newsize=" << newsize << ", align=" << align << ")"); + LOG_ASSERT(ptr_ofs == Allocation::PTR_BASE, "__rust_reallocate with offset pointer"); LOG_ASSERT(alloc_ptr, "__rust_reallocate with no backing allocation attached to pointer"); LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer"); @@ -1843,7 +1846,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation"); auto alloc_ptr = args.at(0).get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); - LOG_ASSERT(ptr_ofs == 0, "__rust_deallocate with offset pointer"); + LOG_ASSERT(ptr_ofs == Allocation::PTR_BASE, "__rust_deallocate with offset pointer"); LOG_DEBUG("__rust_deallocate(ptr=" << alloc_ptr << ")"); LOG_ASSERT(alloc_ptr, "__rust_deallocate with no backing allocation attached to pointer"); @@ -2087,20 +2090,33 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto key = args.at(0).read_u32(0); // Get a pointer-sized value from storage - uint64_t v = key < m_thread.tls_values.size() ? m_thread.tls_values[key] : 0; - - rv = Value::new_usize(v); + if( key < m_thread.tls_values.size() ) + { + const auto& e = m_thread.tls_values[key]; + rv = Value::new_usize(e.first); + rv.create_allocation(); + if( e.second ) + { + rv.allocation->set_reloc(0, POINTER_SIZE, e.second); + } + } + else + { + // Return zero until populated + rv = Value::new_usize(0); + } } else if( link_name == "pthread_setspecific" ) { auto key = args.at(0).read_u32(0); auto v = args.at(1).read_u64(0); + auto v_reloc = args.at(1).get_relocation(0); - // Get a pointer-sized value from storage + // Store a pointer-sized value in storage if( key >= m_thread.tls_values.size() ) { m_thread.tls_values.resize(key+1); } - m_thread.tls_values[key] = v; + m_thread.tls_values[key] = ::std::make_pair(v, v_reloc); rv = Value::new_i32(0); } @@ -2337,7 +2353,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic side of this? - size_t ofs = ptr_val.read_usize(0); + size_t ofs = ptr_val.read_usize(0) - Allocation::PTR_BASE; alloc.alloc().write_value(ofs, ::std::move(data_val)); } else if( name == "atomic_load" || name == "atomic_load_relaxed" || name == "atomic_load_acq" ) @@ -2350,7 +2366,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: LOG_ASSERT(alloc, "Deref of a value with no relocation"); // TODO: Atomic lock the allocation. - size_t ofs = ptr_val.read_usize(0); + size_t ofs = ptr_val.read_usize(0) - Allocation::PTR_BASE; const auto& ty = ty_params.tys.at(0); rv = alloc.alloc().read_value(ofs, ty.get_size()); @@ -2358,7 +2374,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: else if( name == "atomic_xadd" || name == "atomic_xadd_relaxed" ) { const auto& ty_T = ty_params.tys.at(0); - auto ptr_ofs = args.at(0).read_usize(0); + auto ptr_ofs = args.at(0).read_usize(0) - Allocation::PTR_BASE; auto ptr_alloc = args.at(0).get_relocation(0); auto v = args.at(1).read_value(0, ty_T.get_size()); @@ -2379,7 +2395,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: else if( name == "atomic_xsub" || name == "atomic_xsub_relaxed" || name == "atomic_xsub_rel" ) { const auto& ty_T = ty_params.tys.at(0); - auto ptr_ofs = args.at(0).read_usize(0); + auto ptr_ofs = args.at(0).read_usize(0) - Allocation::PTR_BASE; auto ptr_alloc = args.at(0).get_relocation(0); auto v = args.at(1).read_value(0, ty_T.get_size()); @@ -2437,6 +2453,8 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { auto ptr_alloc = args.at(0).get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); + LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "`offset` with invalid pointer - " << args.at(0)); + ptr_ofs -= Allocation::PTR_BASE; auto& ofs_val = args.at(1); auto delta_counts = ofs_val.read_usize(0); @@ -2446,10 +2464,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: } rv = ::std::move(args.at(0)); - rv.write_usize(0, new_ofs); - if( ptr_alloc ) { - rv.allocation->relocations.push_back({ 0, ptr_alloc }); - } + rv.write_ptr(0, Allocation::PTR_BASE + new_ofs, ptr_alloc); } // effectively ptr::write else if( name == "move_val_init" ) @@ -2457,18 +2472,13 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: auto& ptr_val = args.at(0); auto& data_val = args.at(1); - LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "move_val_init of an address that isn't a pointer-sized value"); - // There MUST be a relocation at this point with a valid allocation. - LOG_ASSERT(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)"); - LOG_TRACE("Deref " << ptr_val << " and store " << data_val); - - auto ptr_alloc = ptr_val.get_relocation(0); - LOG_ASSERT(ptr_alloc, "Deref of a value with no relocation"); + // - TODO: What about FFI? (can't be a string or function though) + auto dst_vr = ptr_val.deref(0, ty_params.tys.at(0)); + LOG_ASSERT(dst_vr.m_alloc, "Deref didn't yeild an allocation (error?)"); + LOG_ASSERT(dst_vr.m_alloc.is_alloc(), "Deref didn't yield an allocation"); - size_t ofs = ptr_val.read_usize(0); - ptr_alloc.alloc().write_value(ofs, ::std::move(data_val)); - LOG_DEBUG(ptr_alloc.alloc()); + dst_vr.m_alloc.alloc().write_value(dst_vr.m_offset, ::std::move(data_val)); } else if( name == "uninit" ) { @@ -2643,10 +2653,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: // memcpy else if( name == "copy_nonoverlapping" ) { - auto src_ofs = args.at(0).read_usize(0); - auto src_alloc = args.at(0).get_relocation(0); - auto dst_ofs = args.at(1).read_usize(0); - auto dst_alloc = args.at(1).get_relocation(0); + //auto src_ofs = args.at(0).read_usize(0); + //auto src_alloc = args.at(0).get_relocation(0); + //auto dst_ofs = args.at(1).read_usize(0); + //auto dst_alloc = args.at(1).get_relocation(0); size_t ent_count = args.at(2).read_usize(0); size_t ent_size = ty_params.tys.at(0).get_size(); auto byte_count = ent_count * ent_size; @@ -2654,32 +2664,16 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: // A count of zero doesn't need to do any of the checks (TODO: Validate this rule) if( byte_count > 0 ) { - LOG_ASSERT(src_alloc, "Source of copy* must have an allocation"); + // TODO: is this inefficient? + auto src_val = args.at(0).read_pointer_valref_mut(0, byte_count).read_value(0, byte_count); + auto dst_vr = args.at(1).read_pointer_valref_mut(0, byte_count); + + + auto& dst_alloc = dst_vr.m_alloc; LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation"); LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation"); - switch(src_alloc.get_ty()) - { - case RelocationPtr::Ty::Allocation: { - auto v = src_alloc.alloc().read_value(src_ofs, byte_count); - LOG_DEBUG("v = " << v); - dst_alloc.alloc().write_value(dst_ofs, ::std::move(v)); - } break; - case RelocationPtr::Ty::StdString: - LOG_ASSERT(src_ofs <= src_alloc.str().size(), ""); - LOG_ASSERT(byte_count <= src_alloc.str().size(), ""); - LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), ""); - dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count); - break; - case RelocationPtr::Ty::Function: - LOG_FATAL("Attempt to copy* a function"); - break; - case RelocationPtr::Ty::FfiPointer: - LOG_ASSERT(src_alloc.ffi().layout, ""); - LOG_ASSERT(src_alloc.ffi().layout->is_valid_read(src_ofs, byte_count), ""); - dst_alloc.alloc().write_bytes(dst_ofs, reinterpret_cast<const char*>(src_alloc.ffi().ptr_value) + src_ofs, byte_count); - break; - } + dst_alloc.alloc().write_value(dst_vr.m_offset, ::std::move(src_val)); } } else @@ -2699,7 +2693,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ auto box_ptr_vr = ptr.read_pointer_valref_mut(0, POINTER_SIZE); auto ofs = box_ptr_vr.read_usize(0); auto alloc = box_ptr_vr.get_relocation(0); - if( ofs != 0 || !alloc || !alloc.is_alloc() ) { + if( ofs != Allocation::PTR_BASE || !alloc || !alloc.is_alloc() ) { LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr); } @@ -2737,7 +2731,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ auto pty = ity.wrapped(TypeWrapper::Ty::Borrow, static_cast<size_t>(::HIR::BorrowType::Move)); for(uint64_t i = 0; i < count; i ++) { - auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); + auto ptr = Value::new_pointer(pty, Allocation::PTR_BASE + ofs, ptr_reloc); if( !drop_value(ptr, ity) ) { // - This is trying to invoke custom drop glue, need to suspend this operation and come back later @@ -2749,7 +2743,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ i ++; if( i < count ) { - auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); + auto ptr = Value::new_pointer(pty, Allocation::PTR_BASE + ofs, ptr_reloc); ofs += ity.get_size(); assert(!drop_value(ptr, ity)); return false; diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 3181a116..e6830679 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -13,7 +13,7 @@ struct ThreadState { static unsigned s_next_tls_key; unsigned call_stack_depth; - ::std::vector<uint64_t> tls_values; + ::std::vector< ::std::pair<uint64_t, RelocationPtr> > tls_values; ThreadState(): call_stack_depth(0) diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 232613b7..58ad7292 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -241,6 +241,8 @@ void ValueCommonWrite::write_usize(size_t ofs, uint64_t v) void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& out_size, bool& out_is_mut) const { auto ofs = read_usize(rd_ofs); + LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Deref of invalid pointer"); + ofs -= Allocation::PTR_BASE; auto reloc = get_relocation(rd_ofs); if( !reloc ) { @@ -260,10 +262,7 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size { case RelocationPtr::Ty::Allocation: { auto& a = reloc.alloc(); - if( ofs > a.size() ) - LOG_FATAL("Out-of-bounds pointer"); - if( ofs + req_valid > a.size() ) - LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size()); + LOG_ASSERT(in_bounds(ofs, req_valid, a.size()), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << a.size() << ")"); a.check_bytes_valid( ofs, req_valid ); out_size = a.size() - ofs; out_is_mut = true; @@ -271,10 +270,7 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size } case RelocationPtr::Ty::StdString: { const auto& s = reloc.str(); - if( ofs > s.size() ) - LOG_FATAL("Out-of-bounds pointer"); - if( ofs + req_valid > s.size() ) - LOG_FATAL("Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size()); + LOG_ASSERT(in_bounds(ofs, req_valid, s.size()), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << s.size() << ")"); out_size = s.size() - ofs; out_is_mut = false; return const_cast<void*>( static_cast<const void*>(s.data() + ofs) ); @@ -283,11 +279,13 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size LOG_FATAL("read_pointer w/ function"); case RelocationPtr::Ty::FfiPointer: { const auto& f = reloc.ffi(); + size_t size = f.get_size(); + LOG_ASSERT(in_bounds(ofs, req_valid, size), "Out-of-bounds pointer (" << ofs << " + " << req_valid << " > " << size << ")"); // TODO: Validity? //if( req_valid ) // LOG_FATAL("Can't request valid data from a FFI pointer"); // TODO: Have an idea of mutability and available size from FFI - out_size = f.get_size() - ofs; + out_size = size - ofs; out_is_mut = false; return reinterpret_cast<char*>(reloc.ffi().ptr_value) + ofs; } @@ -298,6 +296,8 @@ void* ValueCommonRead::read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) { auto ofs = read_usize(rd_ofs); + LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Invalid pointer read"); + ofs -= Allocation::PTR_BASE; auto reloc = get_relocation(rd_ofs); if( !reloc ) { @@ -305,7 +305,21 @@ ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) } else { - // TODO: Validate size + // Validate size and offset are in bounds + switch(reloc.get_ty()) + { + case RelocationPtr::Ty::Allocation: + LOG_ASSERT( in_bounds(ofs, size, reloc.alloc().size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.alloc().size() ); + break; + case RelocationPtr::Ty::StdString: + LOG_ASSERT( in_bounds(ofs, size, reloc.str().size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.str().size() ); + break; + case RelocationPtr::Ty::Function: + LOG_FATAL("read_pointer_valref_mut w/ function"); + case RelocationPtr::Ty::FfiPointer: + LOG_ASSERT( in_bounds(ofs, size, reloc.ffi().get_size()), "Deref with OOB size - " << ofs << "+" << size << " > " << reloc.ffi().get_size() ); + break; + } return ValueRef(reloc, ofs, size); } } @@ -355,6 +369,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const if( this->is_freed ) LOG_ERROR("Use of freed memory " << this); LOG_DEBUG(*this); + LOG_ASSERT( in_bounds(ofs, size, this->size()), "Read out of bounds (" << ofs << "+" << size << " > " << this->size() << ")" ); // Determine if this can become an inline allocation. bool has_reloc = false; @@ -539,6 +554,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) } void Allocation::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) { + LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "Invalid pointer being written"); this->write_usize(ofs, ptr_ofs); this->set_reloc(ofs, POINTER_SIZE, ::std::move(reloc)); } @@ -643,7 +659,7 @@ Value Value::new_fnptr(const ::HIR::Path& fn_path) Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) ); assert(rv.allocation); rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_fcn(fn_path) }); - rv.allocation->data.at(0) = 0; + rv.allocation->data.at(0) = Allocation::PTR_BASE; rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes return rv; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 19df8540..ec8f1899 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -255,6 +255,9 @@ public: virtual ~Allocation() {} static AllocationHandle new_alloc(size_t size, ::std::string tag); + // NOTE: This should match the value in the MMIR backend + static const size_t PTR_BASE = 0x1000; + const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } size_t size() const { return this->data.size() * 8; } |