From b9f65d3234026d231b889abded407c4ae1e34286 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 19:16:38 +0800 Subject: standalone_miri - Fix for MIR changes, fiddling with FFI --- tools/standalone_miri/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/standalone_miri/main.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index deed08be..ed9b9267 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -74,11 +74,11 @@ 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_alloc->write_usize(0 * POINTER_SIZE, 0); - argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer { "", (void*)(opts.infile.c_str()), opts.infile.size() + 1 }) }); + 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->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi({ "", (void*)(opts.args[0]), ::std::strlen(opts.args[0]) + 1 }) }); + 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 -- cgit v1.2.3 From 50c96bfab2b0bad4845a8a6beec096239a1840ab Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 20 Jul 2019 14:19:50 +0800 Subject: Standalone MIRI - Name tags on allocations --- tools/standalone_miri/debug.hpp | 2 ++ tools/standalone_miri/main.cpp | 4 ++-- tools/standalone_miri/miri.cpp | 4 ++-- tools/standalone_miri/module_tree.cpp | 2 +- tools/standalone_miri/value.cpp | 20 +++++++++++++++----- tools/standalone_miri/value.hpp | 4 +++- 6 files changed, 25 insertions(+), 11 deletions(-) (limited to 'tools/standalone_miri/main.cpp') diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp index 4b8d7aa9..5f1dd038 100644 --- a/tools/standalone_miri/debug.hpp +++ b/tools/standalone_miri/debug.hpp @@ -112,3 +112,5 @@ struct DebugExceptionError: #define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; throw DebugExceptionTodo{}; } while(0) #define LOG_BUG(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "BUG: " << strm; abort(); } while(0) #define LOG_ASSERT(cnd,strm) do { if( !(cnd) ) { LOG_BUG("Assertion failure: " #cnd " - " << strm); } } while(0) + +#define FMT_STRING(...) (dynamic_cast<::std::stringstream&>(::std::stringstream() << __VA_ARGS__).str()) diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index ed9b9267..c603d5f1 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -72,7 +72,7 @@ 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); + auto argv_alloc = Allocation::new_alloc((1 + opts.args.size()) * POINTER_SIZE, "argv"); argv_alloc->write_usize(0 * POINTER_SIZE, 0); 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 ++) @@ -80,7 +80,7 @@ int main(int argc, const char* argv[]) argv_alloc->write_usize((1 + i) * POINTER_SIZE, 0); 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); diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 3714ed56..3d28c542 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -575,7 +575,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) assert( !this->m_stack.empty() ); assert( !this->m_stack.back().cb ); auto& cur_frame = this->m_stack.back(); - TRACE_FUNCTION_R(cur_frame.fcn.my_path, ""); + TRACE_FUNCTION_R(cur_frame.fcn.my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, ""); const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); const size_t MAX_STACK_DEPTH = 40; @@ -1613,7 +1613,7 @@ 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(Allocation::new_alloc(size))); + rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size, "__rust_alloc"))); } else if( link_name == "__rust_reallocate" || link_name == "__rust_realloc" ) { diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 82bbbf3f..29b822de 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -153,7 +153,7 @@ bool Parser::parse_one() { auto reloc_str = ::std::move(lex.consume().strval); - auto a = Allocation::new_alloc( reloc_str.size() ); + auto a = Allocation::new_alloc( reloc_str.size(), FMT_STRING("static " << p) ); //a.alloc().set_tag(); a->write_bytes(0, reloc_str.data(), reloc_str.size()); s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_alloc(::std::move(a)) }); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 0b3aa988..3a479bce 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -45,9 +45,10 @@ bool FfiLayout::is_valid_read(size_t o, size_t s) const return true; } -AllocationHandle Allocation::new_alloc(size_t size) +AllocationHandle Allocation::new_alloc(size_t size, ::std::string tag) { Allocation* rv = new Allocation(); + rv->m_tag = ::std::move(tag); rv->refcount = 1; rv->data.resize( (size + 8-1) / 8 ); // QWORDS rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes @@ -318,6 +319,11 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const } } } +::std::ostream& operator<<(::std::ostream& os, const Allocation* x) +{ + os << static_cast(x) << " A(" << x->tag() << ")"; + return os; +} void Allocation::mark_bytes_valid(size_t ofs, size_t size) { assert( ofs+size <= this->mask.size() * 8 ); @@ -345,7 +351,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const } if( has_reloc || size > sizeof(rv.direct_data.data) ) { - rv.allocation = Allocation::new_alloc(size); + rv.allocation = Allocation::new_alloc(size, FMT_STRING("Allocation::read_value(" << ofs << "," << size << ")")); rv.write_bytes(0, this->data_ptr() + ofs, size); @@ -595,14 +601,14 @@ Value::Value(::HIR::TypeRef ty) // Fallback: Make a new allocation //LOG_TRACE(" Creating allocation for " << ty); - this->allocation = Allocation::new_alloc(size); + this->allocation = Allocation::new_alloc(size, FMT_STRING(ty)); } Value Value::with_size(size_t size, bool have_allocation) { Value rv; if(have_allocation) { - rv.allocation = Allocation::new_alloc(size); + rv.allocation = Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")")); } else { @@ -662,7 +668,7 @@ Value Value::new_i32(int32_t v) { void Value::create_allocation() { assert(!this->allocation); - this->allocation = Allocation::new_alloc(this->direct_data.size); + this->allocation = Allocation::new_alloc(this->direct_data.size, "create_allocation"); if( this->direct_data.size > 0 ) this->allocation->mask[0] = this->direct_data.mask[0]; if( this->direct_data.size > 8 ) @@ -862,6 +868,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) case RelocationPtr::Ty::Allocation: { const auto& alloc = alloc_ptr.alloc(); + os << "A(" << alloc.tag() << ")@" << v.m_offset << "+" << v.m_size << " "; + auto flags = os.flags(); os << ::std::hex; for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++) @@ -915,6 +923,8 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) { const auto& alloc = *v.m_value->allocation; + os << "A(" << alloc.tag() << ")@" << v.m_offset << "+" << v.m_size << " "; + auto flags = os.flags(); os << ::std::hex; for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++) diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index e45759a7..8db17f03 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -243,16 +243,18 @@ class Allocation: public ValueCommonWrite { friend class AllocationHandle; + ::std::string m_tag; size_t refcount; // TODO: Read-only flag? bool is_freed = false; public: virtual ~Allocation() {} - static AllocationHandle new_alloc(size_t size); + static AllocationHandle new_alloc(size_t size, ::std::string tag); const uint8_t* data_ptr() const { return reinterpret_cast(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } size_t size() const { return this->data.size() * 8; } + const ::std::string& tag() const { return m_tag; } ::std::vector data; ::std::vector mask; -- cgit v1.2.3 From e14473dcce910959a3f6a3c0c683456ab0f9dd1a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 15:08:30 +0800 Subject: Standalone MIRI - Restructure so `0` is never a valid pointer value --- src/trans/codegen_mmir.cpp | 19 +++--- tools/standalone_miri/main.cpp | 6 +- tools/standalone_miri/miri.cpp | 124 +++++++++++++++++++--------------------- tools/standalone_miri/miri.hpp | 2 +- tools/standalone_miri/value.cpp | 38 ++++++++---- tools/standalone_miri/value.hpp | 3 + 6 files changed, 105 insertions(+), 87 deletions(-) (limited to 'tools/standalone_miri/main.cpp') 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 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(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(::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 tls_values; + ::std::vector< ::std::pair > 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( static_cast(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(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(this->data.data()); } uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } size_t size() const { return this->data.size() * 8; } -- cgit v1.2.3 From 6c6fd331a7bb415abd723f29cb9014dac25d50cf Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 17:23:12 +0800 Subject: Standalone MIRI - Properly tagged FFI pointers --- tools/standalone_miri/main.cpp | 7 ++++--- tools/standalone_miri/miri.cpp | 21 +++++++++++++++------ tools/standalone_miri/value.hpp | 4 ++-- 3 files changed, 21 insertions(+), 11 deletions(-) (limited to 'tools/standalone_miri/main.cpp') diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index ad5a978e..4da6c7fc 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -74,12 +74,13 @@ 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, 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)) }); + argv_alloc->relocations.push_back({ 0 * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes("argv0", 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, 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)) }); + argv_alloc->relocations.push_back({ (1 + i) * POINTER_SIZE, RelocationPtr::new_ffi(FFIPointer::new_const_bytes("argv", opts.args[i], ::std::strlen(opts.args[i]) + 1)) }); } + LOG_DEBUG("argv_alloc = " << *argv_alloc); // Construct argc/argv values auto val_argc = Value::new_isize(1 + opts.args.size()); @@ -90,7 +91,7 @@ int main(int argc, const char* argv[]) try { InterpreterThread root_thread(tree); - + ::std::vector args; args.push_back(::std::move(val_argc)); args.push_back(::std::move(val_argv)); diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 04dc13ba..e9d6d150 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -522,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, Allocation::PTR_BASE + 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("Constant::Bytes", ce.data(), ce.size()))); val.write_usize(POINTER_SIZE, ce.size()); LOG_DEBUG(c << " = " << val); return val; @@ -1035,7 +1035,14 @@ bool InterpreterThread::step_one(Value& out_thread_result) case ::MIR::eBinOp::LE: { LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); int res = 0; + // TODO: Handle comparison of the relocations too + // - If both sides have a relocation: + // > EQ/NE always valid + // > others require the same relocation + // - If one side has a relocation: + // > EQ/NE only allow zero on the non-reloc side + // > others are invalid? //const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc; //const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc; @@ -2171,7 +2178,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c } else if( link_name == "__errno_location" ) { - rv = Value::new_ffiptr(FFIPointer::new_const_bytes(&errno, sizeof(errno))); + rv = Value::new_ffiptr(FFIPointer::new_const_bytes("errno", &errno, sizeof(errno))); } else if( link_name == "syscall" ) { @@ -2258,7 +2265,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret_ptr ) { LOG_DEBUG("= \"" << ret_ptr << "\""); - rv = Value::new_ffiptr(FFIPointer::new_const_bytes(ret_ptr, strlen(ret_ptr)+1)); + rv = Value::new_ffiptr(FFIPointer::new_const_bytes("getenv", ret_ptr, strlen(ret_ptr)+1)); } else { @@ -2660,19 +2667,21 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: 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; + LOG_DEBUG("`copy_nonoverlapping`: byte_count=" << byte_count); // A count of zero doesn't need to do any of the checks (TODO: Validate this rule) if( byte_count > 0 ) { - // TODO: is this inefficient? - auto src_val = args.at(0).read_pointer_valref_mut(0, byte_count).read_value(0, byte_count); + auto src_vr = args.at(0).read_pointer_valref_mut(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"); + // TODO: is this inefficient? + auto src_val = src_vr.read_value(0, byte_count); + LOG_DEBUG("src_val = " << src_val); dst_alloc.alloc().write_value(dst_vr.m_offset, ::std::move(src_val)); } } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index ec8f1899..f4ac2d36 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -56,8 +56,8 @@ struct FFIPointer const char* tag_name; ::std::shared_ptr layout; - static FFIPointer new_const_bytes(const void* s, size_t size) { - return FFIPointer { const_cast(s), "", ::std::make_shared(FfiLayout::new_const_bytes(size)) }; + static FFIPointer new_const_bytes(const char* name, const void* s, size_t size) { + return FFIPointer { const_cast(s), name, ::std::make_shared(FfiLayout::new_const_bytes(size)) }; }; size_t get_size() const { -- cgit v1.2.3 From d9f71c09eb6f35ee5692147479a318e701106379 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 5 Aug 2019 22:27:52 +0800 Subject: Standalone MIRI - Various improvements --- tools/standalone_miri/hir_sim.cpp | 48 +++++++++++++ tools/standalone_miri/hir_sim.hpp | 1 + tools/standalone_miri/main.cpp | 2 + tools/standalone_miri/miri.cpp | 123 ++++++++++++++++++++++++++++++++-- tools/standalone_miri/module_tree.cpp | 45 ++++++++++++- tools/standalone_miri/module_tree.hpp | 11 +-- tools/standalone_miri/value.cpp | 1 + tools/standalone_miri/value.hpp | 37 +++++----- 8 files changed, 236 insertions(+), 32 deletions(-) (limited to 'tools/standalone_miri/main.cpp') diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 085c045f..a666dfee 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -77,6 +77,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const return 0; case RawType::Composite: // NOTE: Don't care if the type has metadata + LOG_ASSERT(this->composite_type->populated, "Getting size of non-defined type - " << *this); return this->composite_type->size; case RawType::Unreachable: LOG_BUG("Attempting to get size of an unreachable type, " << *this); @@ -111,6 +112,53 @@ size_t HIR::TypeRef::get_size(size_t ofs) const throw ""; } } +size_t HIR::TypeRef::get_align(size_t ofs) const +{ + if( const auto* w = this->get_wrapper(ofs) ) + { + LOG_TODO("get_align " << *this); + } + else + { + switch(this->inner_type) + { + case RawType::Unit: + return 1; + case RawType::Composite: + // NOTE: Don't care if the type has metadata + LOG_ASSERT(this->composite_type->populated, "Getting alignment of non-defined type - " << *this); + return this->composite_type->alignment; + case RawType::TraitObject: + case RawType::Str: + return 1; + case RawType::U8: case RawType::I8: + return 1; + case RawType::U16: case RawType::I16: + return 2; + case RawType::U32: case RawType::I32: + return 4; + case RawType::U64: case RawType::I64: + return 8; + case RawType::U128: case RawType::I128: + return 16; + + case RawType::Bool: + return 1; + case RawType::Char: + return 4; + + case RawType::F32: + return 4; + case RawType::F64: + return 8; + + case RawType::Function: // This should probably be invalid? + case RawType::USize: + case RawType::ISize: + return POINTER_SIZE; + } + } +} bool HIR::TypeRef::has_slice_meta(size_t& out_inner_size) const { if( const auto* w = this->get_wrapper() ) diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index cedbf3b9..9483f1bb 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -128,6 +128,7 @@ namespace HIR { } size_t get_size(size_t ofs=0) const; + size_t get_align(size_t ofs=0) const; // Returns true if this (unsized) type is a wrapper around a slice // - Fills `out_inner_size` with the size of the slice element diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 4da6c7fc..8ee118f7 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -51,6 +51,7 @@ int main(int argc, const char* argv[]) try { tree.load_file(opts.infile); + tree.validate(); } catch(const DebugExceptionTodo& /*e*/) { @@ -71,6 +72,7 @@ int main(int argc, const char* argv[]) return 1; } + // 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, Allocation::PTR_BASE); diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 2deb421b..906949b6 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1487,11 +1487,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) alloc = RelocationPtr::new_alloc( v.m_value->allocation ); } size_t ofs = v.m_offset; - assert(ty.get_meta_type() == RawType::Unreachable); + //LOG_ASSERT(ty.get_meta_type() == RawType::Unreachable, "Dropping an unsized type with Statement::Drop - " << ty); - auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, 2); + auto ptr_ty = ty.wrapped(TypeWrapper::Ty::Borrow, /*BorrowTy::Unique*/2); auto ptr_val = Value::new_pointer(ptr_ty, Allocation::PTR_BASE + ofs, ::std::move(alloc)); + if( v.m_metadata ) + { + ptr_val.write_value(POINTER_SIZE, *v.m_metadata); + } if( !drop_value(ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW) ) { @@ -1805,8 +1809,17 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve if( fcn.external.link_name != "" ) { - // External function! - return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + // TODO: Search for a function with both code and this link name + if(const auto* ext_fcn = m_modtree.get_ext_function(fcn.external.link_name.c_str())) + { + this->m_stack.push_back(StackFrame(*ext_fcn, ::std::move(args))); + return false; + } + else + { + // External function! + return this->call_extern(ret, fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + } } this->m_stack.push_back(StackFrame(fcn, ::std::move(args))); @@ -1932,6 +1945,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c return false; } } + else if( link_name == "panic_impl" ) + { + LOG_TODO("panic_impl"); + } else if( link_name == "__rust_start_panic" ) { LOG_TODO("__rust_start_panic"); @@ -2121,6 +2138,22 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + else if( link_name == "pthread_attr_setstacksize" ) + { + // Lie and return succeess + rv = Value::new_i32(0); + } + else if( link_name == "pthread_create" ) + { + auto thread_handle_out = args.at(0).read_pointer_valref_mut(0, sizeof(pthread_t)); + auto attrs = args.at(1).read_pointer_const(0, sizeof(pthread_attr_t)); + auto fcn_path = args.at(2).get_relocation(0).fcn(); + LOG_ASSERT(args.at(2).read_usize(0) == Allocation::PTR_BASE, ""); + auto arg = args.at(3); + LOG_NOTICE("TODO: pthread_create(" << thread_handle_out << ", " << attrs << ", " << fcn_path << ", " << arg << ")"); + // TODO: Create a new interpreter context with this thread, use co-operative scheduling + rv = Value::new_i32(EPERM); + } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { rv = Value::new_i32(0); @@ -2230,6 +2263,15 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c errno = ENOSYS; rv = Value::new_i64(-1); } + else if( link_name == "dlsym" ) + { + auto handle = args.at(0).read_usize(0); + const char* name = FfiHelpers::read_cstr(args.at(1), 0); + + LOG_DEBUG("dlsym(0x" << ::std::hex << handle << ", '" << name << "')"); + LOG_NOTICE("dlsym stubbed to zero"); + rv = Value::new_usize(0); + } #endif // std C else if( link_name == "signal" ) @@ -2347,6 +2389,21 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = Value::with_size(POINTER_SIZE, false); rv.write_usize(0, it - type_ids.begin()); } + else if( name == "type_name" ) + { + const auto& ty_T = ty_params.tys.at(0); + + static ::std::map s_type_names; + auto it = s_type_names.find(ty_T); + if( it == s_type_names.end() ) + { + it = s_type_names.insert( ::std::make_pair(ty_T, FMT_STRING(ty_T)) ).first; + } + + rv = Value::with_size(2*POINTER_SIZE, /*needs_alloc=*/true); + rv.write_ptr(0*POINTER_SIZE, Allocation::PTR_BASE, RelocationPtr::new_string(&it->second)); + rv.write_usize(1*POINTER_SIZE, 0); + } else if( name == "discriminant_value" ) { const auto& ty = ty_params.tys.at(0); @@ -2582,7 +2639,12 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: } else if( ity->inner_type == RawType::TraitObject ) { - LOG_TODO("size_of_val - Trait Object - " << ty); + auto vtable_ty = meta_ty.get_inner(); + LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")"); + auto vtable = val.deref(POINTER_SIZE, vtable_ty); + LOG_DEBUG("> vtable = " << vtable); + auto size = vtable.read_usize(1*POINTER_SIZE); + flex_size = size; } else { @@ -2596,6 +2658,40 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv.write_usize(0, ty.get_size()); } } + else if( name == "min_align_of_val" ) + { + /*const*/ auto& val = args.at(0); + const auto& ty = ty_params.tys.at(0); + rv = Value(::HIR::TypeRef(RawType::USize)); + size_t fixed_size = 0; // unused + size_t flex_align = 0; + if( const auto* ity = ty.get_unsized_type(fixed_size) ) + { + if( const auto* w = ity->get_wrapper() ) + { + LOG_ASSERT(w->type == TypeWrapper::Ty::Slice, "align_of_val on wrapped type that isn't a slice - " << *ity); + flex_align = ity->get_inner().get_align(); + } + else if( ity->inner_type == RawType::Str ) + { + flex_align = 1; + } + else if( ity->inner_type == RawType::TraitObject ) + { + const auto meta_ty = ty.get_meta_type(); + auto vtable_ty = meta_ty.get_inner(); + LOG_DEBUG("> vtable_ty = " << vtable_ty << " (size= " << vtable_ty.get_size() << ")"); + auto vtable = val.deref(POINTER_SIZE, vtable_ty); + LOG_DEBUG("> vtable = " << vtable); + flex_align = vtable.read_usize(2*POINTER_SIZE); + } + else + { + LOG_BUG("Inner unsized type unknown - " << *ity); + } + } + rv.write_usize(0, ::std::max( ty.get_align(), flex_align )); + } else if( name == "drop_in_place" ) { auto& val = args.at(0); @@ -2739,6 +2835,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: // TODO: Use a ValueRef instead? bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow/*=false*/) { + TRACE_FUNCTION_R(ptr << ": " << ty << (is_shallow ? " (shallow)" : ""), ""); // TODO: After the drop is done, flag the backing allocation for `ptr` as freed if( is_shallow ) { @@ -2836,7 +2933,21 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ } else if( ty.inner_type == RawType::TraitObject ) { - LOG_TODO("Drop - " << ty << " - trait object"); + // Get the drop glue from the vtable (first entry) + auto inner_ptr = ptr.read_value(0, POINTER_SIZE); + auto vtable = ptr.deref(POINTER_SIZE, ty.get_meta_type().get_inner()); + auto drop_r = vtable.get_relocation(0); + if( drop_r ) + { + LOG_ASSERT(drop_r.get_ty() == RelocationPtr::Ty::Function, ""); + auto fcn = drop_r.fcn(); + static Value tmp; + return this->call_path(tmp, fcn, { ::std::move(inner_ptr) }); + } + else + { + // None + } } else { diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 29b822de..7fab4d88 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -57,6 +57,24 @@ void ModuleTree::load_file(const ::std::string& path) // Keep going! } } +void ModuleTree::validate() +{ + TRACE_FUNCTION_R("", ""); + for(const auto& dt : this->data_types) + { + //LOG_ASSERT(dt.second->populated, "Type " << dt.first << " never defined"); + } + + for(const auto& fcn : this->functions) + { + // TODO: This doesn't actually happen yet (this combination can't be parsed) + if( fcn.second.external.link_name != "" && !fcn.second.m_mir.blocks.empty() ) + { + LOG_DEBUG(fcn.first << " = '" << fcn.second.external.link_name << "'"); + ext_functions.insert(::std::make_pair( fcn.second.external.link_name, &fcn.second )); + } + } +} // Parse a single item from a .mir file bool Parser::parse_one() { @@ -185,6 +203,7 @@ bool Parser::parse_one() //LOG_TRACE("type " << p); auto rv = DataType {}; + rv.populated = true; rv.my_path = p; lex.check_consume('{'); @@ -1259,15 +1278,29 @@ RawType Parser::parse_core_type() } lex.consume_if(')'); + // Ignore marker traits. + auto rv = ::HIR::TypeRef(RawType::TraitObject); if( base_trait != ::HIR::GenericPath() ) { // Generate vtable path auto vtable_path = base_trait; vtable_path.m_simplepath.ents.back() += "#vtable"; - // - TODO: Associated types? + if( atys.size() > 1 ) + { + LOG_TODO("Handle multiple ATYs in vtable path"); + } + else if( atys.size() == 1 ) + { + vtable_path.m_params.tys.push_back( ::std::move(atys[0].second) ); + } + // - TODO: Associated types? (Need to ensure ordering is correct) rv.composite_type = this->get_composite( ::std::move(vtable_path) ); } + else + { + // TODO: vtable for empty trait? + } return rv; } else if( lex.next() == TokenClass::Ident ) @@ -1286,6 +1319,7 @@ const DataType* Parser::get_composite(::HIR::GenericPath gp) { // TODO: Later on need to check if the type is valid. auto v = ::std::make_unique(DataType {}); + v->populated = false; v->my_path = gp; auto ir = tree.data_types.insert(::std::make_pair( ::std::move(gp), ::std::move(v)) ); it = ir.first; @@ -1315,6 +1349,15 @@ const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const } return &it->second; } +const Function* ModuleTree::get_ext_function(const char* name) const +{ + auto it = ext_functions.find(name); + if( it == ext_functions.end() ) + { + return nullptr; + } + return it->second; +} Static& ModuleTree::get_static(const ::HIR::Path& p) { auto it = statics.find(p); diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index 653104df..6637c2d4 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -48,14 +48,18 @@ class ModuleTree // Hack: Tuples are stored as `::""::` ::std::map<::HIR::GenericPath, ::std::unique_ptr> data_types; + + ::std::map<::std::string, const Function*> ext_functions; public: ModuleTree(); void load_file(const ::std::string& path); + void validate(); ::HIR::SimplePath find_lang_item(const char* name) const; const Function& get_function(const ::HIR::Path& p) const; const Function* get_function_opt(const ::HIR::Path& p) const; + const Function* get_ext_function(const char* name) const; Static& get_static(const ::HIR::Path& p); Static* get_static_opt(const ::HIR::Path& p); @@ -67,16 +71,15 @@ public: // struct/union/enum struct DataType { + bool populated; ::HIR::GenericPath my_path; - // TODO: Store the name of this type for logging? - - // TODO: Metadata type! (indicates an unsized wrapper) - // TODO: Drop glue size_t alignment; size_t size; + // Drop glue ::HIR::Path drop_glue; + // Metadata type! (indicates an unsized wrapper) ::HIR::TypeRef dst_meta; // Offset and datatype diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 319f516b..16842d82 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -299,6 +299,7 @@ ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Invalid pointer read"); ofs -= Allocation::PTR_BASE; auto reloc = get_relocation(rd_ofs); + LOG_DEBUG("ValueCommonRead::read_pointer_valref_mut(" << ofs << "+" << size << ", reloc=" << reloc << ")"); if( !reloc ) { LOG_ERROR("Getting ValRef to null pointer (no relocation)"); diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index f4ac2d36..1ba3382e 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -363,42 +363,41 @@ struct ValueRef: size_t m_size; // Size in bytes of the referenced value ::std::shared_ptr m_metadata; + static bool in_bounds(size_t ofs, size_t size, size_t max_size) { + if( size == 0 ) { + return ofs <= max_size; + } + if( ofs > 0 && !(ofs < max_size) ) + return false; + if( !(size <= max_size) ) + return false; + return ofs + size <= max_size; + } + ValueRef(RelocationPtr ptr, size_t ofs, size_t size): m_alloc(ptr), m_value(nullptr), m_offset(ofs), m_size(size) { - struct H { - static bool in_bounds(size_t ofs, size_t size, size_t max_size) { - if( size == 0 ) { - return ofs <= max_size; - } - if( ofs > 0 && !(ofs < max_size) ) - return false; - if( !(size <= max_size) ) - return false; - return ofs + size <= max_size; - } - }; if( m_alloc ) { switch(m_alloc.get_ty()) { case RelocationPtr::Ty::Allocation: - if( !H::in_bounds(ofs, size, m_alloc.alloc().size()) ) + if( !in_bounds(ofs, size, m_alloc.alloc().size()) ) { LOG_ERROR("ValueRef exceeds bounds of " << m_alloc << " - " << ofs << "+" << size << " > " << m_alloc.alloc().size()); } break; case RelocationPtr::Ty::StdString: - if( !H::in_bounds(ofs, size, m_alloc.str().size()) ) + if( !in_bounds(ofs, size, m_alloc.str().size()) ) { LOG_ERROR("ValueRef exceeds bounds of string - " << ofs << "+" << size << " > " << m_alloc.str().size()); } break; case RelocationPtr::Ty::FfiPointer: - if( !H::in_bounds(ofs, size, m_alloc.ffi().get_size()) ) + if( !in_bounds(ofs, size, m_alloc.ffi().get_size()) ) { LOG_ERROR("ValueRef exceeds bounds of FFI buffer - " << ofs << "+" << size << " > " << m_alloc.ffi().get_size()); } @@ -482,9 +481,7 @@ struct ValueRef: void read_bytes(size_t ofs, void* dst, size_t size) const { if( size == 0 ) return ; - assert(ofs < m_size); - assert(size <= m_size); - assert(ofs+size <= m_size); + LOG_ASSERT(in_bounds(ofs, size, m_size), "read_bytes(" << ofs << "+" << size << " > " << m_size <<")"); if( m_alloc ) { switch(m_alloc.get_ty()) { @@ -507,9 +504,7 @@ struct ValueRef: void check_bytes_valid(size_t ofs, size_t size) const { if( size == 0 ) return ; - assert(ofs < m_size); - assert(size <= m_size); - assert(ofs+size <= m_size); + LOG_ASSERT(in_bounds(ofs, size, m_size), "check_bytes_valid(" << ofs << "+" << size << " > " << m_size <<")"); if( m_alloc ) { switch(m_alloc.get_ty()) { -- cgit v1.2.3