summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-05-13 14:08:55 +0800
committerJohn Hodge <tpg@mutabah.net>2018-05-13 14:08:55 +0800
commit689722fa920cfa74880922ac626cc935b202acc4 (patch)
tree64f603eb174f5e127b22f4d24f4f1d92d1a4c3e1
parent51e08ea81248930fdaf94acb4d893e8a47f406f2 (diff)
downloadmrust-689722fa920cfa74880922ac626cc935b202acc4.tar.gz
Standalone MIRI - Shallow drops and better tracing
-rw-r--r--tools/standalone_miri/main.cpp76
-rw-r--r--tools/standalone_miri/module_tree.cpp2
-rw-r--r--tools/standalone_miri/value.cpp52
-rw-r--r--tools/standalone_miri/value.hpp11
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);