diff options
author | John Hodge <tpg@mutabah.net> | 2018-03-07 22:09:19 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-03-17 18:52:16 +0800 |
commit | 4dca93d85c1cf0753183d7e4156ff925ac514b4d (patch) | |
tree | 5badd80fd8b8f346935331340651ec4e6a788041 /tools | |
parent | 912f54efc564f1928b70349960e0eee6020242fe (diff) | |
download | mrust-4dca93d85c1cf0753183d7e4156ff925ac514b4d.tar.gz |
Standalone MIRI - Coming along slowly.
Diffstat (limited to 'tools')
-rw-r--r-- | tools/standalone_miri/hir_sim.cpp | 41 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.hpp | 2 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 257 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 2 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 152 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 77 |
6 files changed, 429 insertions, 102 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index e1b7faf8..85c05459 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -74,7 +74,9 @@ size_t HIR::TypeRef::get_size(size_t ofs) const { return POINTER_SIZE; } - LOG_TODO("Handle unsized struct " << *this); + + // TODO: Ideally, this inner type wouldn't be unsized itself... but checking that would be interesting. + return POINTER_SIZE + this->composite_type->dst_meta.get_size(); } else if( this->inner_type == RawType::Str ) return POINTER_SIZE*2; @@ -94,7 +96,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const return POINTER_SIZE; } case TypeWrapper::Ty::Slice: - throw "Invalid"; + LOG_BUG("Getting size of a slice - " << *this); } throw ""; } @@ -128,6 +130,40 @@ HIR::TypeRef HIR::TypeRef::get_inner() const ity.wrappers.erase(ity.wrappers.begin()); return ity; } +HIR::TypeRef HIR::TypeRef::wrap(TypeWrapper::Ty ty, size_t size) const +{ + auto rv = *this; + rv.wrappers.insert(rv.wrappers.begin(), { ty, size }); + return rv; +} +const HIR::TypeRef* HIR::TypeRef::get_meta_type() const +{ + static ::HIR::TypeRef static_usize = ::HIR::TypeRef(RawType::USize); + if( this->wrappers.empty() ) + { + switch(this->inner_type) + { + case RawType::Composite: + if( this->composite_type->dst_meta == RawType::Unreachable ) + return nullptr; + return &this->composite_type->dst_meta; + case RawType::TraitObject: + LOG_TODO("get_meta_type on TraitObject - " << *this); + case RawType::Str: + return &static_usize; + default: + return nullptr; + } + } + else if( this->wrappers[0].type == TypeWrapper::Ty::Slice ) + { + return &static_usize; + } + else + { + return nullptr; + } +} HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const { @@ -135,6 +171,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const { if( this->inner_type == RawType::Composite ) { + LOG_ASSERT(idx < this->composite_type->fields.size(), "Field " << idx << " out of bounds in type " << *this); ofs = this->composite_type->fields.at(idx).first; return this->composite_type->fields.at(idx).second; } diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 4b111d3e..504f0450 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -119,7 +119,9 @@ namespace HIR { size_t get_size(size_t ofs=0) const; bool has_slice_meta() const; // The attached metadata is a count + const TypeRef* get_meta_type() const; TypeRef get_inner() const; + TypeRef wrap(TypeWrapper::Ty ty, size_t size) const; TypeRef get_field(size_t idx, size_t& ofs) const; bool operator==(const RawType& x) const { diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 703a6fab..d6cf6702 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -60,7 +60,7 @@ int main(int argc, const char* argv[]) catch(const DebugExceptionError& /*e*/) { ::std::cerr << "Error encountered" << ::std::endl; - throw; + return 1; } return 0; @@ -291,7 +291,8 @@ struct Ops { Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) { Value ret; - TRACE_FUNCTION_R(path, path << " = " << ret); + + const auto& fcn = modtree.get_function(path); // TODO: Support overriding certain functions @@ -304,19 +305,20 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } } - const auto& fcn = modtree.get_function(path); - for(size_t i = 0; i < args.size(); i ++) - { - LOG_DEBUG("- Argument(" << i << ") = " << args[i]); - } - if( fcn.external.link_name != "" ) { // External function! ret = MIRI_Invoke_Extern(fcn.external.link_name, fcn.external.link_abi, ::std::move(args)); + LOG_DEBUG(path << " = " << ret); return ret; } + TRACE_FUNCTION_R(path, path << " = " << ret); + for(size_t i = 0; i < args.size(); i ++) + { + LOG_DEBUG("- Argument(" << i << ") = " << args[i]); + } + ret = Value(fcn.ret_ty == RawType::Unreachable ? ::HIR::TypeRef() : fcn.ret_ty); struct State @@ -393,10 +395,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar TU_ARM(lv, Field, e) { ::HIR::TypeRef composite_ty; auto base_val = get_value_and_type(*e.val, composite_ty); - LOG_DEBUG("Field - " << composite_ty); + // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata size_t inner_ofs; ty = composite_ty.get_field(e.field_index, inner_ofs); + LOG_DEBUG("Field - " << composite_ty << "#" << e.field_index << " = @" << inner_ofs << " " << ty); base_val.m_offset += inner_ofs; + if( !ty.get_meta_type() ) + { + LOG_ASSERT(base_val.m_size >= ty.get_size(), "Field didn't fit in the value - " << ty.get_size() << " required, but " << base_val.m_size << " avail"); + base_val.m_size = ty.get_size(); + } return base_val; } TU_ARM(lv, Downcast, e) { @@ -413,33 +421,46 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar ::HIR::TypeRef ptr_ty; auto val = get_value_and_type(*e.val, ptr_ty); ty = ptr_ty.get_inner(); - // TODO: Slices and slice-like types have the same logic. - if( ty == RawType::Str || (!ty.wrappers.empty() && ty.wrappers.front().type == TypeWrapper::Ty::Slice) ) + LOG_DEBUG("val = " << val); + + LOG_ASSERT(val.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty); + size_t ofs = val.read_usize(0); + + // There MUST be a relocation at this point with a valid allocation. + auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation; + LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)"); + LOG_ASSERT(val_alloc.is_alloc(), "Deref of a value with a non-data allocation"); + LOG_TRACE("Deref " << val_alloc.alloc() << " + " << ofs << " to give value of type " << ty); + auto alloc = val_alloc.alloc().get_relocation(val.m_offset); + LOG_ASSERT(alloc, "Deref of a value with no relocation"); + if( alloc.is_alloc() ) + { + LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc()); + } + size_t size; + + const auto* meta_ty = ty.get_meta_type(); + ::std::shared_ptr<Value> meta_val; + // If the type has metadata, store it. + if( meta_ty ) { - LOG_ASSERT(val.m_size == 2*POINTER_SIZE, "Deref of " << ty << " that isn't a fat-pointer sized value"); - // There MUST be a relocation at this point with a valid allocation. - auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation; - LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)"); - LOG_TRACE("Deref " << val_alloc.alloc()); - auto alloc = val_alloc.alloc().get_relocation(val.m_offset); - LOG_ASSERT(alloc, "Deref of a value with no relocation"); - size_t ofs = val.read_usize(0); - size_t size = val.read_usize(POINTER_SIZE); - return ValueRef(::std::move(alloc), ofs, size); + auto meta_size = meta_ty->get_size(); + LOG_ASSERT(val.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size"); + meta_val = ::std::make_shared<Value>( val.read_value(POINTER_SIZE, meta_size) ); + + // TODO: Get a more sane size from the metadata + LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + size = alloc.get_size() - ofs; } - // TODO: Trait objects and trait-object likes else { - LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value"); - // There MUST be a relocation at this point with a valid allocation. - auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation; - LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)"); - LOG_TRACE("Deref " << val_alloc.alloc()); - auto alloc = val_alloc.alloc().get_relocation(val.m_offset); - LOG_ASSERT(alloc, "Deref of a value with no relocation"); - size_t ofs = val.read_usize(0); - return ValueRef(::std::move(alloc), ofs, ty.get_size()); + LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << val.m_size << ") - " << val << ": " << ptr_ty); + size = ty.get_size(); } + + auto rv = ValueRef(::std::move(alloc), ofs, size); + rv.m_metadata = ::std::move(meta_val); + return rv; } break; } throw ""; @@ -624,15 +645,17 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar else LOG_DEBUG("- alloc=" << alloc); size_t ofs = src_base_value.m_offset; + const auto* meta = src_ty.get_meta_type(); bool is_slice_like = src_ty.has_slice_meta(); src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) }); new_val = Value(src_ty); // ^ Pointer value new_val.write_usize(0, ofs); - if( is_slice_like ) + if( meta ) { - new_val.write_usize(POINTER_SIZE, src_base_value.m_size); + LOG_ASSERT(src_base_value.m_metadata, "Borrow of an unsized value, but no metadata avaliable"); + new_val.write_value(POINTER_SIZE, *src_base_value.m_metadata); } // - Add the relocation after writing the value (writing clears the relocations) new_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); @@ -801,11 +824,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar case RawType::Str: LOG_FATAL("Cast of unsized type - " << src_ty); case RawType::Function: - LOG_ASSERT(re.type.inner_type == RawType::USize, ""); + LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type); new_val = src_value.read_value(0, re.type.get_size()); break; case RawType::Char: - LOG_TODO("Cast char to integer (only u32)"); + LOG_ASSERT(re.type.inner_type == RawType::U32, "Char can only be casted to u32, instead " << re.type); + new_val = src_value.read_value(0, 4); + break; case RawType::Unit: LOG_FATAL("Cast of unit"); case RawType::Composite: { @@ -964,8 +989,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar 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; - auto reloc_l = alloc_l ? alloc_l.alloc().get_relocation(v_l.m_offset) : AllocationPtr(); - auto reloc_r = alloc_r ? alloc_r.alloc().get_relocation(v_r.m_offset) : AllocationPtr(); + auto reloc_l = alloc_l ? v_l.get_relocation(v_l.m_offset) : AllocationPtr(); + auto reloc_r = alloc_r ? v_r.get_relocation(v_r.m_offset) : AllocationPtr(); if( reloc_l != reloc_r ) { @@ -1179,7 +1204,17 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar LOG_TODO(stmt); } break; TU_ARM(se.src, MakeDst, re) { - LOG_TODO(stmt); + // - Get target type, just for some assertions + ::HIR::TypeRef dst_ty; + state.get_value_and_type(se.dst, dst_ty); + new_val = Value(dst_ty); + + auto ptr = state.param_to_value(re.ptr_val ); + auto meta = state.param_to_value(re.meta_val); + LOG_DEBUG("ty=" << dst_ty << ", ptr=" << ptr << ", meta=" << meta); + + new_val.write_value(0, ::std::move(ptr)); + new_val.write_value(POINTER_SIZE, ::std::move(meta)); } break; TU_ARM(se.src, Tuple, re) { ::HIR::TypeRef dst_ty; @@ -1227,6 +1262,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar const auto& data_ty = state.modtree.get_composite(re.path); auto dst_ty = ::HIR::TypeRef(&data_ty); new_val = Value(dst_ty); + LOG_DEBUG("Variant " << new_val); // Three cases: // - Unions (no tag) // - Data enums (tag and data) @@ -1238,6 +1274,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar new_val.write_value(fld.first, state.param_to_value(re.val)); } + LOG_DEBUG("Variant " << new_val); if( var.base_field != SIZE_MAX ) { ::HIR::TypeRef tag_ty; @@ -1249,6 +1286,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar { // Union, no tag } + LOG_DEBUG("Variant " << new_val); } break; TU_ARM(se.src, Struct, re) { const auto& data_ty = state.modtree.get_composite(re.path); @@ -1274,14 +1312,35 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar TU_ARM(stmt, Drop, se) { if( se.flag_idx == ~0u || state.drop_flags.at(se.flag_idx) ) { - auto drop_value = [](ValueRef v, const ::HIR::TypeRef& ty) { + auto drop_value = [&](ValueRef v, const ::HIR::TypeRef& ty) { if( ty.wrappers.empty() ) { if( ty.inner_type == RawType::Composite ) { if( ty.composite_type->drop_glue != ::HIR::Path() ) { - LOG_TODO("Drop - " << ty); + LOG_DEBUG("Drop - " << ty); + + // - Take a pointer to the inner + auto alloc = v.m_alloc; + if( !alloc ) + { + if( !v.m_value->allocation ) + { + v.m_value->create_allocation(); + } + alloc = AllocationPtr(v.m_value->allocation); + } + size_t ofs = v.m_offset; + assert(!ty.get_meta_type()); + + auto ptr_ty = ty.wrap(TypeWrapper::Ty::Borrow, 2); + + auto ptr_val = Value(ptr_ty); + ptr_val.write_usize(0, ofs); + ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); + + MIRI_Invoke(modtree, ty.composite_type->drop_glue, { ptr_val }); } else { @@ -1290,7 +1349,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } else if( ty.inner_type == RawType::TraitObject ) { - LOG_TODO("Drop - " << ty); + LOG_TODO("Drop - " << ty << " - trait object"); } else { @@ -1312,7 +1371,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar // TODO: Arrays else { - LOG_TODO("Drop - " << ty); + LOG_TODO("Drop - " << ty << " - array"); } }; @@ -1384,6 +1443,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar // Read the value bytes ::std::vector<char> tmp( var.tag_data.size() ); v.read_bytes(tag_ofs, const_cast<char*>(tmp.data()), tmp.size()); + if( v.get_relocation(tag_ofs) ) + continue ; if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 ) { found_target = i; @@ -1435,8 +1496,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } LOG_DEBUG("Call " << *fcn_p); - state.write_lvalue(te.ret_val, MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args))); - LOG_DEBUG("resume " << path); + auto v = MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)); + LOG_DEBUG(te.ret_val << " = " << v << " (resume " << path << ")"); + state.write_lvalue(te.ret_val, ::std::move(v)); } bb_idx = te.ret_block; } continue; @@ -1448,25 +1510,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args) { - // WinAPI functions used by libstd - if( link_name == "AddVectoredExceptionHandler" ) - { - LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null"); - auto rv = Value(::HIR::TypeRef(RawType::USize)); - rv.write_usize(0, 1); - return rv; - } -#ifdef _WIN32 - else if( link_name == "GetModuleHandleW" ) - { - const void* arg0 = (args.at(0).allocation ? args.at(0).allocation.alloc().data_ptr() : nullptr); - //extern void* GetModuleHandleW(const void* s); - - return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", GetModuleHandleW(static_cast<LPCWSTR>(arg0)) }); - } -#endif - // Allocators! - else if( link_name == "__rust_allocate" ) + if( link_name == "__rust_allocate" ) { auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); @@ -1474,7 +1518,8 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab ::HIR::TypeRef rty { RawType::Unit }; rty.wrappers.push_back({ TypeWrapper::Ty::Pointer, 0 }); Value rv = Value(rty); - // TODO: Use the alignment when making an allocation. + rv.write_usize(0, 0); + // TODO: Use the alignment when making an allocation? rv.allocation.alloc().relocations.push_back({ 0, Allocation::new_alloc(size) }); return rv; } @@ -1493,10 +1538,76 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_reallocate with no backing allocation attached to pointer"); auto& alloc = alloc_ptr.alloc(); // TODO: Check old size and alignment against allocation. - alloc.data.resize(newsize); + alloc.data.resize( (newsize + 8-1) / 8 ); + alloc.mask.resize( (newsize + 8-1) / 8 ); // TODO: Should this instead make a new allocation to catch use-after-free? return ::std::move(args.at(0)); } +#ifdef _WIN32 + // WinAPI functions used by libstd + else if( link_name == "AddVectoredExceptionHandler" ) + { + LOG_DEBUG("Call `AddVectoredExceptionHandler` - Ignoring and returning non-null"); + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.write_usize(0, 1); + return rv; + } + else if( link_name == "GetModuleHandleW" ) + { + LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); + const auto& tgt_alloc = args.at(0).allocation.alloc().get_relocation(0); + const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr); + //extern void* GetModuleHandleW(const void* s); + if(arg0) { + LOG_DEBUG("GetModuleHandleW(" << tgt_alloc.alloc() << ")"); + } + else { + LOG_DEBUG("GetModuleHandleW(NULL)"); + } + + auto rv = GetModuleHandleW(static_cast<LPCWSTR>(arg0)); + if(rv) + { + return Value::new_ffiptr(FFIPointer { "GetModuleHandleW", rv }); + } + else + { + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.create_allocation(); + rv.write_usize(0,0); + return rv; + } + } + else if( link_name == "GetProcAddress" ) + { + LOG_ASSERT(args.at(0).allocation.is_alloc(), ""); + const auto& handle_alloc = args.at(0).allocation.alloc().get_relocation(0); + LOG_ASSERT(args.at(1).allocation.is_alloc(), ""); + const auto& sym_alloc = args.at(1).allocation.alloc().get_relocation(0); + + // TODO: Ensure that first arg is a FFI pointer with offset+size of zero + void* handle = handle_alloc.ffi().ptr_value; + // TODO: Get either a FFI data pointer, or a inner data pointer + const void* symname = sym_alloc.alloc().data_ptr(); + // TODO: Sanity check that it's a valid c string within its allocation + LOG_DEBUG("FFI GetProcAddress(" << handle << ", \"" << static_cast<const char*>(symname) << "\")"); + + auto rv = GetProcAddress(static_cast<HMODULE>(handle), static_cast<LPCSTR>(symname)); + + if( rv ) + { + return Value::new_ffiptr(FFIPointer { "GetProcAddress", rv }); + } + else + { + auto rv = Value(::HIR::TypeRef(RawType::USize)); + rv.create_allocation(); + rv.write_usize(0,0); + return rv; + } + } +#endif + // Allocators! else { LOG_TODO("Call external function " << link_name); @@ -1558,16 +1669,15 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name auto r = ptr_val.allocation.alloc().get_relocation(0); auto orig_ofs = ptr_val.read_usize(0); - auto delta_ofs = ptr_val.read_usize(0); - auto new_ofs = orig_ofs + delta_ofs; + auto delta_counts = ofs_val.read_usize(0); + auto new_ofs = orig_ofs + delta_counts * ty_params.tys.at(0).get_size(); if(POINTER_SIZE != 8) { new_ofs &= 0xFFFFFFFF; } - ptr_val.write_usize(0, new_ofs); ptr_val.allocation.alloc().relocations.push_back({ 0, r }); - return ptr_val; + rv = ::std::move(ptr_val); } // effectively ptr::write else if( name == "move_val_init" ) @@ -1579,17 +1689,18 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name // 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.allocation.alloc()); + LOG_TRACE("Deref " << ptr_val << " and store " << data_val); auto alloc = ptr_val.allocation.alloc().get_relocation(0); LOG_ASSERT(alloc, "Deref of a value with no relocation"); size_t ofs = ptr_val.read_usize(0); const auto& ty = ty_params.tys.at(0); alloc.alloc().write_value(ofs, ::std::move(data_val)); + LOG_DEBUG(alloc.alloc()); } else if( name == "uninit" ) { - return Value(ty_params.tys.at(0)); + rv = Value(ty_params.tys.at(0)); } // ---------------------------------------------------------------- // Checked arithmatic @@ -1667,7 +1778,9 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name auto src_alloc = args.at(0).allocation.alloc().get_relocation(0); auto dst_ofs = args.at(1).read_usize(0); auto dst_alloc = args.at(1).allocation.alloc().get_relocation(0); - auto byte_count = args.at(2).read_usize(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; LOG_ASSERT(src_alloc, "Source of copy* must have an allocation"); LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation"); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 905e6aaf..2513140a 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -265,7 +265,7 @@ bool Parser::parse_one() } else { - LOG_BUG(""); + LOG_BUG("Unexpected token in `type` - " << lex.next()); } } lex.check_consume('}'); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 168df328..18bed61e 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -104,6 +104,24 @@ AllocationPtr::~AllocationPtr() } } } +size_t AllocationPtr::get_size() const +{ + if( !*this ) + return 0; + switch(get_ty()) + { + case Ty::Allocation: + return alloc().size(); + case Ty::Function: + return 0; + case Ty::StdString: + return str().size(); + case Ty::FfiPointer: + return 0; + //return ffi().size; + } + throw "Unreachable"; +} ::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x) { @@ -167,6 +185,7 @@ void Allocation::mark_bytes_valid(size_t ofs, size_t size) Value Allocation::read_value(size_t ofs, size_t size) const { Value rv; + // TODO: Determine if this can become an inline allocation. bool has_reloc = false; for(const auto& r : this->relocations) @@ -189,11 +208,44 @@ Value Allocation::read_value(size_t ofs, size_t size) const rv.allocation.alloc().relocations.push_back({ r.slot_ofs - ofs, r.backing_alloc }); } } + + // Copy the mask bits + for(size_t i = 0; i < size; i ++) + { + size_t j = ofs + i; + bool v = (this->mask[j/8] & (1 << j%8)) != 0; + if( v ) + { + rv.allocation.alloc().mask[i/8] |= (1 << i%8); + } + else + { + rv.allocation.alloc().mask[i/8] &= ~(1 << i%8); + } + } } else { rv.direct_data.size = static_cast<uint8_t>(size); + rv.write_bytes(0, this->data_ptr() + ofs, size); + rv.direct_data.mask[0] = 0; + rv.direct_data.mask[1] = 0; + + // Copy the mask bits + for(size_t i = 0; i < size; i ++) + { + size_t j = ofs + i; + bool v = (this->mask[j/8] & (1 << j%8)) != 0; + if( v ) + { + rv.direct_data.mask[i/8] |= (1 << i%8); + } + //else + //{ + // rv.direct_data.mask[i/8] &= ~(1 << i%8); + //} + } } return rv; } @@ -240,7 +292,7 @@ void Allocation::write_value(size_t ofs, Value v) // 2. Move the new relocations into this allocation for(auto& r : new_relocs) { - LOG_TRACE("Insert " << r.backing_alloc); + //LOG_TRACE("Insert " << r.backing_alloc); r.slot_ofs += ofs; this->relocations.push_back( ::std::move(r) ); } @@ -307,7 +359,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) { if( ofs <= it->slot_ofs && it->slot_ofs < ofs + count) { - LOG_TRACE("Delete " << it->backing_alloc); + //LOG_TRACE("Delete " << it->backing_alloc); it = this_relocs.erase(it); } else @@ -325,6 +377,8 @@ void Allocation::write_usize(size_t ofs, uint64_t v) } ::std::ostream& operator<<(::std::ostream& os, const Allocation& x) { + auto flags = os.flags(); + os << ::std::hex; for(size_t i = 0; i < x.size(); i++) { if( i != 0 ) @@ -339,6 +393,7 @@ void Allocation::write_usize(size_t ofs, uint64_t v) os << "--"; } } + os.setf(flags); os << " {"; for(const auto& r : x.relocations) @@ -408,6 +463,21 @@ Value::Value(::HIR::TypeRef ty) //LOG_TRACE(" Creating allocation for " << ty); this->allocation = Allocation::new_alloc(size); } +Value Value::with_size(size_t size, bool have_allocation) +{ + Value rv; + if(have_allocation) + { + rv.allocation = Allocation::new_alloc(size); + } + else + { + rv.direct_data.size = static_cast<uint8_t>(size); + rv.direct_data.mask[0] = 0; + rv.direct_data.mask[1] = 0; + } + return rv; +} Value Value::new_fnptr(const ::HIR::Path& fn_path) { Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) ); @@ -476,7 +546,7 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) } else { - for(size_t i = 0; i < this->direct_data.size; i++) + for(size_t i = ofs; i < ofs+size; i++) { this->direct_data.mask[i/8] |= (1 << i%8); } @@ -567,8 +637,17 @@ void Value::write_value(size_t ofs, Value v) } else { - v.check_bytes_valid(0, v.direct_data.size); write_bytes(ofs, v.direct_data.data, v.direct_data.size); + + // Lazy way, sets/clears individual bits + for(size_t i = 0; i < v.direct_data.size; i ++) + { + uint8_t dbit = 1 << ((ofs+i) % 8); + if( v.direct_data.mask[i/8] & (1 << (i %8)) ) + this->direct_data.mask[ (ofs+i) / 8 ] |= dbit; + else + this->direct_data.mask[ (ofs+i) / 8 ] &= ~dbit; + } } } } @@ -606,36 +685,65 @@ void Value::write_usize(size_t ofs, uint64_t v) } extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) { + if( v.m_size == 0 ) + return os; if( v.m_alloc || v.m_value->allocation ) { const auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation; // TODO: What if alloc_ptr isn't a data allocation? - const auto& alloc = alloc_ptr.alloc(); - - for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++) + switch(alloc_ptr.get_ty()) { - if( i != 0 ) - os << " "; - - if( alloc.mask[i/8] & (1 << i%8) ) + case AllocationPtr::Ty::Allocation: { + const auto& alloc = alloc_ptr.alloc(); + + 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++) { - os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; + if( i != 0 ) + os << " "; + + if( alloc.mask[i/8] & (1 << i%8) ) + { + os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; + } + else + { + os << "--"; + } } - else + os.setf(flags); + + os << " {"; + for(const auto& r : alloc.relocations) { - os << "--"; + if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size ) + { + os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc; + } } - } - - os << " {"; - for(const auto& r : alloc.relocations) - { - if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size ) + os << " }"; + } break; + case AllocationPtr::Ty::Function: + LOG_TODO("ValueRef to " << alloc_ptr); + break; + case AllocationPtr::Ty::StdString: { + const auto& s = alloc_ptr.str(); + assert(v.m_offset < s.size()); + assert(v.m_size < s.size()); + assert(v.m_offset + v.m_size <= s.size()); + auto flags = os.flags(); + os << ::std::hex; + for(size_t i = v.m_offset; i < v.m_offset + v.m_size; i++) { - os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc; + os << ::std::setw(2) << ::std::setfill('0') << (int)s.data()[i]; } + os.setf(flags); + } break; + case AllocationPtr::Ty::FfiPointer: + LOG_TODO("ValueRef to " << alloc_ptr); + break; } - os << " }"; } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index ca15dea9..3dfdd369 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -60,8 +60,10 @@ public: return *this; } + size_t get_size() const; + operator bool() const { return m_ptr != 0; } - bool is_alloc() { + bool is_alloc() const { return *this && get_ty() == Ty::Allocation; } Allocation& alloc() { @@ -183,6 +185,7 @@ struct Value Value(); Value(::HIR::TypeRef ty); + static Value with_size(size_t size, bool have_allocation); static Value new_fnptr(const ::HIR::Path& fn_path); static Value new_ffiptr(FFIPointer ffi); @@ -233,8 +236,9 @@ struct ValueRef // Either an AllocationPtr, or a Value pointer AllocationPtr m_alloc; Value* m_value; - size_t m_offset; - size_t m_size; + size_t m_offset; // Offset within the value + size_t m_size; // Size in bytes of the referenced value + ::std::shared_ptr<Value> m_metadata; ValueRef(AllocationPtr ptr, size_t ofs, size_t size): m_alloc(ptr), @@ -242,6 +246,21 @@ struct ValueRef m_offset(ofs), m_size(size) { + switch(m_alloc.get_ty()) + { + case AllocationPtr::Ty::Allocation: + assert(ofs < m_alloc.alloc().size()); + assert(size <= m_alloc.alloc().size()); + assert(ofs+size <= m_alloc.alloc().size()); + break; + case AllocationPtr::Ty::StdString: + assert(ofs < m_alloc.str().size()); + assert(size <= m_alloc.str().size()); + assert(ofs+size <= m_alloc.str().size()); + break; + default: + throw "TODO"; + } } ValueRef(Value& val): ValueRef(val, 0, val.size()) @@ -254,6 +273,26 @@ struct ValueRef { } + AllocationPtr get_relocation(size_t ofs) const { + if(m_alloc) + { + if( m_alloc.is_alloc() ) + return m_alloc.alloc().get_relocation(ofs); + else + return AllocationPtr(); + } + else if( m_value->allocation ) + { + if( m_value->allocation.is_alloc() ) + return m_value->allocation.alloc().get_relocation(ofs); + else + return AllocationPtr(); + } + else + { + return AllocationPtr(); + } + } Value read_value(size_t ofs, size_t size) const { if( size == 0 ) return Value(); @@ -261,7 +300,23 @@ struct ValueRef assert(size <= m_size); assert(ofs+size <= m_size); if( m_alloc ) { - return m_alloc.alloc().read_value(m_offset + ofs, size); + switch(m_alloc.get_ty()) + { + case AllocationPtr::Ty::Allocation: + return m_alloc.alloc().read_value(m_offset + ofs, size); + case AllocationPtr::Ty::StdString: { + auto rv = Value::with_size(size, false); + //ASSERT_BUG(ofs <= m_alloc.str().size(), ""); + //ASSERT_BUG(size <= m_alloc.str().size(), ""); + //ASSERT_BUG(ofs+size <= m_alloc.str().size(), ""); + assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size()); + rv.write_bytes(0, m_alloc.str().data() + m_offset + ofs, size); + return rv; + } + default: + //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << ); + throw "TODO"; + } } else { return m_value->read_value(m_offset + ofs, size); @@ -274,7 +329,19 @@ struct ValueRef assert(size <= m_size); assert(ofs+size <= m_size); if( m_alloc ) { - m_alloc.alloc().read_bytes(m_offset + ofs, dst, size); + switch(m_alloc.get_ty()) + { + case AllocationPtr::Ty::Allocation: + m_alloc.alloc().read_bytes(m_offset + ofs, dst, size); + break; + case AllocationPtr::Ty::StdString: + assert(m_offset+ofs <= m_alloc.str().size() && size <= m_alloc.str().size() && m_offset+ofs+size <= m_alloc.str().size()); + ::std::memcpy(dst, m_alloc.str().data() + m_offset + ofs, size); + break; + default: + //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << ); + throw "TODO"; + } } else { m_value->read_bytes(m_offset + ofs, dst, size); |