summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-08-03 18:13:51 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-08-03 18:13:51 +0800
commit17615468f01bbe83486500f9cc4020b4cd3b6e8b (patch)
tree6e6c9964a3ab9ca5cd190782c1acce5a986b4e8e /tools
parent85bc7996313b4df50cbb227ae25c0721f7f5eadd (diff)
downloadmrust-17615468f01bbe83486500f9cc4020b4cd3b6e8b.tar.gz
Standalone miri - General fixes trying to get a test running
Diffstat (limited to 'tools')
-rw-r--r--tools/standalone_miri/debug.hpp2
-rw-r--r--tools/standalone_miri/miri.cpp94
-rw-r--r--tools/standalone_miri/value.cpp2
-rw-r--r--tools/standalone_miri/value.hpp32
4 files changed, 90 insertions, 40 deletions
diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp
index 5f1dd038..9de6231b 100644
--- a/tools/standalone_miri/debug.hpp
+++ b/tools/standalone_miri/debug.hpp
@@ -111,6 +111,6 @@ struct DebugExceptionError:
#define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0)
#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 LOG_ASSERT(cnd,strm) do { if( !(cnd) ) { LOG_ERROR("Assertion failure: " #cnd " - " << strm); } } while(0)
#define FMT_STRING(...) (dynamic_cast<::std::stringstream&>(::std::stringstream() << __VA_ARGS__).str())
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp
index 8fe941d9..ef8a71c9 100644
--- a/tools/standalone_miri/miri.cpp
+++ b/tools/standalone_miri/miri.cpp
@@ -26,6 +26,7 @@ class PrimitiveValue
public:
virtual ~PrimitiveValue() {}
+ virtual bool is_zero() const = 0;
virtual bool add(const PrimitiveValue& v) = 0;
virtual bool subtract(const PrimitiveValue& v) = 0;
virtual bool multiply(const PrimitiveValue& v) = 0;
@@ -51,6 +52,9 @@ struct PrimitiveUInt:
PrimitiveUInt(T v): v(v) {}
~PrimitiveUInt() override {}
+ virtual bool is_zero() const {
+ return this->v == 0;
+ }
bool add(const PrimitiveValue& x) override {
const auto* xp = &x.check<Self>("add");
T newv = this->v + xp->v;
@@ -111,6 +115,9 @@ struct PrimitiveSInt:
PrimitiveSInt(T v): v(v) {}
~PrimitiveSInt() override {}
+ virtual bool is_zero() const {
+ return this->v == 0;
+ }
// TODO: Make this correct.
bool add(const PrimitiveValue& x) override {
const auto* xp = &x.check<Self>("add");
@@ -1628,13 +1635,19 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
{
if( link_name == "__rust_allocate" || link_name == "__rust_alloc" )
{
+ static unsigned s_alloc_count = 0;
+
+ auto alloc_idx = s_alloc_count ++;
+ auto alloc_name = FMT_STRING("__rust_alloc#" << alloc_idx);
auto size = args.at(0).read_usize(0);
auto align = args.at(1).read_usize(0);
- LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << ")");
+ LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << "): name=" << alloc_name);
+ auto alloc = Allocation::new_alloc(size, ::std::move(alloc_name));
+ LOG_TRACE("- alloc=" << alloc << " (" << alloc->size() << " bytes)");
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, "__rust_alloc")));
+ rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(::std::move(alloc)));
}
else if( link_name == "__rust_reallocate" || link_name == "__rust_realloc" )
{
@@ -1643,8 +1656,9 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c
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);
- auto newsize = args.at(2).read_usize(0);
- auto align = args.at(3).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(alloc_ptr, "__rust_reallocate with no backing allocation attached to pointer");
@@ -2197,7 +2211,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
else if( name == "mul_with_overflow" )
{
const auto& ty = ty_params.tys.at(0);
-
+
auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
bool didnt_overflow = lhs.get().multiply( rhs.get() );
@@ -2212,6 +2226,24 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
lhs.get().write_to_value(rv, dty.fields[0].first);
rv.write_u8( dty.fields[1].first, didnt_overflow ? 0 : 1 ); // Returns true if overflow happened
}
+ // - "exact_div" :: Normal divide, but UB if not an exact multiple
+ else if( name == "exact_div" )
+ {
+ const auto& ty = ty_params.tys.at(0);
+
+ auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0));
+ auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1));
+
+ LOG_ASSERT(!rhs.get().is_zero(), "`exact_div` with zero divisor: " << args.at(0) << " / " << args.at(1));
+ auto rem = lhs;
+ rem.get().modulo( rhs.get() );
+ LOG_ASSERT(rem.get().is_zero(), "`exact_div` with yielded non-zero remainder: " << args.at(0) << " / " << args.at(1));
+ bool didnt_overflow = lhs.get().divide( rhs.get() );
+ LOG_ASSERT(didnt_overflow, "`exact_div` failed for unknown reason: " << args.at(0) << " /" << args.at(1));
+
+ rv = Value(ty);
+ lhs.get().write_to_value(rv, 0);
+ }
// Overflowing artithmatic
else if( name == "overflowing_sub" )
{
@@ -2248,31 +2280,35 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::
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");
- LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
-
- switch(src_alloc.get_ty())
+ // A count of zero doesn't need to do any of the checks (TODO: Validate this rule)
+ if( byte_count > 0 )
{
- case RelocationPtr::Ty::Allocation: {
- auto v = src_alloc.alloc().read_value(src_ofs, byte_count);
- LOG_DEBUG("v = " << v);
- dst_alloc.alloc().write_value(dst_ofs, ::std::move(v));
- } break;
- case RelocationPtr::Ty::StdString:
- LOG_ASSERT(src_ofs <= src_alloc.str().size(), "");
- LOG_ASSERT(byte_count <= src_alloc.str().size(), "");
- LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), "");
- dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count);
- break;
- case RelocationPtr::Ty::Function:
- LOG_FATAL("Attempt to copy* a function");
- break;
- case RelocationPtr::Ty::FfiPointer:
- LOG_ASSERT(src_alloc.ffi().layout, "");
- LOG_ASSERT(src_alloc.ffi().layout->is_valid_read(src_ofs, byte_count), "");
- dst_alloc.alloc().write_bytes(dst_ofs, reinterpret_cast<const char*>(src_alloc.ffi().ptr_value) + src_ofs, byte_count);
- break;
+ LOG_ASSERT(src_alloc, "Source of copy* must have an allocation");
+ LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation");
+ LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation");
+
+ switch(src_alloc.get_ty())
+ {
+ case RelocationPtr::Ty::Allocation: {
+ auto v = src_alloc.alloc().read_value(src_ofs, byte_count);
+ LOG_DEBUG("v = " << v);
+ dst_alloc.alloc().write_value(dst_ofs, ::std::move(v));
+ } break;
+ case RelocationPtr::Ty::StdString:
+ LOG_ASSERT(src_ofs <= src_alloc.str().size(), "");
+ LOG_ASSERT(byte_count <= src_alloc.str().size(), "");
+ LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), "");
+ dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count);
+ break;
+ case RelocationPtr::Ty::Function:
+ LOG_FATAL("Attempt to copy* a function");
+ break;
+ case RelocationPtr::Ty::FfiPointer:
+ LOG_ASSERT(src_alloc.ffi().layout, "");
+ LOG_ASSERT(src_alloc.ffi().layout->is_valid_read(src_ofs, byte_count), "");
+ dst_alloc.alloc().write_bytes(dst_ofs, reinterpret_cast<const char*>(src_alloc.ffi().ptr_value) + src_ofs, byte_count);
+ break;
+ }
}
}
else
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index 4318d289..7344ef46 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -15,7 +15,7 @@
::std::ostream& operator<<(::std::ostream& os, const Allocation* x)
{
- os << "A(" << static_cast<const void*>(x) << " " << x->tag() << ")";
+ os << "A(" << static_cast<const void*>(x) << " " << x->tag() /*<< " +" << x->size()*/ << ")";
return os;
}
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index 9c780351..68fa492f 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -13,6 +13,8 @@
#include <cstring> // memcpy
#include <cassert>
+#include "debug.hpp"
+
namespace HIR {
struct TypeRef;
struct Path;
@@ -359,24 +361,36 @@ struct ValueRef:
m_offset(ofs),
m_size(size)
{
+ struct H {
+ static bool in_bounds(size_t ofs, size_t size, size_t max_size) {
+ if( !(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:
- assert(ofs < m_alloc.alloc().size());
- assert(size <= m_alloc.alloc().size());
- assert(ofs+size <= m_alloc.alloc().size());
+ if( !H::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:
- assert(ofs < m_alloc.str().size());
- assert(size <= m_alloc.str().size());
- assert(ofs+size <= m_alloc.str().size());
+ if( !H::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:
- assert(ofs < m_alloc.ffi().get_size());
- assert(size <= m_alloc.ffi().get_size());
- assert(ofs+size <= m_alloc.ffi().get_size());
+ if( !H::in_bounds(ofs, size, m_alloc.ffi().get_size()) )
+ {
+ LOG_ERROR("ValueRef exceeds bounds of FFI buffer - " << ofs << "+" << size << " > " << m_alloc.ffi().get_size());
+ }
break;
default:
throw "TODO";