diff options
author | John Hodge <tpg@mutabah.net> | 2018-05-13 14:08:55 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-05-13 14:08:55 +0800 |
commit | 689722fa920cfa74880922ac626cc935b202acc4 (patch) | |
tree | 64f603eb174f5e127b22f4d24f4f1d92d1a4c3e1 | |
parent | 51e08ea81248930fdaf94acb4d893e8a47f406f2 (diff) | |
download | mrust-689722fa920cfa74880922ac626cc935b202acc4.tar.gz |
Standalone MIRI - Shallow drops and better tracing
-rw-r--r-- | tools/standalone_miri/main.cpp | 76 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 2 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 52 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 11 |
4 files changed, 109 insertions, 32 deletions
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index d210849c..97ca8e6f 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -314,8 +314,22 @@ struct Ops { namespace { - void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty) + void drop_value(ModuleTree& modtree, ThreadState& thread, Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false) { + if( is_shallow ) + { + // HACK: Only works for Box<T> where the first pointer is the data pointer + 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() ) { + LOG_ERROR("Attempting to shallow drop with invalid pointer (no relocation or non-zero offset) - " << box_ptr_vr); + } + + LOG_DEBUG("drop_value SHALLOW deallocate " << alloc); + alloc.alloc().mark_as_freed(); + return ; + } if( ty.wrappers.empty() ) { if( ty.inner_type == RawType::Composite ) @@ -1479,7 +1493,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: ptr_val.write_usize(0, ofs); ptr_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) }); - drop_value(modtree, thread, ptr_val, ty); + // TODO: Shallow drop + drop_value(modtree, thread, ptr_val, ty, /*shallow=*/se.kind == ::MIR::eDropKind::SHALLOW); // TODO: Clear validity on the entire inner value. //alloc.mark_as_freed(); } @@ -1618,6 +1633,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ThreadState& thread, ::HIR::Path path, :: extern "C" { long sysconf(int); + ssize_t write(int, const void*, size_t); } Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args) @@ -1661,14 +1677,12 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: auto alloc_ptr = args.at(0).allocation.alloc().get_relocation(0); auto ptr_ofs = args.at(0).read_usize(0); LOG_ASSERT(ptr_ofs == 0, "__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"); LOG_ASSERT(alloc_ptr.is_alloc(), "__rust_deallocate with no backing allocation attached to pointer"); auto& alloc = alloc_ptr.alloc(); - // TODO: Figure out how to prevent this ever being written again. - //alloc.mark_as_freed(); - for(auto& v : alloc.mask) - v = 0; + alloc.mark_as_freed(); // Just let it drop. return Value(); } @@ -1693,6 +1707,10 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: { LOG_TODO("__rust_start_panic"); } + else if( link_name == "rust_begin_unwind" ) + { + LOG_TODO("rust_begin_unwind"); + } #ifdef _WIN32 // WinAPI functions used by libstd else if( link_name == "AddVectoredExceptionHandler" ) @@ -1758,6 +1776,18 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: } #else // POSIX + else if( link_name == "write" ) + { + auto fd = args.at(0).read_i32(0); + auto count = args.at(2).read_isize(0); + const auto* buf = args.at(1).read_pointer_const(0, count); + + ssize_t val = write(fd, buf, count); + + auto rv = Value(::HIR::TypeRef(RawType::ISize)); + rv.write_isize(0, val); + return rv; + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -1767,7 +1797,7 @@ Value MIRI_Invoke_Extern(ModuleTree& modtree, ThreadState& thread, const ::std:: rv.write_usize(0, val); return rv; } - else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" ) + else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { auto rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, 0); @@ -1902,7 +1932,11 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st TRACE_FUNCTION_R(name, rv); for(const auto& a : args) LOG_DEBUG("#" << (&a - args.data()) << ": " << a); - if( name == "atomic_store" ) + if( name == "atomic_fence" || name == "atomic_fence_acq" ) + { + return Value(); + } + else if( name == "atomic_store" ) { auto& ptr_val = args.at(0); auto& data_val = args.at(1); @@ -1956,6 +1990,27 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); } + 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_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto v = args.at(1).read_value(0, ty_T.get_size()); + + // TODO: Atomic lock the allocation. + if( !ptr_alloc || !ptr_alloc.is_alloc() ) { + LOG_ERROR("atomic pointer has no allocation"); + } + + // - Result is the original value + rv = ptr_alloc.alloc().read_value(ptr_ofs, ty_T.get_size()); + + auto val_l = PrimitiveValueVirt::from_value(ty_T, rv); + const auto val_r = PrimitiveValueVirt::from_value(ty_T, v); + val_l.get().subtract( val_r.get() ); + + val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); + } else if( name == "atomic_cxchg" ) { const auto& ty_T = ty_params.tys.at(0); @@ -2086,13 +2141,14 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st case TypeWrapper::Ty::Pointer: break; case TypeWrapper::Ty::Borrow: + // TODO: Only &move has a destructor break; } LOG_ASSERT(ty.wrappers[0].type == TypeWrapper::Ty::Slice, "drop_in_place should only exist for slices - " << ty); const auto& ity = ty.get_inner(); size_t item_size = ity.get_size(); - auto ptr = val.read_value(0, POINTER_SIZE);; + auto ptr = val.read_value(0, POINTER_SIZE); for(size_t i = 0; i < item_count; i ++) { drop_value(modtree, thread, ptr, ity); @@ -2101,7 +2157,7 @@ Value MIRI_Invoke_Intrinsic(ModuleTree& modtree, ThreadState& thread, const ::st } else { - LOG_TODO("drop_in_place - " << ty); + drop_value(modtree, thread, val, ty); } } // ---------------------------------------------------------------- diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index c70f17dd..88d8ff88 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -675,7 +675,7 @@ bool Parser::parse_one() case '<': if( t.strval[1] == '<' ) op = ::MIR::eBinOp::BIT_SHL; - else if( lex.consume_if('=') ) + else if( t.strval[1] == '=' ) op = ::MIR::eBinOp::LE; else op = ::MIR::eBinOp::LT; diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index db352019..cdace6e2 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -232,6 +232,8 @@ ValueRef ValueCommon::read_pointer_valref_mut(size_t rd_ofs, size_t size) void Allocation::resize(size_t new_size) { + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); //size_t old_size = this->size(); //size_t extra_bytes = (new_size > old_size ? new_size - old_size : 0); @@ -246,9 +248,9 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const } for(size_t i = ofs; i < ofs + size; i++) { - if( !(this->mask[i/8] & (1 << i%8)) ) + if( !(this->mask[i/8] & (1 << (i%8))) ) { - LOG_ERROR("Invalid bytes in value"); + LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this); throw "ERROR"; } } @@ -258,14 +260,18 @@ void Allocation::mark_bytes_valid(size_t ofs, size_t size) assert( ofs+size <= this->mask.size() * 8 ); for(size_t i = ofs; i < ofs + size; i++) { - this->mask[i/8] |= (1 << i%8); + this->mask[i/8] |= (1 << (i%8)); } } Value Allocation::read_value(size_t ofs, size_t size) const { Value rv; + TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << rv); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + LOG_DEBUG(*this); - // TODO: Determine if this can become an inline allocation. + // Determine if this can become an inline allocation. bool has_reloc = false; for(const auto& r : this->relocations) { @@ -292,14 +298,12 @@ Value Allocation::read_value(size_t ofs, size_t size) const for(size_t i = 0; i < size; i ++) { size_t j = ofs + i; - bool v = (this->mask[j/8] & (1 << j%8)) != 0; + const uint8_t test_mask = (1 << (j%8)); + const uint8_t set_mask = (1 << (i%8)); + bool v = (this->mask[j/8] & test_mask) != 0; if( v ) { - rv.allocation.alloc().mask[i/8] |= (1 << i%8); - } - else - { - rv.allocation.alloc().mask[i/8] &= ~(1 << i%8); + rv.allocation.alloc().mask[i/8] |= set_mask; } } } @@ -315,21 +319,23 @@ Value Allocation::read_value(size_t ofs, size_t size) const for(size_t i = 0; i < size; i ++) { size_t j = ofs + i; - bool v = (this->mask[j/8] & (1 << j%8)) != 0; + const uint8_t tst_mask = 1 << (j%8); + const uint8_t set_mask = 1 << (i%8); + bool v = (this->mask[j/8] & tst_mask) != 0; if( v ) { - rv.direct_data.mask[i/8] |= (1 << i%8); + rv.direct_data.mask[i/8] |= set_mask; } - //else - //{ - // rv.direct_data.mask[i/8] &= ~(1 << i%8); - //} } } return rv; } void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const { + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + + LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count); if(count == 0) return ; @@ -352,6 +358,11 @@ void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const } void Allocation::write_value(size_t ofs, Value v) { + TRACE_FUNCTION_R("Allocation::write_value " << this << " " << ofs << "+" << v.size() << " " << v, *this); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + //if( this->is_read_only ) + // LOG_ERROR("Writing to read-only allocation " << this); if( v.allocation ) { size_t v_size = v.allocation.alloc().size(); @@ -416,8 +427,15 @@ void Allocation::write_value(size_t ofs, Value v) } void Allocation::write_bytes(size_t ofs, const void* src, size_t count) { + //LOG_DEBUG("Allocation::write_bytes " << this << " " << ofs << "+" << count); + if( this->is_freed ) + LOG_ERROR("Use of freed memory " << this); + //if( this->is_read_only ) + // LOG_ERROR("Writing to read-only allocation " << this); + if(count == 0) return ; + TRACE_FUNCTION_R("Allocation::write_bytes " << this << " " << ofs << "+" << count, *this); if(ofs >= this->size() ) { LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size()); throw "ERROR"; @@ -459,7 +477,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) if( i != 0 ) os << " "; - if( x.mask[i/8] & (1 << i%8) ) + if( x.mask[i/8] & (1 << (i%8)) ) { os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i]; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 2b3bd4e6..aa41b838 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -171,6 +171,7 @@ class Allocation: friend class AllocationPtr; size_t refcount; // TODO: Read-only flag? + bool is_freed = false; public: static AllocationPtr new_alloc(size_t size); @@ -189,10 +190,12 @@ public: } return AllocationPtr(); } - //void mark_as_freed() { - // for(auto& v : mask) - // v = 0; - //} + void mark_as_freed() { + is_freed = true; + relocations.clear(); + for(auto& v : mask) + v = 0; + } void resize(size_t new_size); |