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/miri.cpp | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 8231f2c5..d5bcb024 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -273,7 +273,7 @@ struct MirHelpers return ValueRef(this->frame.args.at(e.idx)); } break; TU_ARM(lv, Static, e) { - /*const*/ auto& s = this->thread.m_modtree.get_static(e); + /*const*/ auto& s = this->thread.m_modtree.get_static(*e); ty = s.ty; return ValueRef(s.val); } break; @@ -482,15 +482,15 @@ struct MirHelpers // --> Accessor TU_ARM(c, ItemAddr, ce) { // Create a value with a special backing allocation of zero size that references the specified item. - if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(ce) ) { + if( /*const auto* fn =*/ this->thread.m_modtree.get_function_opt(*ce) ) { ty = ::HIR::TypeRef(RawType::Function); - return Value::new_fnptr(ce); + return Value::new_fnptr(*ce); } - if( const auto* s = this->thread.m_modtree.get_static_opt(ce) ) { + 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)); } - LOG_ERROR("Constant::ItemAddr - " << ce << " - not found"); + LOG_ERROR("Constant::ItemAddr - " << *ce << " - not found"); } break; } throw ""; @@ -1031,19 +1031,20 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r); size_t max_bits = ty_r.get_size() * 8; uint8_t shift; - auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; + auto check_cast_u = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; + auto check_cast_s = [&](auto v){ LOG_ASSERT(v <= static_cast(max_bits), "Shift out of range - " << v); return static_cast(v); }; switch(ty_r.inner_type) { - case RawType::U64: shift = check_cast(v_r.read_u64(0)); break; - case RawType::U32: shift = check_cast(v_r.read_u32(0)); break; - case RawType::U16: shift = check_cast(v_r.read_u16(0)); break; - case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break; - case RawType::I64: shift = check_cast(v_r.read_i64(0)); break; - case RawType::I32: shift = check_cast(v_r.read_i32(0)); break; - case RawType::I16: shift = check_cast(v_r.read_i16(0)); break; - case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break; - case RawType::USize: shift = check_cast(v_r.read_usize(0)); break; - case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break; + case RawType::U64: shift = check_cast_u(v_r.read_u64(0)); break; + case RawType::U32: shift = check_cast_u(v_r.read_u32(0)); break; + case RawType::U16: shift = check_cast_u(v_r.read_u16(0)); break; + case RawType::U8 : shift = check_cast_u(v_r.read_u8 (0)); break; + case RawType::I64: shift = check_cast_s(v_r.read_i64(0)); break; + case RawType::I32: shift = check_cast_s(v_r.read_i32(0)); break; + case RawType::I16: shift = check_cast_s(v_r.read_i16(0)); break; + case RawType::I8 : shift = check_cast_s(v_r.read_i8 (0)); break; + case RawType::USize: shift = check_cast_u(v_r.read_usize(0)); break; + case RawType::ISize: shift = check_cast_s(v_r.read_isize(0)); break; default: LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); } @@ -2213,9 +2214,8 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con LOG_FATAL("Attempt to copy* a function"); break; case RelocationPtr::Ty::FfiPointer: - LOG_ASSERT(src_ofs <= src_alloc.ffi().size, ""); - LOG_ASSERT(byte_count <= src_alloc.ffi().size, ""); - LOG_ASSERT(src_ofs + byte_count <= src_alloc.ffi().size, ""); + 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; } -- cgit v1.2.3 From 311b406bf90a8244a39a8eff933c7fce45b9c7f2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 15 May 2019 20:35:44 +0800 Subject: standalone_miri - Fiddling for 1.29 support (not working yet) --- tools/standalone_miri/miri.cpp | 36 +++++++++++++++++++++++++++++++++--- tools/standalone_miri/value.cpp | 32 ++++++++++++++++++++++++++++++++ tools/standalone_miri/value.hpp | 30 +++++------------------------- 3 files changed, 70 insertions(+), 28 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index d5bcb024..4bba4da4 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1553,7 +1553,9 @@ bool InterpreterThread::call_path(Value& ret, const ::HIR::Path& path, ::std::ve } // - No guard page needed - if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } ) + if( path == ::HIR::SimplePath { "std", {"sys", "imp", "thread", "guard", "init" } } + || path == ::HIR::SimplePath { "std", {"sys", "unix", "thread", "guard", "init" } } + ) { ret = Value::with_size(16, false); ret.write_u64(0, 0); @@ -1599,7 +1601,7 @@ extern "C" { #endif bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { - if( link_name == "__rust_allocate" ) + if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) { auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); @@ -1609,7 +1611,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // TODO: Use the alignment when making an allocation? rv = Value::new_pointer(rty, 0, RelocationPtr::new_alloc(Allocation::new_alloc(size))); } - else if( link_name == "__rust_reallocate" ) + 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); @@ -1757,6 +1759,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value::new_usize(val); } + else if( link_name == "pthread_self" ) + { + rv = Value::new_i32(0); + } else if( link_name == "pthread_mutex_init" || link_name == "pthread_mutex_lock" || link_name == "pthread_mutex_unlock" || link_name == "pthread_mutex_destroy" ) { rv = Value::new_i32(0); @@ -1773,6 +1779,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + else if( link_name == "pthread_attr_init" || link_name == "pthread_attr_destroy" || link_name == "pthread_getattr_np" ) + { + rv = Value::new_i32(0); + } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { rv = Value::new_i32(0); @@ -1820,6 +1830,14 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, 1); } + else if( link_name == "sigaction" ) + { + rv = Value::new_i32(-1); + } + else if( link_name == "sigaltstack" ) // POSIX: Set alternate signal stack + { + rv = Value::new_i32(-1); + } // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { @@ -2177,6 +2195,18 @@ bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, con auto lhs = PrimitiveValueVirt::from_value(ty, args.at(0)); auto rhs = PrimitiveValueVirt::from_value(ty, args.at(1)); lhs.get().subtract( rhs.get() ); + // TODO: Overflowing part + + rv = Value(ty); + lhs.get().write_to_value(rv, 0); + } + else if( name == "overflowing_add" ) + { + 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)); + lhs.get().add( rhs.get() ); rv = Value(ty); lhs.get().write_to_value(rv, 0); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 9007eb5c..0b3aa988 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -13,6 +13,38 @@ #include #include "debug.hpp" +FfiLayout FfiLayout::new_const_bytes(size_t s) +{ + return FfiLayout { + { Range {s, true, false} } + }; +} +bool FfiLayout::is_valid_read(size_t o, size_t s) const +{ + for(const auto& r : ranges) + { + if( o < r.len ) { + if( !r.is_valid ) + return false; + if( o + s <= r.len ) + { + s = 0; + break; + } + s -= (r.len - o); + o = 0; + } + else { + o -= r.len; + } + } + if( s > 0 ) + { + return false; + } + return true; +} + AllocationHandle Allocation::new_alloc(size_t size) { Allocation* rv = new Allocation(); diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 377361ce..e45759a7 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -30,36 +30,15 @@ struct FfiLayout }; ::std::vector ranges; + static FfiLayout new_const_bytes(size_t s); + size_t get_size() const { size_t rv = 0; for(const auto& r : ranges) rv += r.len; return rv; } - bool is_valid_read(size_t o, size_t s) { - for(const auto& r : ranges) - { - if( o < r.len ) { - if( !r.is_valid ) - return false; - if( o + s <= r.len ) - { - s = 0; - break; - } - s -= (r.len - o); - o = 0; - } - else { - o -= r.len; - } - } - if( s > 0 ) - { - return false; - } - return true; - } + bool is_valid_read(size_t o, size_t s) const; }; struct FFIPointer { @@ -76,7 +55,7 @@ struct FFIPointer ::std::shared_ptr layout; static FFIPointer new_const_bytes(const void* s, size_t size) { - return FFIPointer { const_cast(s), "", ::std::shared_ptr() }; + return FFIPointer { const_cast(s), "", ::std::make_shared(FfiLayout::new_const_bytes(size)) }; }; size_t get_size() const { @@ -268,6 +247,7 @@ class Allocation: // TODO: Read-only flag? bool is_freed = false; public: + virtual ~Allocation() {} static AllocationHandle new_alloc(size_t size); const uint8_t* data_ptr() const { return reinterpret_cast(this->data.data()); } -- cgit v1.2.3 From 0d5fe417e6ff1806987f77c97b0841b0b600cde0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 14 Jul 2019 17:53:53 +0800 Subject: standalone_miri - Fix after MIR refactor --- src/trans/codegen_mmir.cpp | 29 +++-- tools/standalone_miri/Makefile | 7 +- tools/standalone_miri/hir_sim.cpp | 7 +- tools/standalone_miri/hir_sim.hpp | 89 +++++++------ tools/standalone_miri/mir.cpp | 90 +++++++++++--- tools/standalone_miri/miri.cpp | 228 +++++++++++++++++----------------- tools/standalone_miri/miri.hpp | 2 +- tools/standalone_miri/module_tree.cpp | 21 ++-- tools/standalone_miri/module_tree.hpp | 1 + 9 files changed, 278 insertions(+), 196 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 76d79e93..a86eadc9 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -31,6 +31,12 @@ namespace ::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::LValue>& x) { + for(const auto& w : ::reverse(x.e.m_wrappers)) + { + if( w.is_Deref() ) { + os << "(*"; + } + } TU_MATCHA( (x.e.m_root), (e), (Return, os << "RETURN"; @@ -52,7 +58,7 @@ namespace switch(w.tag()) { TU_ARM(w, Deref, e) - os << "*"; + os << ")"; break; TU_ARM(w, Field, field_index) { // Add a space to prevent accidental float literals @@ -62,7 +68,7 @@ namespace was_num = true; } break; TU_ARM(w, Index, e) { - os << "[var" << fmt(::MIR::LValue::new_Local(e)) << "]"; + os << "[" << fmt(::MIR::LValue::new_Local(e)) << "]"; } break; TU_ARM(w, Downcast, variant_index) { os << "@" << variant_index; @@ -147,12 +153,12 @@ namespace CodeGenerator_MonoMir(const ::HIR::Crate& crate, const ::std::string& outfile): m_crate(crate), m_resolve(crate), - m_outfile_path(outfile + ".mir"), - m_of(m_outfile_path) + m_outfile_path(outfile), + m_of(m_outfile_path + ".mir") { for( const auto& crate : m_crate.m_ext_crates ) { - m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".o.mir\";\n"; + m_of << "crate \"" << FmtEscaped(crate.second.m_path) << ".mir\";\n"; } } @@ -183,6 +189,15 @@ namespace m_of.flush(); m_of.close(); + + // HACK! Create the output file, but keep it empty + { + ::std::ofstream of( m_outfile_path ); + if( !of.good() ) + { + // TODO: Error? + } + } } @@ -1108,8 +1123,8 @@ namespace case ::MIR::eBinOp::SUB_OV: m_of << "-^"; break; case ::MIR::eBinOp::MUL: m_of << "*"; break; case ::MIR::eBinOp::MUL_OV: m_of << "*^"; break; - case ::MIR::eBinOp::DIV: m_of << "*"; break; - case ::MIR::eBinOp::DIV_OV: m_of << "*^"; break; + case ::MIR::eBinOp::DIV: m_of << "/"; break; + case ::MIR::eBinOp::DIV_OV: m_of << "/^"; break; case ::MIR::eBinOp::MOD: m_of << "%"; break; case ::MIR::eBinOp::BIT_OR: m_of << "|"; break; case ::MIR::eBinOp::BIT_AND:m_of << "&"; break; diff --git a/tools/standalone_miri/Makefile b/tools/standalone_miri/Makefile index f4dc0d0d..0a8bd672 100644 --- a/tools/standalone_miri/Makefile +++ b/tools/standalone_miri/Makefile @@ -11,7 +11,7 @@ V ?= @ OBJDIR := .obj/ BIN := ../bin/standalone_miri$(EXESUF) -OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.o miri.o +OBJS := main.o debug.o mir.o lex.o value.o module_tree.o hir_sim.o miri.o rc_string.o LINKFLAGS := -g -lpthread CXXFLAGS := -Wall -std=c++14 -g -O2 @@ -37,6 +37,11 @@ $(OBJDIR)%.o: %.cpp @echo [CXX] $< $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep +$(OBJDIR)%.o: ../../src/%.cpp + @mkdir -p $(dir $@) + @echo [CXX] $< + $V$(CXX) -o $@ -c $< $(CXXFLAGS) -MMD -MP -MF $@.dep + ../bin/common_lib.a: make -C ../common diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 88739730..085c045f 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -249,7 +249,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const if( w->type == TypeWrapper::Ty::Slice ) { // TODO - throw "TODO"; + LOG_TODO("Field on slice - " << *this << " #" << idx); } else if( w->type == TypeWrapper::Ty::Array ) { @@ -260,7 +260,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const } else { - throw "ERROR"; + LOG_ERROR("Field on unknown wrapper type - " << *this << " #" << idx); } } else @@ -273,8 +273,7 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const } else { - ::std::cerr << *this << " doesn't have fields" << ::std::endl; - throw "ERROR"; + LOG_ERROR(*this << " doesn't have fields"); } } } diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 62248fe9..cedbf3b9 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -9,18 +9,23 @@ #include #include #include +#include "../../src/include/rc_string.hpp" const size_t POINTER_SIZE = 8; +#define __ORD(fld) do { auto o = ::ord(this->fld, x.fld); if( o != OrdEqual ) return o; } while(0) +#define __ORD_C(ty, fld) do { auto o = ::ord((ty)this->fld, (ty)x.fld); if( o != OrdEqual ) return o; } while(0) #define __NE(fld) if(this->fld != x.fld) return true #define __LT(fld) if(this->fld != x.fld) return this->fld < x.fld +#if 0 enum Ordering { OrdLess, OrdEqual, OrdGreater, }; +#endif struct DataType; @@ -56,18 +61,19 @@ struct TypeWrapper } type; size_t size; + Ordering ord(const TypeWrapper& x) const { + __ORD_C(int, type); + __ORD(size); + return OrdEqual; + } bool operator==(const TypeWrapper& x) const { - return !(*this != x); + return this->ord(x) == OrdEqual; } bool operator!=(const TypeWrapper& x) const { - __NE(type); - __NE(size); - return false; + return this->ord(x) != OrdEqual; } bool operator<(const TypeWrapper& x) const { - __LT(type); - __LT(size); - return false; + return this->ord(x) == OrdLess; } }; @@ -166,20 +172,20 @@ namespace HIR { bool operator!=(const RawType& x) const { return !(*this == x); } + Ordering ord(const TypeRef& x) const { + __ORD(wrappers); + __ORD_C(int, inner_type); + __ORD_C(uintptr_t, composite_type); + return OrdEqual; + } bool operator==(const TypeRef& x) const { - return !(*this != x); + return this->ord(x) == OrdEqual; } bool operator!=(const TypeRef& x) const { - __NE(wrappers); - __NE(inner_type); - __NE(composite_type); - return false; + return this->ord(x) != OrdEqual; } bool operator<(const TypeRef& x) const { - __LT(wrappers); - __LT(inner_type); - __LT(composite_type); - return false; + return this->ord(x) == OrdLess; } friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x); @@ -189,18 +195,19 @@ namespace HIR { { ::std::string crate_name; ::std::vector<::std::string> ents; + Ordering ord(const SimplePath& x) const { + __ORD(crate_name); + __ORD(ents); + return OrdEqual; + } bool operator==(const SimplePath& x) const { - return !(*this != x); + return this->ord(x) == OrdEqual; } bool operator!=(const SimplePath& x) const { - __NE(crate_name); - __NE(ents); - return false; + return this->ord(x) != OrdEqual; } bool operator<(const SimplePath& x) const { - __LT(crate_name); - __LT(ents); - return false; + return this->ord(x) == OrdLess; } friend ::std::ostream& operator<<(::std::ostream& os, const SimplePath& x); }; @@ -221,18 +228,19 @@ namespace HIR { m_simplepath(sp) { } + Ordering ord(const GenericPath& x) const { + __ORD(m_simplepath); + __ORD(m_params.tys); + return OrdEqual; + } bool operator==(const GenericPath& x) const { - return !(*this != x); + return this->ord(x) == OrdEqual; } bool operator!=(const GenericPath& x) const { - __NE(m_simplepath); - __NE(m_params.tys); - return false; + return this->ord(x) != OrdEqual; } bool operator<(const GenericPath& x) const { - __LT(m_simplepath); - __LT(m_params.tys); - return false; + return this->ord(x) == OrdLess; } friend ::std::ostream& operator<<(::std::ostream& os, const GenericPath& x); @@ -263,22 +271,21 @@ namespace HIR { { } + Ordering ord(const Path& x) const { + __ORD(m_type); + __ORD(m_trait); + __ORD(m_name); + __ORD(m_params.tys); + return OrdEqual; + } bool operator==(const Path& x) const { - return !(*this != x); + return this->ord(x) == OrdEqual; } bool operator!=(const Path& x) const { - __NE(m_type); - __NE(m_trait); - __NE(m_name); - __NE(m_params.tys); - return false; + return this->ord(x) != OrdEqual; } bool operator<(const Path& x) const { - __LT(m_type); - __LT(m_trait); - __LT(m_name); - __LT(m_params.tys); - return false; + return this->ord(x) == OrdLess; } friend ::std::ostream& operator<<(::std::ostream& os, const Path& x); diff --git a/tools/standalone_miri/mir.cpp b/tools/standalone_miri/mir.cpp index f1b4841e..4a5df067 100644 --- a/tools/standalone_miri/mir.cpp +++ b/tools/standalone_miri/mir.cpp @@ -5,10 +5,12 @@ * mir/mir.cpp * - MIR (Middle Intermediate Representation) definitions */ +#include "../../src/include/rc_string.hpp" #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" #include +#if 0 namespace std { template inline ::std::ostream& operator<<(::std::ostream& os, const ::std::vector& v) { @@ -26,6 +28,7 @@ namespace std { return os; } } +#endif namespace MIR { ::std::ostream& operator<<(::std::ostream& os, const Constant& v) { @@ -70,36 +73,87 @@ namespace MIR { ) return os; } - ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + void LValue::RefCommon::fmt(::std::ostream& os) const { - TU_MATCHA( (x), (e), + TU_MATCHA( (m_lv->m_root), (e), (Return, - os << "Return"; + os << "retval"; ), (Argument, - os << "Argument(" << e.idx << ")"; + os << "a" << e; ), (Local, - os << "Local(" << e << ")"; + os << "_" << e; ), (Static, - os << "Static(" << *e << ")"; - ), - (Field, - os << "Field(" << e.field_index << ", " << *e.val << ")"; - ), - (Deref, - os << "Deref(" << *e.val << ")"; - ), - (Index, - os << "Index(" << *e.val << ", " << *e.idx << ")"; - ), - (Downcast, - os << "Downcast(" << e.variant_index << ", " << *e.val << ")"; + os << "(" << e << ")"; ) ) + for(size_t i = 0; i < m_wrapper_count; i ++) + { + const LValue::Wrapper& w = m_lv->m_wrappers.at(i); + TU_MATCHA( (w), (e), + (Field, + os << "." << e; + ), + (Deref, + os << "*"; + ), + (Index, + os << "[_" << e << "]"; + ), + (Downcast, + os << "#" << e; + ) + ) + } + } + + ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + { + LValue::CRef(x).fmt(os); return os; } + + Ordering LValue::Storage::ord(const LValue::Storage& x) const + { + if( x.is_Static() ) + { + if( this->is_Static() ) + return this->as_Static().ord( x.as_Static() ); + else + return OrdLess; + } + else + { + if( this->is_Static() ) + return OrdGreater; + } + + return ::ord(this->val, x.val); + } + Ordering LValue::ord(const LValue& x) const + { + auto rv = m_root.ord(x.m_root); + if( rv != OrdEqual ) + return rv; + return ::ord(m_wrappers, x.m_wrappers); + } + Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const + { + Ordering rv; + //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv); + rv = m_lv->m_root.ord(x.m_lv->m_root); + if( rv != OrdEqual ) + return rv; + for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++) + { + rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]); + if( rv != OrdEqual ) + return rv; + } + return (rv = ::ord(m_wrapper_count, x.m_wrapper_count)); + } ::std::ostream& operator<<(::std::ostream& os, const Param& x) { TU_MATCHA( (x), (e), diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 4bba4da4..3714ed56 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -254,137 +254,141 @@ struct MirHelpers { } - ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty) + ValueRef get_value_and_type_root(const ::MIR::LValue::Storage& lv_root, ::HIR::TypeRef& ty) { - switch(lv.tag()) + switch(lv_root.tag()) { - case ::MIR::LValue::TAGDEAD: throw ""; + case ::MIR::LValue::Storage::TAGDEAD: throw ""; // --> Slots - TU_ARM(lv, Return, _e) { + TU_ARM(lv_root, Return, _e) { ty = this->frame.fcn.ret_ty; return ValueRef(this->frame.ret); } break; - TU_ARM(lv, Local, e) { + TU_ARM(lv_root, Local, e) { ty = this->frame.fcn.m_mir.locals.at(e); return ValueRef(this->frame.locals.at(e)); } break; - TU_ARM(lv, Argument, e) { - ty = this->frame.fcn.args.at(e.idx); - return ValueRef(this->frame.args.at(e.idx)); + TU_ARM(lv_root, Argument, e) { + ty = this->frame.fcn.args.at(e); + return ValueRef(this->frame.args.at(e)); } break; - TU_ARM(lv, Static, e) { - /*const*/ auto& s = this->thread.m_modtree.get_static(*e); + TU_ARM(lv_root, Static, e) { + /*const*/ auto& s = this->thread.m_modtree.get_static(e); ty = s.ty; return ValueRef(s.val); } break; - // --> Modifiers - TU_ARM(lv, Index, e) { - auto idx = get_value_ref(*e.idx).read_usize(0); - ::HIR::TypeRef array_ty; - auto base_val = get_value_and_type(*e.val, array_ty); - const auto* wrapper = array_ty.get_wrapper(); - if( !wrapper ) - { - LOG_ERROR("Indexing non-array/slice - " << array_ty); - } - else if( wrapper->type == TypeWrapper::Ty::Array ) - { - ty = array_ty.get_inner(); - base_val.m_offset += ty.get_size() * idx; - return base_val; - } - else if( wrapper->type == TypeWrapper::Ty::Slice ) - { - LOG_TODO("Slice index"); - } - else - { - LOG_ERROR("Indexing non-array/slice - " << array_ty); - throw "ERROR"; - } - } break; - TU_ARM(lv, Field, e) { - ::HIR::TypeRef composite_ty; - auto base_val = get_value_and_type(*e.val, 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() == HIR::TypeRef(RawType::Unreachable) ) - { - 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) { - ::HIR::TypeRef composite_ty; - auto base_val = get_value_and_type(*e.val, composite_ty); - LOG_DEBUG("Downcast - " << composite_ty); - - size_t inner_ofs; - ty = composite_ty.get_field(e.variant_index, inner_ofs); - base_val.m_offset += inner_ofs; - return base_val; - } - TU_ARM(lv, Deref, e) { - ::HIR::TypeRef ptr_ty; - auto val = get_value_and_type(*e.val, ptr_ty); - ty = ptr_ty.get_inner(); - LOG_DEBUG("val = " << val << ", (inner) ty=" << ty); - - 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 alloc = val.get_relocation(val.m_offset); - LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty); - // NOTE: No alloc can happen when dereferencing a zero-sized pointer - if( alloc.is_alloc() ) - { - LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc()); - } - size_t size; - - const auto meta_ty = ty.get_meta_type(); - ::std::shared_ptr meta_val; - // If the type has metadata, store it. - if( meta_ty != RawType::Unreachable ) + } + throw ""; + } + ValueRef get_value_and_type(const ::MIR::LValue& lv, ::HIR::TypeRef& ty) + { + auto vr = get_value_and_type_root(lv.m_root, ty); + for(const auto& w : lv.m_wrappers) + { + switch(w.tag()) { - 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( val.read_value(POINTER_SIZE, meta_size) ); + case ::MIR::LValue::Wrapper::TAGDEAD: throw ""; + // --> Modifiers + TU_ARM(w, Index, idx_var) { + auto idx = this->frame.locals.at(idx_var).read_usize(0); + const auto* wrapper = ty.get_wrapper(); + if( !wrapper ) + { + LOG_ERROR("Indexing non-array/slice - " << ty); + throw "ERROR"; + } + else if( wrapper->type == TypeWrapper::Ty::Array ) + { + ty = ty.get_inner(); + vr.m_offset += ty.get_size() * idx; + } + else if( wrapper->type == TypeWrapper::Ty::Slice ) + { + LOG_TODO("Slice index"); + } + else + { + LOG_ERROR("Indexing non-array/slice - " << ty); + throw "ERROR"; + } + } break; + TU_ARM(w, Field, fld_idx) { + // TODO: if there's metadata present in the base, but the inner doesn't have metadata, clear the metadata + size_t inner_ofs; + auto inner_ty = ty.get_field(fld_idx, inner_ofs); + LOG_DEBUG("Field - " << ty << "#" << fld_idx << " = @" << inner_ofs << " " << inner_ty); + vr.m_offset += inner_ofs; + if( inner_ty.get_meta_type() == HIR::TypeRef(RawType::Unreachable) ) + { + LOG_ASSERT(vr.m_size >= inner_ty.get_size(), "Field didn't fit in the value - " << inner_ty.get_size() << " required, but " << vr.m_size << " available"); + vr.m_size = inner_ty.get_size(); + } + ty = ::std::move(inner_ty); + } + TU_ARM(w, Downcast, variant_index) { + auto composite_ty = ::std::move(ty); + LOG_DEBUG("Downcast - " << composite_ty); - size_t slice_inner_size; - if( ty.has_slice_meta(slice_inner_size) ) { - size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; + size_t inner_ofs; + ty = composite_ty.get_field(variant_index, inner_ofs); + vr.m_offset += inner_ofs; } - //else if( ty == RawType::TraitObject) { - // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects - // size = alloc.get_size() - ofs; - //} - else { - LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); - size = alloc.get_size() - ofs; + TU_ARM(w, Deref, _) { + auto ptr_ty = ::std::move(ty); + ty = ptr_ty.get_inner(); + LOG_DEBUG("val = " << vr << ", (inner) ty=" << ty); + + LOG_ASSERT(vr.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty); + size_t ofs = vr.read_usize(0); + + // There MUST be a relocation at this point with a valid allocation. + auto alloc = vr.get_relocation(vr.m_offset); + LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty); + // NOTE: No alloc can happen when dereferencing a zero-sized pointer + if( alloc.is_alloc() ) + { + LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc()); } - } - else - { - 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(); - if( !alloc ) { - LOG_ERROR("Deref of a value with no relocation - " << val); + size_t size; + + const auto meta_ty = ty.get_meta_type(); + ::std::shared_ptr meta_val; + // If the type has metadata, store it. + if( meta_ty != RawType::Unreachable ) + { + auto meta_size = meta_ty.get_size(); + LOG_ASSERT(vr.m_size == POINTER_SIZE + meta_size, "Deref of " << ty << ", but pointer isn't correct size"); + meta_val = ::std::make_shared( vr.read_value(POINTER_SIZE, meta_size) ); + + size_t slice_inner_size; + if( ty.has_slice_meta(slice_inner_size) ) { + size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; + } + //else if( ty == RawType::TraitObject) { + // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects + // size = alloc.get_size() - ofs; + //} + else { + LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + size = alloc.get_size() - ofs; + } + } + else + { + LOG_ASSERT(vr.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << vr << ") - " << vr << ": " << ptr_ty); + size = ty.get_size(); + if( !alloc ) { + LOG_ERROR("Deref of a value with no relocation - " << vr); + } } - } - LOG_DEBUG("alloc=" << alloc << ", ofs=" << ofs << ", size=" << size); - auto rv = ValueRef(::std::move(alloc), ofs, size); - rv.m_metadata = ::std::move(meta_val); - return rv; - } break; + LOG_DEBUG("alloc=" << alloc << ", ofs=" << ofs << ", size=" << size); + vr = ValueRef(::std::move(alloc), ofs, size); + vr.m_metadata = ::std::move(meta_val); + } break; + } } - throw ""; + return vr; } ValueRef get_value_ref(const ::MIR::LValue& lv) { @@ -1907,7 +1911,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c return true; } -bool InterpreterThread::call_intrinsic(Value& rv, const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector args) +bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const ::HIR::PathParams& ty_params, ::std::vector args) { TRACE_FUNCTION_R(name, rv); for(const auto& a : args) diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 6f02ffee..2966e7bf 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -77,7 +77,7 @@ private: // Returns true if the call was resolved instantly bool call_extern(Value& ret_val, const ::std::string& name, const ::std::string& abi, ::std::vector args); // Returns true if the call was resolved instantly - bool call_intrinsic(Value& ret_val, const ::std::string& name, const ::HIR::PathParams& pp, ::std::vector args); + bool call_intrinsic(Value& ret_val, const RcString& name, const ::HIR::PathParams& pp, ::std::vector args); // Returns true if the call was resolved instantly bool drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_shallow=false); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 984662fe..82bbbf3f 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -332,9 +332,6 @@ bool Parser::parse_one() struct H { - static ::std::unique_ptr<::MIR::LValue> make_lvp(::MIR::LValue&& lv) { - return ::std::unique_ptr<::MIR::LValue>(new ::MIR::LValue(::std::move(lv))); - } // // Parse a LValue // @@ -357,7 +354,7 @@ bool Parser::parse_one() if( name.substr(0,3) == "arg" ) { try { auto idx = static_cast( ::std::stol(name.substr(3)) ); - lv = ::MIR::LValue::make_Argument({ idx }); + lv = ::MIR::LValue::new_Argument( idx ); } catch(const ::std::exception& e) { LOG_ERROR(lex << "Invalid argument name - " << name << " - " << e.what()); @@ -365,7 +362,7 @@ bool Parser::parse_one() } // Hard-coded "RETURN" lvalue else if( name == "RETURN" ) { - lv = ::MIR::LValue::make_Return({}); + lv = ::MIR::LValue::new_Return(); } // Otherwise, look up variable names else { @@ -373,13 +370,13 @@ bool Parser::parse_one() if( it == var_names.end() ) { LOG_ERROR(lex << "Cannot find variable named '" << name << "'"); } - lv = ::MIR::LValue::make_Local(static_cast(it - var_names.begin())); + lv = ::MIR::LValue::new_Local(static_cast(it - var_names.begin())); } } else if( lex.next() == "::" || lex.next() == '<' ) { auto path = p.parse_path(); - lv = ::MIR::LValue( ::std::make_unique(::std::move(path)) ); + lv = ::MIR::LValue::new_Static( ::std::move(path) ); } else { LOG_ERROR(lex << "Unexpected token in LValue - " << lex.next()); @@ -390,19 +387,19 @@ bool Parser::parse_one() { lex.check(TokenClass::Integer); auto idx = static_cast( lex.consume().integer() ); - lv = ::MIR::LValue::make_Downcast({ make_lvp(::std::move(lv)), idx }); + lv = ::MIR::LValue::new_Downcast(::std::move(lv), idx); } else if( lex.consume_if('.') ) { lex.check(TokenClass::Integer); auto idx = static_cast( lex.consume().integer() ); - lv = ::MIR::LValue::make_Field({ make_lvp(::std::move(lv)), idx }); + lv = ::MIR::LValue::new_Field( ::std::move(lv), idx ); } else if( lex.next() == '[' ) { lex.consume(); auto idx_lv = parse_lvalue(p, var_names); - lv = ::MIR::LValue::make_Index({ make_lvp(::std::move(lv)), make_lvp(::std::move(idx_lv)) }); + lv = ::MIR::LValue::new_Index(::std::move(lv), idx_lv.as_Local()); lex.check_consume(']'); } else @@ -412,7 +409,7 @@ bool Parser::parse_one() } while(deref --) { - lv = ::MIR::LValue::make_Deref({ make_lvp(::std::move(lv)) }); + lv = ::MIR::LValue::new_Deref( ::std::move(lv) ); } return lv; } @@ -936,7 +933,7 @@ bool Parser::parse_one() lex.check_consume(')'); } else if( lex.next() == TokenClass::String ) { - auto name = ::std::move(lex.consume().strval); + auto name = RcString::new_interned(lex.consume().strval); auto params = parse_pathparams(); ct = ::MIR::CallTarget::make_Intrinsic({ ::std::move(name), ::std::move(params) }); } diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index efa0a034..653104df 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -11,6 +11,7 @@ #include #include +#include "../../src/include/rc_string.hpp" #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" #include "value.hpp" -- 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/miri.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 b105e1ef0310454a96899d5fb815257a7fda88f0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 20 Jul 2019 16:46:38 +0800 Subject: standalone_miri - Improved logging for allocation tags --- tools/standalone_miri/miri.cpp | 2 ++ tools/standalone_miri/value.cpp | 16 +++++++++------- tools/standalone_miri/value.hpp | 5 +++++ 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 3d28c542..d9402aa3 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1459,6 +1459,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) if( !this->call_path(rv, *fcn_p, ::std::move(sub_args)) ) { // Early return, don't want to update stmt_idx yet + LOG_DEBUG("- Non-immediate return, do not advance yet"); return false; } } @@ -1534,6 +1535,7 @@ InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vectorlocals.reserve( fcn.m_mir.locals.size() ); for(const auto& ty : fcn.m_mir.locals) { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 3a479bce..4318d289 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -13,6 +13,12 @@ #include #include "debug.hpp" +::std::ostream& operator<<(::std::ostream& os, const Allocation* x) +{ + os << "A(" << static_cast(x) << " " << x->tag() << ")"; + return os; +} + FfiLayout FfiLayout::new_const_bytes(size_t s) { return FfiLayout { @@ -53,6 +59,7 @@ AllocationHandle Allocation::new_alloc(size_t size, ::std::string tag) rv->data.resize( (size + 8-1) / 8 ); // QWORDS rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes //LOG_DEBUG(rv << " ALLOC"); + LOG_DEBUG(rv); return AllocationHandle(rv); } AllocationHandle::AllocationHandle(const AllocationHandle& x): @@ -319,11 +326,6 @@ 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 ); @@ -868,7 +870,7 @@ 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 << " "; + os << &alloc << "@" << v.m_offset << "+" << v.m_size << " "; auto flags = os.flags(); os << ::std::hex; @@ -923,7 +925,7 @@ 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 << " "; + os << &alloc << "@" << v.m_offset << "+" << v.m_size << " "; auto flags = os.flags(); os << ::std::hex; diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 8db17f03..59a570f0 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -303,6 +303,11 @@ struct Value: Value(); Value(::HIR::TypeRef ty); + //Value(const Value&) = delete; + //Value(Value&&) = default; + //Value& operator=(const Value&) = delete; + //Value& operator=(Value&&) = default; + 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); -- cgit v1.2.3 From c96d5e03c73d0cd171b29c387601776174e811b8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Jul 2019 13:47:27 +0800 Subject: standalone_miri - Improved logging, fix incorrect offset when getting relocations (1.29 hello is working) --- tools/standalone_miri/miri.cpp | 41 ++++++++++++++++++++++++++--------------- tools/standalone_miri/value.hpp | 4 ++-- 2 files changed, 28 insertions(+), 17 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index d9402aa3..1d350a3c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -17,6 +17,7 @@ # define NOMINMAX # include #endif +#undef DEBUG unsigned ThreadState::s_next_tls_key = 1; @@ -336,18 +337,22 @@ struct MirHelpers TU_ARM(w, Deref, _) { auto ptr_ty = ::std::move(ty); ty = ptr_ty.get_inner(); - LOG_DEBUG("val = " << vr << ", (inner) ty=" << ty); + LOG_DEBUG("Deref - " << vr << " into " << ty); LOG_ASSERT(vr.m_size >= POINTER_SIZE, "Deref of a value that doesn't fit a pointer - " << ty); size_t ofs = vr.read_usize(0); + auto alloc = vr.get_relocation(0); // There MUST be a relocation at this point with a valid allocation. - auto alloc = vr.get_relocation(vr.m_offset); - LOG_TRACE("Deref " << alloc << " + " << ofs << " to give value of type " << ty); + LOG_TRACE("Interpret " << alloc << " + " << ofs << " as value of type " << ty); // NOTE: No alloc can happen when dereferencing a zero-sized pointer if( alloc.is_alloc() ) { - LOG_DEBUG("> " << lv << " alloc=" << alloc.alloc()); + LOG_DEBUG("Deref - lvr=" << ::MIR::LValue::CRef(lv, &w - &lv.m_wrappers.front()) << " alloc=" << alloc.alloc()); + } + else + { + LOG_ASSERT(ty.get_meta_type() != RawType::Unreachable || ty.get_size() >= 0, "Dereference (giving a non-ZST) with no allocation"); } size_t size; @@ -370,6 +375,7 @@ struct MirHelpers //} else { LOG_DEBUG("> Meta " << *meta_val << ", size = " << alloc.get_size() << " - " << ofs); + // TODO: if the inner type is a trait object, then check that it has an allocation. size = alloc.get_size() - ofs; } } @@ -382,7 +388,7 @@ struct MirHelpers } } - LOG_DEBUG("alloc=" << alloc << ", ofs=" << ofs << ", size=" << size); + LOG_DEBUG("Deref - New VR: alloc=" << alloc << ", ofs=" << ofs << ", size=" << size); vr = ValueRef(::std::move(alloc), ofs, size); vr.m_metadata = ::std::move(meta_val); } break; @@ -608,8 +614,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) ::HIR::TypeRef src_ty; ValueRef src_base_value = state.get_value_and_type(re.val, src_ty); auto alloc = src_base_value.m_alloc; + // If the source doesn't yet have a relocation, give it a backing allocation so we can borrow if( !alloc && src_base_value.m_value ) { + LOG_DEBUG("Borrow - Creating allocation for " << src_base_value); if( !src_base_value.m_value->allocation ) { src_base_value.m_value->create_allocation(); @@ -617,14 +625,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation ); } if( alloc.is_alloc() ) - LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")"); + LOG_DEBUG("Borrow - alloc=" << alloc << " (" << alloc.alloc() << ")"); else - LOG_DEBUG("- alloc=" << alloc); + LOG_DEBUG("Borrow - alloc=" << alloc); size_t ofs = src_base_value.m_offset; const auto meta = src_ty.get_meta_type(); auto dst_ty = src_ty.wrapped(TypeWrapper::Ty::Borrow, static_cast(re.type)); + LOG_DEBUG("Borrow - ofs=" << ofs << ", meta_ty=" << meta); - // Create the pointer + // Create the pointer (can this just store into the target?) new_val = Value(dst_ty); new_val.write_ptr(0, ofs, ::std::move(alloc)); // - Add metadata if required @@ -960,8 +969,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) //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 ? */v_l.get_relocation(v_l.m_offset)/* : RelocationPtr()*/; - auto reloc_r = /*alloc_r ? */v_r.get_relocation(v_r.m_offset)/* : RelocationPtr()*/; + auto reloc_l = /*alloc_l ? */v_l.get_relocation(0)/* : RelocationPtr()*/; + auto reloc_r = /*alloc_r ? */v_r.get_relocation(0)/* : RelocationPtr()*/; if( reloc_l != reloc_r ) { @@ -1292,7 +1301,9 @@ bool InterpreterThread::step_one(Value& out_thread_result) for(size_t i = 0; i < re.vals.size(); i++) { auto fld_ofs = data_ty.fields.at(i).first; - new_val.write_value(fld_ofs, state.param_to_value(re.vals[i])); + auto v = state.param_to_value(re.vals[i]); + LOG_DEBUG("Struct - @" << fld_ofs << " = " << v); + new_val.write_value(fld_ofs, ::std::move(v)); } } break; } @@ -1448,7 +1459,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) // TODO: Assert type // TODO: Assert offset/content. assert(v.read_usize(0) == 0); - fcn_alloc_ptr = v.get_relocation(v.m_offset); + fcn_alloc_ptr = v.get_relocation(0); if( !fcn_alloc_ptr ) LOG_FATAL("Calling value with no relocation - " << v); LOG_ASSERT(fcn_alloc_ptr.get_ty() == RelocationPtr::Ty::Function, "Calling value that isn't a function pointer"); @@ -1637,7 +1648,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // TODO: Should this instead make a new allocation to catch use-after-free? rv = ::std::move(args.at(0)); } - else if( link_name == "__rust_deallocate" ) + else if( link_name == "__rust_deallocate" || link_name == "__rust_dealloc" ) { LOG_ASSERT(args.at(0).allocation, "__rust_deallocate first argument doesn't have an allocation"); auto alloc_ptr = args.at(0).get_relocation(0); @@ -1950,10 +1961,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: size_t ofs = ptr_val.read_usize(0); alloc.alloc().write_value(ofs, ::std::move(data_val)); } - else if( name == "atomic_load" || name == "atomic_load_relaxed" ) + else if( name == "atomic_load" || name == "atomic_load_relaxed" || name == "atomic_load_acq" ) { auto& ptr_val = args.at(0); - LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value"); + LOG_ASSERT(ptr_val.size() == POINTER_SIZE, "atomic_load of a value that isn't a pointer-sized value"); // There MUST be a relocation at this point with a valid allocation. auto alloc = ptr_val.get_relocation(0); diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 59a570f0..9c780351 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -398,13 +398,13 @@ struct ValueRef: if(m_alloc) { if( m_alloc.is_alloc() ) - return m_alloc.alloc().get_relocation(ofs); + return m_alloc.alloc().get_relocation(m_offset + ofs); else return RelocationPtr(); } else if( m_value ) { - return m_value->get_relocation(ofs); + return m_value->get_relocation(m_offset + ofs); } else { -- cgit v1.2.3 From eab86ffcd2f7608c744b72befba6201989ba32f1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 09:56:35 +0800 Subject: standalone_miri - Misc tweaks --- tools/standalone_miri/miri.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 1d350a3c..e6b56192 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -305,7 +305,11 @@ struct MirHelpers } else if( wrapper->type == TypeWrapper::Ty::Slice ) { - LOG_TODO("Slice index"); + ty = ty.get_inner(); + LOG_ASSERT(vr.m_metadata, "No slice metadata"); + auto len = vr.m_metadata->read_usize(0); + LOG_ASSERT(idx < len, "Slice index out of range"); + vr.m_offset += ty.get_size() * idx; } else { @@ -1098,6 +1102,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) break; case RawType::U8: case RawType::I8: + case RawType::Bool: new_val.write_u8 ( 0, static_cast(Ops::do_bitwise(v_l.read_u8 (0), v_r.read_u8 (0), re.op)) ); break; case RawType::USize: @@ -1539,7 +1544,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector args): fcn(fcn), - ret( fcn.ret_ty ), + ret( fcn.ret_ty == RawType::Unreachable ? Value() : Value(fcn.ret_ty) ), args( ::std::move(args) ), locals( ), drop_flags( fcn.m_mir.drop_flags ), @@ -1550,6 +1555,7 @@ InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vectorlocals.reserve( fcn.m_mir.locals.size() ); for(const auto& ty : fcn.m_mir.locals) { + LOG_DEBUG("_" << (&ty - &fcn.m_mir.locals.front()) << ": " << ty); if( ty == RawType::Unreachable ) { // HACK: Locals can be !, but they can NEVER be accessed this->locals.push_back( Value() ); -- cgit v1.2.3 From 85bc7996313b4df50cbb227ae25c0721f7f5eadd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 16:35:38 +0800 Subject: Standalone miri - Fix handling of `str` deref --- tools/standalone_miri/miri.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index e6b56192..8fe941d9 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -371,7 +371,9 @@ struct MirHelpers size_t slice_inner_size; if( ty.has_slice_meta(slice_inner_size) ) { - size = (ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; + // Slice metadata, add the base size (if it's a struct) to the variable size + // - `get_wrapper` will return non-null for `[T]`, special-case `str` + size = (ty != RawType::Str && ty.get_wrapper() == nullptr ? ty.get_size() : 0) + meta_val->read_usize(0) * slice_inner_size; } //else if( ty == RawType::TraitObject) { // // NOTE: Getting the size from the allocation is semi-valid, as you can't sub-slice trait objects -- cgit v1.2.3 From 17615468f01bbe83486500f9cc4020b4cd3b6e8b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 18:13:51 +0800 Subject: Standalone miri - General fixes trying to get a test running --- tools/standalone_miri/debug.hpp | 2 +- tools/standalone_miri/miri.cpp | 94 ++++++++++++++++++++++++++++------------- tools/standalone_miri/value.cpp | 2 +- tools/standalone_miri/value.hpp | 32 ++++++++++---- 4 files changed, 90 insertions(+), 40 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') 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("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("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(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(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(x) << " " << x->tag() << ")"; + os << "A(" << static_cast(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 // memcpy #include +#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"; -- cgit v1.2.3 From 2c7799d737dfe44e805a5e66877ee1b7b12d06ed Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 20:14:35 +0800 Subject: Standalone MIRI - SwitcValue, slice drops, char cast, ... --- tools/standalone_miri/miri.cpp | 173 ++++++++++++++++++++++++++++++++++------- tools/standalone_miri/miri.hpp | 2 +- 2 files changed, 148 insertions(+), 27 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index ef8a71c9..d4bb267c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -269,15 +269,15 @@ struct MirHelpers case ::MIR::LValue::Storage::TAGDEAD: throw ""; // --> Slots TU_ARM(lv_root, Return, _e) { - ty = this->frame.fcn.ret_ty; + ty = this->frame.fcn->ret_ty; return ValueRef(this->frame.ret); } break; TU_ARM(lv_root, Local, e) { - ty = this->frame.fcn.m_mir.locals.at(e); + ty = this->frame.fcn->m_mir.locals.at(e); return ValueRef(this->frame.locals.at(e)); } break; TU_ARM(lv_root, Argument, e) { - ty = this->frame.fcn.args.at(e); + ty = this->frame.fcn->args.at(e); return ValueRef(this->frame.args.at(e)); } break; TU_ARM(lv_root, Static, e) { @@ -571,8 +571,8 @@ InterpreterThread::~InterpreterThread() } else { - ::std::cout << frame.fcn.my_path << " BB" << frame.bb_idx << "/"; - if( frame.stmt_idx == frame.fcn.m_mir.blocks.at(frame.bb_idx).statements.size() ) + ::std::cout << frame.fcn->my_path << " BB" << frame.bb_idx << "/"; + if( frame.stmt_idx == frame.fcn->m_mir.blocks.at(frame.bb_idx).statements.size() ) ::std::cout << "TERM"; else ::std::cout << frame.stmt_idx; @@ -594,8 +594,8 @@ 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 << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, ""); - const auto& bb = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); + 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; if( this->m_stack.size() > MAX_STACK_DEPTH ) @@ -795,7 +795,15 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Bool: LOG_TODO("Cast to " << re.type); case RawType::Char: - LOG_TODO("Cast to " << re.type); + switch(src_ty.inner_type) + { + case RawType::Char: new_val.write_u32(0, src_value.read_u32(0) ); break; + case RawType::U8: new_val.write_u32(0, src_value.read_u8(0) ); break; + default: + LOG_ERROR("Cat from " << src_ty << " to char isn't valid"); + break; + } + break; case RawType::USize: case RawType::U8: case RawType::U16: @@ -1031,6 +1039,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::I8 : res = res != 0 ? res : Ops::do_compare(v_l.read_i8 (0), v_r.read_i8 (0)); break; case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break; case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; + case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1440,8 +1449,65 @@ bool InterpreterThread::step_one(Value& out_thread_result) } cur_frame.bb_idx = te.targets.at(found_target); } break; - TU_ARM(bb.terminator, SwitchValue, _te) - LOG_TODO("Terminator::SwitchValue"); + TU_ARM(bb.terminator, SwitchValue, te) { + ::HIR::TypeRef ty; + auto v = state.get_value_and_type(te.val, ty); + TU_MATCH_HDRA( (te.values), {) + TU_ARMA(Unsigned, vals) { + LOG_ASSERT(vals.size() == te.targets.size(), "Mismatch in SwitchValue target/value list lengths"); + // Read an unsigned value + if( ty.get_wrapper() ) { + LOG_ERROR("Terminator::SwitchValue::Unsigned with wrapped type - " << ty); + } + uint64_t switch_val; + switch(ty.inner_type) + { + case RawType::U8: switch_val = v.read_u8(0); break; + case RawType::U16: switch_val = v.read_u16(0); break; + case RawType::U32: switch_val = v.read_u32(0); break; + case RawType::U64: switch_val = v.read_u64(0); break; + case RawType::U128: LOG_TODO("Terminator::SwitchValue::Unsigned with u128"); + case RawType::USize: switch_val = v.read_usize(0); break; + default: + LOG_ERROR("Terminator::SwitchValue::Unsigned with unexpected type - " << ty); + } + + auto it = ::std::find(vals.begin(), vals.end(), switch_val); + if( it != vals.end() ) + { + auto idx = it - vals.begin(); + LOG_TRACE("- " << switch_val << " matched arm " << idx); + cur_frame.bb_idx = te.targets.at(idx); + } + else + { + LOG_TRACE("- " << switch_val << " not matched, taking default arm"); + cur_frame.bb_idx = te.def_target; + } + } + TU_ARMA(Signed, vals) { + if( ty.get_wrapper() ) { + LOG_ERROR("Terminator::SwitchValue::Signed with wrapped type - " << ty); + } + int64_t switch_val; + switch(ty.inner_type) + { + case RawType::I8: switch_val = v.read_i8(0); break; + case RawType::I16: switch_val = v.read_i16(0); break; + case RawType::I32: switch_val = v.read_i32(0); break; + case RawType::I64: switch_val = v.read_i64(0); break; + case RawType::I128: LOG_TODO("Terminator::SwitchValue::Signed with i128"); + case RawType::ISize: switch_val = v.read_isize(0); break; + default: + LOG_ERROR("Terminator::SwitchValue::Signed with unexpected type - " << ty); + } + LOG_TODO("Terminator::SwitchValue (signed) - " << ty << " " << switch_val); + } + TU_ARMA(String, vals) { + LOG_TODO("Terminator::SwitchValue (string) - " << ty << " " << v); + } + } + } TU_ARM(bb.terminator, Call, te) { ::std::vector sub_args; sub_args.reserve(te.args.size()); for(const auto& a : te.args) @@ -1488,7 +1554,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) return false; } } - LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn->my_path << ")"); state.write_lvalue(te.ret_val, rv); cur_frame.bb_idx = te.ret_block; } break; @@ -1528,19 +1594,19 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) auto& cur_frame = this->m_stack.back(); MirHelpers state { *this, cur_frame }; - const auto& blk = cur_frame.fcn.m_mir.blocks.at( cur_frame.bb_idx ); + const auto& blk = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx ); if( cur_frame.stmt_idx < blk.statements.size() ) { assert( blk.statements[cur_frame.stmt_idx].is_Drop() ); cur_frame.stmt_idx ++; - LOG_DEBUG("DROP complete (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG("DROP complete (resume " << cur_frame.fcn->my_path << ")"); } else { assert( blk.terminator.is_Call() ); const auto& te = blk.terminator.as_Call(); - LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn.my_path << ")"); + LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn->my_path << ")"); state.write_lvalue(te.ret_val, res_v); cur_frame.stmt_idx = 0; @@ -1552,7 +1618,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) } InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector args): - fcn(fcn), + fcn(&fcn), ret( fcn.ret_ty == RawType::Unreachable ? Value() : Value(fcn.ret_ty) ), args( ::std::move(args) ), locals( ), @@ -1633,6 +1699,27 @@ extern "C" { #endif bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, const ::std::string& abi, ::std::vector args) { + struct FfiHelpers { + static const char* read_cstr(const Value& v, size_t ptr_ofs, size_t* out_strlen=nullptr) + { + bool _is_mut; + size_t size; + // Get the base pointer and allocation size (checking for at least one valid byte to start with) + const char* ptr = reinterpret_cast( v.read_pointer_unsafe(0, 1, /*out->*/ size, _is_mut) ); + size_t len = 0; + // Seek until either out of space, or a NUL is found + while(size -- && *ptr) + { + ptr ++; + len ++; + } + if( out_strlen ) + { + *out_strlen = len; + } + return reinterpret_cast(v.read_pointer_const(0, len + 1)); // Final read will trigger an error if the NUL isn't there + } + }; if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) { static unsigned s_alloc_count = 0; @@ -1923,21 +2010,35 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c else if( link_name == "strlen" ) { // strlen - custom implementation to ensure validity - bool _is_mut; - size_t size; - const char* ptr = reinterpret_cast( args.at(0).read_pointer_unsafe(0, 1, size, _is_mut) ); size_t len = 0; - while(size -- && *ptr) - { - ptr ++; - len ++; - } - args.at(0).read_pointer_const(0, len + 1); + FfiHelpers::read_cstr(args.at(0), 0, &len); //rv = Value::new_usize(len); rv = Value(::HIR::TypeRef(RawType::USize)); rv.write_usize(0, len); } + else if( link_name == "getenv" ) + { + const auto* name = FfiHelpers::read_cstr(args.at(0), 0); + LOG_DEBUG("getenv(\"" << name << "\")"); + const auto* ret_ptr = getenv(name); + if( ret_ptr ) + { + LOG_DEBUG("= \"" << ret_ptr << "\""); + rv = Value::new_ffiptr(FFIPointer::new_const_bytes(ret_ptr, strlen(ret_ptr)+1)); + } + else + { + LOG_DEBUG("= NULL"); + rv = Value(::HIR::TypeRef(RawType::USize)); + rv.create_allocation(); + rv.write_usize(0,0); + } + } + else if( link_name == "setenv" ) + { + LOG_TODO("Allow `setenv` without incurring thread unsafety"); + } // Allocators! else { @@ -2367,8 +2468,28 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ for(uint64_t i = 0; i < count; i ++) { auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); - if( !drop_value(ptr, ity) ) { - LOG_TODO("Handle closure looping when dropping a slice"); + if( !drop_value(ptr, ity) ) + { + // - This is trying to invoke custom drop glue, need to suspend this operation and come back later + + // > insert a new frame shim BEFORE the current top (which would be the frame created by + // `drop_value` calling a function) + m_stack.insert( m_stack.end() - 1, StackFrame::make_wrapper([this,pty,ity,ptr_reloc,count, i,ofs](Value& rv, Value drop_rv) mutable { + assert(i < count); + i ++; + if( i < count ) + { + auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); + ofs += ity.get_size(); + assert(!drop_value(ptr, ity)); + return false; + } + else + { + return true; + } + }) ); + return false; } ofs += ity.get_size(); } diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 2966e7bf..3181a116 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -36,7 +36,7 @@ class InterpreterThread struct StackFrame { ::std::function cb; - const Function& fcn; + const Function* fcn; Value ret; ::std::vector args; ::std::vector locals; -- cgit v1.2.3 From 7f6d0fed8b2d713daa1668c66ffdcc5ac89d7874 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 21:33:28 +0800 Subject: standalone miri - stat, errno, char casts --- tools/standalone_miri/miri.cpp | 38 +++++++++++++++++-- tools/standalone_miri/value.cpp | 82 +++++++++++++++-------------------------- tools/standalone_miri/value.hpp | 31 +++++++++++++--- 3 files changed, 90 insertions(+), 61 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index d4bb267c..c955ef3b 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -12,11 +12,13 @@ #include #include "debug.hpp" #include "miri.hpp" +// VVV FFI #include // memrchr #ifdef _WIN32 # define NOMINMAX # include #endif +#include #undef DEBUG unsigned ThreadState::s_next_tls_key = 1; @@ -800,7 +802,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Char: new_val.write_u32(0, src_value.read_u32(0) ); break; case RawType::U8: new_val.write_u32(0, src_value.read_u8(0) ); break; default: - LOG_ERROR("Cat from " << src_ty << " to char isn't valid"); + LOG_ERROR("Cast from " << src_ty << " to char isn't valid"); break; } break; @@ -829,8 +831,21 @@ bool InterpreterThread::step_one(Value& out_thread_result) new_val = src_value.read_value(0, re.type.get_size()); break; case RawType::Char: - 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); + switch(re.type.inner_type) + { + case RawType::U8: { + uint32_t v = src_value.read_u32(0); + if( v > 0xFF ) { + LOG_NOTICE("Casting to u8 from char above 255"); + } + new_val.write_u8(0, v & 0xFF); + } break; + case RawType::U32: + new_val = src_value.read_value(0, 4); + break; + default: + LOG_ERROR("Char can only be casted to u32/u8, instead " << re.type); + } break; case RawType::Unit: LOG_FATAL("Cast of unit"); @@ -1948,6 +1963,23 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + // - Linux extensions + else if( link_name == "stat64" ) + { + const auto* path = FfiHelpers::read_cstr(args.at(0), 0); + auto outbuf_vr = args.at(1).read_pointer_valref_mut(0, sizeof(struct stat)); + + LOG_DEBUG("stat64(\"" << path << "\", " << outbuf_vr << ")"); + int rv_i = stat(path, reinterpret_cast(outbuf_vr.data_ptr_mut())); + LOG_DEBUG("= " << rv_i); + + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, rv_i); + } + else if( link_name == "__errno_location" ) + { + rv = Value::new_ffiptr(FFIPointer::new_const_bytes(&errno, sizeof(errno))); + } #endif // std C else if( link_name == "signal" ) diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 7344ef46..3fb4c238 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -13,6 +13,16 @@ #include #include "debug.hpp" +namespace { + 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; + } +}; + ::std::ostream& operator<<(::std::ostream& os, const Allocation* x) { os << "A(" << static_cast(x) << " " << x->tag() /*<< " +" << x->size()*/ << ")"; @@ -207,7 +217,7 @@ size_t RelocationPtr::get_size() const os << "\"" << x.str() << "\""; break; case RelocationPtr::Ty::FfiPointer: - os << "FFI " << x.ffi().tag_name << " " << x.ffi().ptr_value; + os << "FFI '" << x.ffi().tag_name << "' " << x.ffi().ptr_value; break; } } @@ -314,7 +324,7 @@ void Allocation::resize(size_t new_size) void Allocation::check_bytes_valid(size_t ofs, size_t size) const { - if( !(ofs + size <= this->size()) ) { + if( !in_bounds(ofs, size, this->size()) ) { LOG_FATAL("Out of range - " << ofs << "+" << size << " > " << this->size()); } for(size_t i = ofs; i < ofs + size; i++) @@ -410,15 +420,7 @@ void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const if(count == 0) return ; - if(ofs >= this->size() ) { - LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - if(count > this->size() ) { - LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - if(ofs+count > this->size() ) { + if( !in_bounds(ofs, count, this->size()) ) { LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); throw "ERROR"; } @@ -507,15 +509,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count) 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"; - } - if(count > this->size() ) { - LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - if(ofs+count > this->size() ) { + if( !in_bounds(ofs, count, this->size()) ) { LOG_ERROR("Out of bounds write, " << ofs << "+" << count << " > " << this->size()); throw "ERROR"; } @@ -690,11 +684,7 @@ void Value::check_bytes_valid(size_t ofs, size_t size) const if( size == 0 && this->direct_data.size > 0 ) { return ; } - if( ofs >= this->direct_data.size ) { - LOG_ERROR("Read out of bounds " << ofs << "+" << size << " > " << int(this->direct_data.size)); - throw "ERROR"; - } - if( ofs+size > this->direct_data.size ) { + if( !in_bounds(ofs, size, this->direct_data.size) ) { LOG_ERROR("Read out of bounds " << ofs+size << " >= " << int(this->direct_data.size)); throw "ERROR"; } @@ -753,15 +743,8 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const { check_bytes_valid(ofs, count); - if(ofs >= this->direct_data.size ) { - LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - if(count > this->direct_data.size ) { - LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - if(ofs+count > this->direct_data.size ) { + // TODO: Redundant due to above? + if( !in_bounds(ofs, count, this->direct_data.size) ) { LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); throw "ERROR"; } @@ -779,13 +762,7 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) } else { - if(ofs >= this->direct_data.size ) { - LOG_BUG("Write to offset outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")"); - } - if(count > this->direct_data.size ){ - LOG_BUG("Write larger than value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")"); - } - if(ofs+count > this->direct_data.size ) { + if( !in_bounds(ofs, count, this->direct_data.size) ) { LOG_BUG("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")"); } ::std::memcpy(this->direct_data.data + ofs, src, count); @@ -905,9 +882,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) break; case RelocationPtr::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()); + assert( in_bounds(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++) @@ -987,7 +962,7 @@ Value ValueRef::read_value(size_t ofs, size_t size) const { if( size == 0 ) return Value(); - if( !(ofs < m_size && size <= m_size && ofs + size <= m_size) ) { + if( !in_bounds(ofs, size, m_size) ) { LOG_ERROR("Read exceeds bounds, " << ofs << " + " << size << " > " << m_size << " - from " << *this); } if( m_alloc ) { @@ -997,16 +972,19 @@ Value ValueRef::read_value(size_t ofs, size_t size) const return m_alloc.alloc().read_value(m_offset + ofs, size); case RelocationPtr::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()); + LOG_ASSERT(in_bounds(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"; + case RelocationPtr::Ty::FfiPointer: { + auto rv = Value::with_size(size, false); + LOG_ASSERT(in_bounds(ofs, size, m_alloc.ffi().get_size()), ""); + rv.write_bytes(0, reinterpret_cast(m_alloc.ffi().ptr_value) + m_offset + ofs, size); + return rv; + } + default: { + LOG_TODO("read_value from " << m_alloc); + } } } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 68fa492f..e8567d02 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -214,8 +214,7 @@ struct ValueCommonRead bool is_mut; void* rv = read_pointer_unsafe(rd_ofs, 0, out_size, is_mut); if(!is_mut) - throw ""; - //LOG_FATAL("Attempting to get an uninit pointer to immutable data"); + LOG_FATAL("Attempting to get an uninit pointer to immutable data"); return rv; } /// Read a pointer and return a ValueRef to it (mutable data) @@ -393,7 +392,7 @@ struct ValueRef: } break; default: - throw "TODO"; + LOG_TODO(""); } } } @@ -436,7 +435,7 @@ struct ValueRef: case RelocationPtr::Ty::StdString: return reinterpret_cast(m_alloc.str().data() + m_offset); default: - throw "TODO"; + LOG_TODO(""); } } else if( m_value ) { @@ -446,6 +445,26 @@ struct ValueRef: return nullptr; } } + uint8_t* data_ptr_mut() { + if( m_alloc ) { + switch(m_alloc.get_ty()) + { + case RelocationPtr::Ty::Allocation: + return m_alloc.alloc().data_ptr() + m_offset; + break; + default: + LOG_TODO(""); + } + } + else if( m_value ) { + return m_value->data_ptr() + m_offset; + } + else { + return nullptr; + } + } + void mark_valid(size_t ofs, size_t size); + void read_bytes(size_t ofs, void* dst, size_t size) const { if( size == 0 ) return ; @@ -464,7 +483,7 @@ struct ValueRef: break; default: //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << ); - throw "TODO"; + LOG_TODO(""); } } else { @@ -488,7 +507,7 @@ struct ValueRef: break; default: //ASSERT_BUG(m_alloc.is_alloc(), "read_value on non-data backed Value - " << ); - throw "TODO"; + LOG_TODO(""); } } else { -- cgit v1.2.3 From 2612c15cc92a7b9331a2bf6970df506d92b9c48f Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 22:27:21 +0800 Subject: Standalone MIRI - discriminant_value --- tools/standalone_miri/miri.cpp | 56 +++++++++++++++++++++++++++++++++++------ tools/standalone_miri/value.cpp | 10 +++++--- tools/standalone_miri/value.hpp | 5 +++- 3 files changed, 60 insertions(+), 11 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index c955ef3b..67023205 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -830,23 +830,26 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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: + case RawType::Char: { + uint32_t v = src_value.read_u32(0); switch(re.type.inner_type) { - case RawType::U8: { - uint32_t v = src_value.read_u32(0); + case RawType::U8: if( v > 0xFF ) { LOG_NOTICE("Casting to u8 from char above 255"); } new_val.write_u8(0, v & 0xFF); - } break; + break; case RawType::U32: new_val = src_value.read_value(0, 4); break; + case RawType::USize: + new_val.write_usize(0, v); + break; default: LOG_ERROR("Char can only be casted to u32/u8, instead " << re.type); } - break; + } break; case RawType::Unit: LOG_FATAL("Cast of unit"); case RawType::Composite: { @@ -2093,10 +2096,49 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { it = type_ids.insert(it, ty_T); } - + rv = Value::with_size(POINTER_SIZE, false); rv.write_usize(0, it - type_ids.begin()); } + else if( name == "discriminant_value" ) + { + const auto& ty = ty_params.tys.at(0); + ValueRef val = args.at(0).deref(0, ty); + + size_t fallback = SIZE_MAX; + size_t found_index = SIZE_MAX; + assert(ty.composite_type); + for(size_t i = 0; i < ty.composite_type->variants.size(); i ++) + { + const auto& var = ty.composite_type->variants[i]; + if( var.tag_data.size() == 0 ) + { + // Only seen in Option + assert(fallback == SIZE_MAX); + fallback = i; + } + else + { + // Get offset to the tag + ::HIR::TypeRef tag_ty; + size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty); + // Compare + if( val.compare(tag_ofs, var.tag_data.data(), var.tag_data.size()) == 0 ) + { + found_index = i; + break ; + } + } + } + + if( found_index == SIZE_MAX ) + { + LOG_ASSERT(fallback != SIZE_MAX, "Can't find variant of " << ty << " for " << val); + found_index = fallback; + } + + rv = Value::new_usize(found_index); + } else if( name == "atomic_fence" || name == "atomic_fence_acq" ) { rv = Value(); @@ -2192,7 +2234,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = Value::with_size( ty_T.get_size() + 1, false ); rv.write_value(0, data_ref.read_value(0, old_v.size())); LOG_DEBUG("> *ptr = " << data_ref); - if( data_ref.compare(old_v.data_ptr(), old_v.size()) == true ) { + if( data_ref.compare(0, old_v.data_ptr(), old_v.size()) == true ) { data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v ); rv.write_u8( old_v.size(), 1 ); } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 3fb4c238..363d980b 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -309,6 +309,10 @@ ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) return ValueRef(reloc, ofs, size); } } +ValueRef ValueCommonRead::deref(size_t ofs, const ::HIR::TypeRef& ty) +{ + return read_pointer_valref_mut(ofs, ty.get_size()); +} void Allocation::resize(size_t new_size) @@ -991,8 +995,8 @@ Value ValueRef::read_value(size_t ofs, size_t size) const return m_value->read_value(m_offset + ofs, size); } } -bool ValueRef::compare(const void* other, size_t other_len) const +bool ValueRef::compare(size_t offset, const void* other, size_t other_len) const { - check_bytes_valid(0, other_len); - return ::std::memcmp(data_ptr(), other, other_len) == 0; + check_bytes_valid(offset, other_len); + return ::std::memcmp(data_ptr() + offset, other, other_len) == 0; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index e8567d02..5e5ccc4f 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -201,6 +201,9 @@ struct ValueCommonRead uint64_t read_usize(size_t ofs) const; int64_t read_isize(size_t ofs) const { return static_cast(read_usize(ofs)); } + /// De-reference a pointer (of target type `ty`) at the given offset, and return a reference to it + ValueRef deref(size_t ofs, const ::HIR::TypeRef& ty); + /// Read a pointer from the value, requiring at least `req_valid` valid bytes, saves avaliable space in `size` void* read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& size, bool& is_mut) const; /// Read a pointer, requiring `req_len` valid bytes @@ -515,6 +518,6 @@ struct ValueRef: } } - bool compare(const void* other, size_t other_len) const; + bool compare(size_t offset, const void* other, size_t other_len) const; }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); -- cgit v1.2.3 From 40c8b8cdfd8dd4eca18a255f8b7b71e916ed6a38 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 3 Aug 2019 23:26:39 +0800 Subject: Standalone MIRI - u8/u16 arithmatic --- tools/standalone_miri/miri.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 67023205..9468303c 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -107,6 +107,20 @@ struct PrimitiveU32: public PrimitiveUInt tgt.write_u32(ofs, this->v); } }; +struct PrimitiveU16: public PrimitiveUInt +{ + PrimitiveU16(uint16_t v): PrimitiveUInt(v) {} + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { + tgt.write_u16(ofs, this->v); + } +}; +struct PrimitiveU8: public PrimitiveUInt +{ + PrimitiveU8(uint8_t v): PrimitiveUInt(v) {} + void write_to_value(ValueCommonWrite& tgt, size_t ofs) const override { + tgt.write_u8(ofs, this->v); + } +}; template struct PrimitiveSInt: public PrimitiveValue @@ -189,6 +203,12 @@ public: LOG_ASSERT(t.get_wrapper() == nullptr, "PrimitiveValueVirt::from_value: " << t); switch(t.inner_type) { + case RawType::U8: + new(&rv.buf) PrimitiveU8(v.read_u8(0)); + break; + case RawType::U16: + new(&rv.buf) PrimitiveU16(v.read_u16(0)); + break; case RawType::U32: new(&rv.buf) PrimitiveU32(v.read_u32(0)); break; -- cgit v1.2.3 From 8ae530e20301e32fe7ef9b539e502cc529805910 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 08:53:27 +0800 Subject: Standalone MIRI - More FFI open+fcntl --- tools/standalone_miri/miri.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 9468303c..f6ea1125 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -19,6 +19,7 @@ # include #endif #include +#include #undef DEBUG unsigned ThreadState::s_next_tls_key = 1; @@ -1987,6 +1988,19 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value::new_i32(0); } // - Linux extensions + else if( link_name == "open64" ) + { + const auto* path = FfiHelpers::read_cstr(args.at(0), 0); + auto flags = args.at(1).read_i32(0); + auto mode = (args.size() > 2 ? args.at(2).read_i32(0) : 0); + + LOG_DEBUG("open64(\"" << path << "\", " << flags << ")"); + int rv_i = open(path, flags, mode); + LOG_DEBUG("= " << rv_i); + + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, rv_i); + } else if( link_name == "stat64" ) { const auto* path = FfiHelpers::read_cstr(args.at(0), 0); @@ -1996,6 +2010,53 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c int rv_i = stat(path, reinterpret_cast(outbuf_vr.data_ptr_mut())); LOG_DEBUG("= " << rv_i); + if( rv_i == 0 ) + { + // TODO: Mark the buffer as valid? + } + + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, rv_i); + } + else if( link_name == "fcntl" ) + { + // `fcntl` has custom handling for the third argument, as some are pointers + int fd = args.at(0).read_i32(0); + int command = args.at(1).read_i32(0); + + int rv_i; + const char* name; + switch(command) + { + // - No argument + case F_GETFD: name = "F_GETFD"; if(0) + ; + { + LOG_DEBUG("fcntl(" << fd << ", " << name << ")"); + rv_i = fcntl(fd, command); + } break; + // - Integer arguments + case F_DUPFD: name = "F_DUPFD"; if(0) + case F_DUPFD_CLOEXEC: name = "F_DUPFD_CLOEXEC"; if(0) + case F_SETFD: name = "F_SETFD"; if(0) + ; + { + int arg = args.at(2).read_i32(0); + LOG_DEBUG("fcntl(" << fd << ", " << name << ", " << arg << ")"); + rv_i = fcntl(fd, command, arg); + } break; + default: + if( args.size() > 2 ) + { + LOG_TODO("fnctl(..., " << command << ", " << args[2] << ")"); + } + else + { + LOG_TODO("fnctl(..., " << command << ")"); + } + } + + LOG_DEBUG("= " << rv_i); rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, rv_i); } -- cgit v1.2.3 From 1cae9e657932e999d525c45ccaef325705319975 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 09:53:23 +0800 Subject: Standalone MIRI - `read` FFI --- tools/standalone_miri/miri.cpp | 27 ++++++++++++++++++++++++++- tools/standalone_miri/value.cpp | 17 +++++++++++++++++ tools/standalone_miri/value.hpp | 6 ++++-- 3 files changed, 47 insertions(+), 3 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index f6ea1125..8d9f31ed 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -20,6 +20,7 @@ #endif #include #include +#include #undef DEBUG unsigned ThreadState::s_next_tls_key = 1; @@ -1915,6 +1916,30 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value::new_isize(val); } + else if( link_name == "read" ) + { + auto fd = args.at(0).read_i32(0); + auto count = args.at(2).read_isize(0); + auto buf_vr = args.at(1).read_pointer_valref_mut(0, count); + + LOG_DEBUG("read(" << fd << ", " << buf_vr.data_ptr_mut() << ", " << count << ")"); + ssize_t val = read(fd, buf_vr.data_ptr_mut(), count); + LOG_DEBUG("= " << val); + + if( val > 0 ) + { + buf_vr.mark_bytes_valid(0, val); + } + + rv = Value::new_isize(val); + } + else if( link_name == "close" ) + { + auto fd = args.at(0).read_i32(0); + LOG_DEBUG("close(" << fd << ")"); + // TODO: Ensure that this FD is from the set known by the FFI layer + close(fd); + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -2224,7 +2249,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { rv = Value(); } - else if( name == "atomic_store" ) + else if( name == "atomic_store" || name == "atomic_store_relaxed" ) { auto& ptr_val = args.at(0); auto& data_val = args.at(1); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 363d980b..01f0fbbc 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -962,6 +962,23 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) return os; } +void ValueRef::mark_bytes_valid(size_t ofs, size_t size) +{ + if( m_alloc ) { + switch(m_alloc.get_ty()) + { + case RelocationPtr::Ty::Allocation: + m_alloc.alloc().mark_bytes_valid(m_offset + ofs, size); + break; + default: + LOG_TODO("mark_valid in " << m_alloc); + } + } + else { + m_value->mark_bytes_valid(m_offset + ofs, size); + } +} + Value ValueRef::read_value(size_t ofs, size_t size) const { if( size == 0 ) diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 5e5ccc4f..ebae2699 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -365,7 +365,7 @@ struct ValueRef: { struct H { static bool in_bounds(size_t ofs, size_t size, size_t max_size) { - if( !(ofs < max_size) ) + if( ofs > 0 && !(ofs < max_size) ) return false; if( !(size <= max_size) ) return false; @@ -448,6 +448,8 @@ struct ValueRef: return nullptr; } } + + // TODO: Remove these two (move to a helper?) uint8_t* data_ptr_mut() { if( m_alloc ) { switch(m_alloc.get_ty()) @@ -466,7 +468,7 @@ struct ValueRef: return nullptr; } } - void mark_valid(size_t ofs, size_t size); + void mark_bytes_valid(size_t ofs, size_t size); void read_bytes(size_t ofs, void* dst, size_t size) const { if( size == 0 ) -- cgit v1.2.3 From 4afb6ca5c167c8757bddf6dc44dd0f8bce7f8490 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 09:57:47 +0800 Subject: Standalone MIRI - isatty (and move fcntl) --- tools/standalone_miri/miri.cpp | 92 +++++++++++++++++++++++------------------- 1 file changed, 50 insertions(+), 42 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 8d9f31ed..2131ffe6 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1940,6 +1940,56 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // TODO: Ensure that this FD is from the set known by the FFI layer close(fd); } + else if( link_name == "isatty" ) + { + auto fd = args.at(0).read_i32(0); + LOG_DEBUG("isatty(" << fd << ")"); + int rv_i = isatty(fd); + LOG_DEBUG("= " << rv_i); + rv = Value::new_i32(rv_i); + } + else if( link_name == "fcntl" ) + { + // `fcntl` has custom handling for the third argument, as some are pointers + int fd = args.at(0).read_i32(0); + int command = args.at(1).read_i32(0); + + int rv_i; + const char* name; + switch(command) + { + // - No argument + case F_GETFD: name = "F_GETFD"; if(0) + ; + { + LOG_DEBUG("fcntl(" << fd << ", " << name << ")"); + rv_i = fcntl(fd, command); + } break; + // - Integer arguments + case F_DUPFD: name = "F_DUPFD"; if(0) + case F_DUPFD_CLOEXEC: name = "F_DUPFD_CLOEXEC"; if(0) + case F_SETFD: name = "F_SETFD"; if(0) + ; + { + int arg = args.at(2).read_i32(0); + LOG_DEBUG("fcntl(" << fd << ", " << name << ", " << arg << ")"); + rv_i = fcntl(fd, command, arg); + } break; + default: + if( args.size() > 2 ) + { + LOG_TODO("fnctl(..., " << command << ", " << args[2] << ")"); + } + else + { + LOG_TODO("fnctl(..., " << command << ")"); + } + } + + LOG_DEBUG("= " << rv_i); + rv = Value(::HIR::TypeRef(RawType::I32)); + rv.write_i32(0, rv_i); + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -2043,48 +2093,6 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, rv_i); } - else if( link_name == "fcntl" ) - { - // `fcntl` has custom handling for the third argument, as some are pointers - int fd = args.at(0).read_i32(0); - int command = args.at(1).read_i32(0); - - int rv_i; - const char* name; - switch(command) - { - // - No argument - case F_GETFD: name = "F_GETFD"; if(0) - ; - { - LOG_DEBUG("fcntl(" << fd << ", " << name << ")"); - rv_i = fcntl(fd, command); - } break; - // - Integer arguments - case F_DUPFD: name = "F_DUPFD"; if(0) - case F_DUPFD_CLOEXEC: name = "F_DUPFD_CLOEXEC"; if(0) - case F_SETFD: name = "F_SETFD"; if(0) - ; - { - int arg = args.at(2).read_i32(0); - LOG_DEBUG("fcntl(" << fd << ", " << name << ", " << arg << ")"); - rv_i = fcntl(fd, command, arg); - } break; - default: - if( args.size() > 2 ) - { - LOG_TODO("fnctl(..., " << command << ", " << args[2] << ")"); - } - else - { - LOG_TODO("fnctl(..., " << command << ")"); - } - } - - LOG_DEBUG("= " << rv_i); - rv = Value(::HIR::TypeRef(RawType::I32)); - rv.write_i32(0, rv_i); - } else if( link_name == "__errno_location" ) { rv = Value::new_ffiptr(FFIPointer::new_const_bytes(&errno, sizeof(errno))); -- cgit v1.2.3 From 982826e4b309979bee8fe10f6ff537b4922e6316 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 13:00:02 +0800 Subject: Standalone MIRI - General improvements --- tools/standalone_miri/miri.cpp | 96 ++++++++++++++++++++++++++++++++++++++--- tools/standalone_miri/value.cpp | 27 +++++++++++- tools/standalone_miri/value.hpp | 6 +++ 3 files changed, 121 insertions(+), 8 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 2131ffe6..674c7e6d 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -516,7 +516,12 @@ struct MirHelpers LOG_BUG("Constant::Const in mmir"); } break; TU_ARM(c, Bytes, ce) { - LOG_TODO("Constant::Bytes"); + 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_usize(POINTER_SIZE, ce.size()); + LOG_DEBUG(c << " = " << val); + return val; } break; TU_ARM(c, StaticString, ce) { ty = ::HIR::TypeRef(RawType::Str).wrap(TypeWrapper::Ty::Borrow, 0); @@ -1104,7 +1109,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case ::MIR::eBinOp::BIT_SHR: { LOG_ASSERT(ty_l.get_wrapper() == nullptr, "Bitwise operator on non-primitive - " << ty_l); LOG_ASSERT(ty_r.get_wrapper() == nullptr, "Bitwise operator with non-primitive - " << ty_r); - size_t max_bits = ty_r.get_size() * 8; + size_t max_bits = ty_l.get_size() * 8; uint8_t shift; auto check_cast_u = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast(v); }; auto check_cast_s = [&](auto v){ LOG_ASSERT(v <= static_cast(max_bits), "Shift out of range - " << v); return static_cast(v); }; @@ -1121,7 +1126,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::USize: shift = check_cast_u(v_r.read_usize(0)); break; case RawType::ISize: shift = check_cast_s(v_r.read_isize(0)); break; default: - LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + LOG_TODO("BinOp shift RHS unknown type - " << se.src << " w/ " << ty_r); } new_val = Value(ty_l); switch(ty_l.inner_type) @@ -1132,9 +1137,11 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast(shift), re.op)); break; case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(shift), re.op)); break; - // TODO: Is signed allowed? + // Is signed allowed? (yes) + // - What's the exact semantics? For now assuming it's unsigned+reinterpret + case RawType::ISize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast(shift), re.op)); break; default: - LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + LOG_TODO("BinOp shift LHS unknown type - " << se.src << " w/ " << ty_l); } } break; case ::MIR::eBinOp::BIT_AND: @@ -1170,16 +1177,45 @@ bool InterpreterThread::step_one(Value& out_thread_result) default: LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l); } + // If the LHS had a relocation, propagate it over + if( auto r = v_l.get_relocation(0) ) + { + LOG_DEBUG("- Restore relocation " << r); + new_val.create_allocation(); + new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), r); + } break; default: LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l); auto val_r = PrimitiveValueVirt::from_value(ty_r, v_r); + RelocationPtr new_val_reloc; switch(re.op) { - case ::MIR::eBinOp::ADD: val_l.get().add( val_r.get() ); break; - case ::MIR::eBinOp::SUB: val_l.get().subtract( val_r.get() ); break; + case ::MIR::eBinOp::ADD: + LOG_ASSERT(!v_r.get_relocation(0), "RHS of `+` has a relocation"); + new_val_reloc = v_l.get_relocation(0); + val_l.get().add( val_r.get() ); + break; + case ::MIR::eBinOp::SUB: + if( auto r = v_l.get_relocation(0) ) + { + if( v_r.get_relocation(0) ) + { + // Pointer difference, no relocation in output + } + else + { + new_val_reloc = ::std::move(r); + } + } + else + { + LOG_ASSERT(!v_r.get_relocation(0), "RHS of `-` has a relocation but LHS does not"); + } + val_l.get().subtract( val_r.get() ); + break; case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break; case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break; case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break; @@ -1189,6 +1225,11 @@ bool InterpreterThread::step_one(Value& out_thread_result) } new_val = Value(ty_l); val_l.get().write_to_value(new_val, 0); + if( new_val_reloc ) + { + new_val.create_allocation(); + new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), ::std::move(new_val_reloc)); + } break; } } break; @@ -2011,6 +2052,11 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + else if( link_name == "pthread_rwlock_unlock" ) + { + // TODO: Check that this thread holds the lock? + rv = Value::new_i32(0); + } else if( link_name == "pthread_mutexattr_init" || link_name == "pthread_mutexattr_settype" || link_name == "pthread_mutexattr_destroy" ) { rv = Value::new_i32(0); @@ -2062,6 +2108,20 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(0); } + // - Time + else if( link_name == "clock_gettime" ) + { + // int clock_gettime(clockid_t clk_id, struct timespec *tp); + auto clk_id = args.at(0).read_u32(0); + auto tp_vr = args.at(1).read_pointer_valref_mut(0, sizeof(struct timespec)); + + LOG_DEBUG("clock_gettime(" << clk_id << ", " << tp_vr); + int rv_i = clock_gettime(clk_id, reinterpret_cast(tp_vr.data_ptr_mut())); + if(rv_i == 0) + tp_vr.mark_bytes_valid(0, tp_vr.m_size); + LOG_DEBUG("= " << rv_i << " (" << tp_vr << ")"); + rv = Value::new_i32(rv_i); + } // - Linux extensions else if( link_name == "open64" ) { @@ -2097,6 +2157,14 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_ffiptr(FFIPointer::new_const_bytes(&errno, sizeof(errno))); } + else if( link_name == "syscall" ) + { + auto num = args.at(0).read_u32(0); + + LOG_DEBUG("syscall(" << num << ", ...) - hack return ENOSYS"); + errno = ENOSYS; + rv = Value::new_i64(-1); + } #endif // std C else if( link_name == "signal" ) @@ -2411,6 +2479,20 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = Value(ty_params.tys.at(0)); rv.mark_bytes_valid(0, rv.size()); } + else if( name == "write_bytes" ) + { + auto& dst_ptr_v = args.at(0); + auto byte = args.at(1).read_u8(0); + auto count = args.at(2).read_usize(0); + + LOG_DEBUG("'write_bytes'(" << dst_ptr_v << ", " << byte << ", " << count << ")"); + + if( count > 0 ) + { + auto dst_vr = dst_ptr_v.read_pointer_valref_mut(0, count); + memset(dst_vr.data_ptr_mut(), byte, count); + } + } // - Unsized stuff else if( name == "size_of_val" ) { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 01f0fbbc..232613b7 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -540,7 +540,27 @@ 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) { this->write_usize(ofs, ptr_ofs); - this->relocations.push_back(Relocation { ofs, /*POINTER_SIZE,*/ ::std::move(reloc) }); + this->set_reloc(ofs, POINTER_SIZE, ::std::move(reloc)); +} +void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc) +{ + LOG_ASSERT(ofs % POINTER_SIZE == 0, ""); + LOG_ASSERT(len == POINTER_SIZE, ""); + // Delete any existing relocation at this position + for(auto it = this->relocations.begin(); it != this->relocations.end();) + { + if( ofs <= it->slot_ofs && it->slot_ofs < ofs + len ) + { + // Slot starts in this updated region + // - TODO: Split in half? + it = this->relocations.erase(it); + continue ; + } + // TODO: What if the slot ends in the new region? + // What if the new region is in the middle of the slot + ++ it; + } + this->relocations.push_back(Relocation { ofs, /*len,*/ ::std::move(reloc) }); } ::std::ostream& operator<<(::std::ostream& os, const Allocation& x) { @@ -664,6 +684,11 @@ Value Value::new_i32(int32_t v) { rv.write_i32(0, v); return rv; } +Value Value::new_i64(int64_t v) { + auto rv = Value( ::HIR::TypeRef(RawType::I64) ); + rv.write_i64(0, v); + return rv; +} void Value::create_allocation() { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index ebae2699..19df8540 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -289,6 +289,8 @@ public: void write_value(size_t ofs, Value v); void write_bytes(size_t ofs, const void* src, size_t count) override; void write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) override; + + void set_reloc(size_t ofs, size_t len, RelocationPtr reloc); }; extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); @@ -320,6 +322,7 @@ struct Value: static Value new_isize(int64_t v); static Value new_u32(uint32_t v); static Value new_i32(int32_t v); + static Value new_i64(int64_t v); void create_allocation(); size_t size() const { return allocation ? allocation->size() : direct_data.size; } @@ -365,6 +368,9 @@ struct ValueRef: { 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) ) -- 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/miri.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/miri.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 dd04189c53be74e170daefbf0e4186ae8265da0b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 18:09:23 +0800 Subject: Standalone MIRI - More pointer fixes --- tools/standalone_miri/miri.cpp | 17 +++++++++++++---- tools/standalone_miri/value.cpp | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index e9d6d150..ba359105 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -378,9 +378,17 @@ struct MirHelpers // 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; + LOG_ASSERT(ofs != 0, "Dereferencing NULL pointer"); auto alloc = vr.get_relocation(0); + if( alloc ) + { + // TODO: It's valid to dereference (but not read) a non-null invalid pointer. + LOG_ASSERT(ofs >= Allocation::PTR_BASE, "Dereferencing invalid pointer - " << ofs << " into " << alloc); + ofs -= Allocation::PTR_BASE; + } + else + { + } // There MUST be a relocation at this point with a valid allocation. LOG_TRACE("Interpret " << alloc << " + " << ofs << " as value of type " << ty); @@ -2733,6 +2741,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ case TypeWrapper::Ty::Slice: { // - Get thin pointer and count auto ofs = ptr.read_usize(0); + LOG_ASSERT(ofs >= Allocation::PTR_BASE, ""); auto ptr_reloc = ptr.get_relocation(0); auto count = ptr.read_usize(POINTER_SIZE); @@ -2740,7 +2749,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, Allocation::PTR_BASE + ofs, ptr_reloc); + auto ptr = Value::new_pointer(pty, 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 @@ -2752,7 +2761,7 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ i ++; if( i < count ) { - auto ptr = Value::new_pointer(pty, Allocation::PTR_BASE + ofs, ptr_reloc); + auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); ofs += ity.get_size(); assert(!drop_value(ptr, ity)); return false; diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 601c1d6c..319f516b 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -666,7 +666,7 @@ Value Value::new_ffiptr(FFIPointer ffi) Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) ); rv.create_allocation(); rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_ffi(ffi) }); - 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; } -- cgit v1.2.3 From a2d34eb26271b1dd0fbe2936b49a866fccf8b605 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 18:49:39 +0800 Subject: Standalone MIRI - Tweak handling of relocation comparisons --- tools/standalone_miri/miri.cpp | 54 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index ba359105..e38ff845 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -395,7 +395,7 @@ struct MirHelpers // NOTE: No alloc can happen when dereferencing a zero-sized pointer if( alloc.is_alloc() ) { - LOG_DEBUG("Deref - lvr=" << ::MIR::LValue::CRef(lv, &w - &lv.m_wrappers.front()) << " alloc=" << alloc.alloc()); + //LOG_DEBUG("Deref - lvr=" << ::MIR::LValue::CRef(lv, &w - &lv.m_wrappers.front()) << " alloc=" << alloc.alloc()); } else { @@ -1044,6 +1044,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); int res = 0; + auto reloc_l = v_l.get_relocation(0); + auto reloc_r = v_r.get_relocation(0); + + // TODO: Handle comparison of the relocations too // - If both sides have a relocation: // > EQ/NE always valid @@ -1051,17 +1055,47 @@ bool InterpreterThread::step_one(Value& out_thread_result) // - 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; - auto reloc_l = /*alloc_l ? */v_l.get_relocation(0)/* : RelocationPtr()*/; - auto reloc_r = /*alloc_r ? */v_r.get_relocation(0)/* : RelocationPtr()*/; - - if( reloc_l != reloc_r ) + if( reloc_l && reloc_r ) + { + // Both have relocations, check if they're equal + if( reloc_l != reloc_r ) + { + switch(re.op) + { + case ::MIR::eBinOp::EQ: + case ::MIR::eBinOp::NE: + res = 1; + break; + default: + LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations"); + } + // - Equality will always fail + // - Ordering is a bug + } + else + { + // Equal: Allow all comparisons + } + } + else if( reloc_l || reloc_r ) + { + // Only one side + // - Ordering is a bug + // - Equalities are allowed, but only for `0`? + switch(re.op) + { + case ::MIR::eBinOp::EQ: + case ::MIR::eBinOp::NE: + // - Allow success, as addresses can be masked down + break; + default: + LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations"); + } + } + else { - res = (reloc_l < reloc_r ? -1 : 1); + // No relocations, no need to check more } - LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r); if( const auto* w = ty_l.get_wrapper() ) { -- cgit v1.2.3 From ebebe58a9a0f1399ac50ab956f254d2c0d2c813d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 4 Aug 2019 19:27:02 +0800 Subject: Standalone MIRI - Fix write_bytes count --- tools/standalone_miri/miri.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index e38ff845..2deb421b 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -2543,13 +2543,15 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: auto& dst_ptr_v = args.at(0); auto byte = args.at(1).read_u8(0); auto count = args.at(2).read_usize(0); + auto bytes = count * ty_params.tys.at(0).get_size(); - LOG_DEBUG("'write_bytes'(" << dst_ptr_v << ", " << byte << ", " << count << ")"); + LOG_DEBUG("'write_bytes'(" << dst_ptr_v << ", " << (int)byte << ", " << count << "): bytes=" << bytes); if( count > 0 ) { - auto dst_vr = dst_ptr_v.read_pointer_valref_mut(0, count); - memset(dst_vr.data_ptr_mut(), byte, count); + auto dst_vr = dst_ptr_v.read_pointer_valref_mut(0, bytes); + memset(dst_vr.data_ptr_mut(), byte, bytes); + dst_vr.mark_bytes_valid(0, bytes); } } // - Unsized stuff -- 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/miri.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 From c36fac95b463ea99534da20c411e87b8b8a9a313 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 5 Aug 2019 22:50:20 +0800 Subject: Standalone MIRI - Hacky thread handling (run in-place) --- tools/standalone_miri/miri.cpp | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 906949b6..74b63063 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -749,13 +749,22 @@ bool InterpreterThread::step_one(Value& out_thread_result) else if( const auto* src_w = src_ty.get_wrapper() ) { if( src_w->type != TypeWrapper::Ty::Pointer && src_w->type != TypeWrapper::Ty::Borrow ) { - LOG_ERROR("Attempting to cast to a non-pointer - " << src_ty); + LOG_ERROR("Attempting to cast from a non-pointer - " << src_ty); } // TODO: MUST be a thin pointer? // TODO: MUST be an integer (usize only?) - if( re.type != RawType::USize && re.type != RawType::ISize ) { - LOG_ERROR("Casting from a pointer to non-usize - " << re.type << " to " << src_ty); + switch(re.type.wrappers.empty() ? re.type.inner_type : RawType::Unreachable) + { + case RawType::USize: + case RawType::ISize: + break; + case RawType::U64: + case RawType::I64: + // TODO: Only if 64-bit? + break; + default: + LOG_ERROR("Casting from a pointer to non-usize - " << src_ty << " to " << re.type); throw "ERROR"; } new_val = src_value.read_value(0, re.type.get_size()); @@ -2152,7 +2161,28 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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); + if( true ) { + this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + out_rv = Value::new_i32(0); + return true; + })); + + // TODO: Catch the panic out of this. + if( this->call_path(rv, fcn_path, { ::std::move(arg) }) ) + { + bool v = this->pop_stack(rv); + assert( v == false ); + return true; + } + else + { + return false; + } + } + else { + //this->m_parent.create_thread(fcn_path, arg); + rv = Value::new_i32(EPERM); + } } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { -- cgit v1.2.3 From 4488ad815467790f63a6eed6a127d0e658cbd631 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 6 Aug 2019 21:33:52 +0800 Subject: Standalone MIRI - Multithreading hacks --- tools/standalone_miri/miri.cpp | 77 +++++++++++++++++++++++++++++++++-- tools/standalone_miri/module_tree.cpp | 19 +++++---- tools/standalone_miri/module_tree.hpp | 2 +- 3 files changed, 85 insertions(+), 13 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 74b63063..6c611382 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -638,7 +638,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) 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; + const size_t MAX_STACK_DEPTH = 60; if( this->m_stack.size() > MAX_STACK_DEPTH ) { LOG_ERROR("Maximum stack depth of " << MAX_STACK_DEPTH << " exceeded"); @@ -1966,6 +1966,12 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { LOG_TODO("rust_begin_unwind"); } + // GCC unwinding panics + else if( link_name == "_Unwind_RaiseException" ) + { + LOG_TODO("_Unwind_RaiseException(" << args.at(0) << ")"); + // Save the first argument in TLS, then return a status that indicates unwinding should commence. + } #ifdef _WIN32 // WinAPI functions used by libstd else if( link_name == "AddVectoredExceptionHandler" ) @@ -2109,6 +2115,22 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value(::HIR::TypeRef(RawType::I32)); rv.write_i32(0, rv_i); } + else if( link_name == "prctl" ) + { + auto option = args.at(0).read_i32(0); + int rv_i; + switch(option) + { + case 15: { // PR_SET_NAME - set thread name + auto name = FfiHelpers::read_cstr(args.at(1), 0); + LOG_DEBUG("prctl(PR_SET_NAME, \"" << name << "\""); + rv_i = 0; + } break; + default: + LOG_TODO("prctl(" << option << ", ..."); + } + rv = Value::new_i32(rv_i); + } else if( link_name == "sysconf" ) { auto name = args.at(0).read_i32(0); @@ -2152,6 +2174,25 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // Lie and return succeess rv = Value::new_i32(0); } + else if( link_name == "pthread_attr_getguardsize" ) + { + const auto attr_p = args.at(0).read_pointer_const(0, 1); + auto out_size = args.at(1).deref(0, HIR::TypeRef(RawType::USize)); + + out_size.m_alloc.alloc().write_usize(out_size.m_offset, 0x1000); + + rv = Value::new_i32(0); + } + else if( link_name == "pthread_attr_getstack" ) + { + const auto attr_p = args.at(0).read_pointer_const(0, 1); + auto out_ptr = args.at(2).deref(0, HIR::TypeRef(RawType::USize)); + auto out_size = args.at(2).deref(0, HIR::TypeRef(RawType::USize)); + + out_size.m_alloc.alloc().write_usize(out_size.m_offset, 0x4000); + + 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)); @@ -2161,9 +2202,13 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 - if( true ) { - this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + // HACK: Just run inline + if( true ) + { + auto tls = ::std::move(m_thread.tls_values); + this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)mutable ->bool { out_rv = Value::new_i32(0); + m_thread.tls_values = ::std::move(tls); return true; })); @@ -2728,6 +2773,32 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: const auto& ty = ty_params.tys.at(0); return drop_value(val, ty); } + else if( name == "try" ) + { + auto fcn_path = args.at(0).get_relocation(0).fcn(); + auto arg = args.at(1); + auto out_panic_value = args.at(2).read_pointer_valref_mut(0, POINTER_SIZE); + + ::std::vector sub_args; + sub_args.push_back( ::std::move(arg) ); + + this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + out_rv = Value::new_u32(0); + return true; + })); + + // TODO: Catch the panic out of this. + if( this->call_path(rv, fcn_path, ::std::move(sub_args)) ) + { + bool v = this->pop_stack(rv); + assert( v == false ); + return true; + } + else + { + return false; + } + } // ---------------------------------------------------------------- // Checked arithmatic else if( name == "add_with_overflow" ) diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 7fab4d88..f6b20fae 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -117,25 +117,26 @@ bool Parser::parse_one() rv_ty = parse_type(); } + Function::ExtInfo ext; if( lex.consume_if('=') ) { - auto link_name = ::std::move(lex.check_consume(TokenClass::String).strval); + ext.link_name = ::std::move(lex.check_consume(TokenClass::String).strval); lex.check_consume(':'); - auto abi = ::std::move(lex.check_consume(TokenClass::String).strval); - lex.check_consume(';'); - + ext.link_abi = ::std::move(lex.check_consume(TokenClass::String).strval); + } + ::MIR::Function body; + if( lex.consume_if(';') ) + { LOG_DEBUG(lex << "extern fn " << p); - auto p2 = p; - tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {link_name, abi}, {} }) ); } else { - auto body = parse_body(); + body = parse_body(); LOG_DEBUG(lex << "fn " << p); - auto p2 = p; - tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, {}, ::std::move(body) }) ); } + auto p2 = p; + tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, ::std::move(ext), ::std::move(body) }) ); } else if( lex.consume_if("static") ) { diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index 6637c2d4..5da8439f 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -23,7 +23,7 @@ struct Function ::HIR::TypeRef ret_ty; // If `link_name` is non-empty, then the function is an external - struct { + struct ExtInfo { ::std::string link_name; ::std::string link_abi; } external; -- cgit v1.2.3 From 7980ff17aa557d5546d920271f47c68ab498714b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 7 Aug 2019 18:48:04 +0800 Subject: Standalone MIRI - Rough panic support --- src/trans/codegen_mmir.cpp | 12 ++++++------ tools/standalone_miri/miri.cpp | 42 +++++++++++++++++++++++++++++++++++------- tools/standalone_miri/miri.hpp | 4 ++++ 3 files changed, 45 insertions(+), 13 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 2f6a2f2e..5ed12418 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -1103,11 +1103,6 @@ namespace ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << p;), ret_type, arg_types, *code }; m_mir_res = &mir_res; - if( item.m_linkage.name != "" ) - { - // TODO: Save the linkage name. - } - // - Signature m_of << "fn " << p << "("; for(unsigned int i = 0; i < item.m_args.size(); i ++) @@ -1115,7 +1110,12 @@ namespace if( i != 0 ) m_of << ", "; m_of << params.monomorph(m_resolve, item.m_args[i].second); } - m_of << "): " << ret_type << " {\n"; + m_of << "): " << ret_type; + if( item.m_linkage.name != "" ) + { + m_of << " = \"" << item.m_linkage.name << "\":\"" << item.m_abi << "\""; + } + m_of << " {\n"; // - Locals for(unsigned int i = 0; i < code->locals.size(); i ++) { DEBUG("var" << i << " : " << code->locals[i]); diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 6c611382..957a69f1 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1533,7 +1533,9 @@ bool InterpreterThread::step_one(Value& out_thread_result) TU_ARM(bb.terminator, Incomplete, _te) LOG_TODO("Terminator::Incomplete hit"); TU_ARM(bb.terminator, Diverge, _te) - LOG_TODO("Terminator::Diverge hit"); + LOG_DEBUG("DIVERGE (continue panic)"); + assert(m_thread.panic_active); + return this->pop_stack(out_thread_result); TU_ARM(bb.terminator, Panic, _te) LOG_TODO("Terminator::Panic"); TU_ARM(bb.terminator, Goto, te) @@ -1700,9 +1702,19 @@ bool InterpreterThread::step_one(Value& out_thread_result) return false; } } - LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn->my_path << ")"); - state.write_lvalue(te.ret_val, rv); - cur_frame.bb_idx = te.ret_block; + // If a panic is in progress (in thread state), take the panic block instead + if( m_thread.panic_active ) + { + //m_thread.panic_active = false; + LOG_DEBUG("Panic into " << cur_frame.fcn->my_path); + cur_frame.bb_idx = te.panic_block; + } + else + { + LOG_DEBUG(te.ret_val << " = " << rv << " (resume " << cur_frame.fcn->my_path << ")"); + state.write_lvalue(te.ret_val, rv); + cur_frame.bb_idx = te.ret_block; + } } break; } cur_frame.stmt_idx = 0; @@ -1754,9 +1766,19 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn->my_path << ")"); - state.write_lvalue(te.ret_val, res_v); cur_frame.stmt_idx = 0; - cur_frame.bb_idx = te.ret_block; + // If a panic is in progress (in thread state), take the panic block instead + if( m_thread.panic_active ) + { + //m_thread.panic_active = false; + LOG_DEBUG("Panic into " << cur_frame.fcn->my_path); + cur_frame.bb_idx = te.panic_block; + } + else + { + state.write_lvalue(te.ret_val, res_v); + cur_frame.bb_idx = te.ret_block; + } } return false; @@ -1969,8 +1991,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c // GCC unwinding panics else if( link_name == "_Unwind_RaiseException" ) { - LOG_TODO("_Unwind_RaiseException(" << args.at(0) << ")"); + LOG_DEBUG("_Unwind_RaiseException(" << args.at(0) << ")"); // Save the first argument in TLS, then return a status that indicates unwinding should commence. + m_thread.panic_active = true; + m_thread.panic_value = ::std::move(args.at(0)); } #ifdef _WIN32 // WinAPI functions used by libstd @@ -2783,6 +2807,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: sub_args.push_back( ::std::move(arg) ); this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + if( m_thread.panic_active ) + { + LOG_TODO("Panic caught in `try` - " << m_thread.panic_value); + } out_rv = Value::new_u32(0); return true; })); diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index e6830679..9c3da72b 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -15,8 +15,12 @@ struct ThreadState unsigned call_stack_depth; ::std::vector< ::std::pair > tls_values; + bool panic_active; + Value panic_value; + ThreadState(): call_stack_depth(0) + ,panic_active(false) { } -- cgit v1.2.3 From 69fd09133591e6a1d5733f4321df4a81a71cb856 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 7 Aug 2019 18:57:56 +0800 Subject: Standalone MIRI - Tweaked panic handling --- tools/standalone_miri/miri.cpp | 16 +++++++++++----- tools/standalone_miri/miri.hpp | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 957a69f1..09855329 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1534,7 +1534,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_TODO("Terminator::Incomplete hit"); TU_ARM(bb.terminator, Diverge, _te) LOG_DEBUG("DIVERGE (continue panic)"); - assert(m_thread.panic_active); + assert(m_thread.panic_count > 0); + m_thread.panic_active = true; return this->pop_stack(out_thread_result); TU_ARM(bb.terminator, Panic, _te) LOG_TODO("Terminator::Panic"); @@ -1705,7 +1706,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) // If a panic is in progress (in thread state), take the panic block instead if( m_thread.panic_active ) { - //m_thread.panic_active = false; + m_thread.panic_active = false; LOG_DEBUG("Panic into " << cur_frame.fcn->my_path); cur_frame.bb_idx = te.panic_block; } @@ -1770,7 +1771,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) // If a panic is in progress (in thread state), take the panic block instead if( m_thread.panic_active ) { - //m_thread.panic_active = false; + m_thread.panic_active = false; LOG_DEBUG("Panic into " << cur_frame.fcn->my_path); cur_frame.bb_idx = te.panic_block; } @@ -1994,6 +1995,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c LOG_DEBUG("_Unwind_RaiseException(" << args.at(0) << ")"); // Save the first argument in TLS, then return a status that indicates unwinding should commence. m_thread.panic_active = true; + m_thread.panic_count += 1; m_thread.panic_value = ::std::move(args.at(0)); } #ifdef _WIN32 @@ -2811,8 +2813,12 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { LOG_TODO("Panic caught in `try` - " << m_thread.panic_value); } - out_rv = Value::new_u32(0); - return true; + else + { + LOG_ASSERT(m_thread.panic_count == 0, "Panic count non-zero, but previous function returned non-panic"); + out_rv = Value::new_u32(0); + return true; + } })); // TODO: Catch the panic out of this. diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 9c3da72b..0b0f8f39 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -15,11 +15,13 @@ struct ThreadState unsigned call_stack_depth; ::std::vector< ::std::pair > tls_values; + unsigned panic_count; bool panic_active; Value panic_value; ThreadState(): call_stack_depth(0) + ,panic_count(0) ,panic_active(false) { } -- cgit v1.2.3 From b01ccc9f2b5bd051535a9757756091c3680940a2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 7 Aug 2019 21:16:56 +0800 Subject: Standalone MIRI - Panic catching, more TODOs removed --- tools/standalone_miri/miri.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 09855329..e7280476 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -1147,6 +1147,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::USize: res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0)); break; case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; + case RawType::Bool: res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0)); break; // TODO: `read_bool` that checks for bool values? default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1651,7 +1652,19 @@ bool InterpreterThread::step_one(Value& out_thread_result) default: LOG_ERROR("Terminator::SwitchValue::Signed with unexpected type - " << ty); } - LOG_TODO("Terminator::SwitchValue (signed) - " << ty << " " << switch_val); + + auto it = ::std::find(vals.begin(), vals.end(), switch_val); + if( it != vals.end() ) + { + auto idx = it - vals.begin(); + LOG_TRACE("- " << switch_val << " matched arm " << idx); + cur_frame.bb_idx = te.targets.at(idx); + } + else + { + LOG_TRACE("- " << switch_val << " not matched, taking default arm"); + cur_frame.bb_idx = te.def_target; + } } TU_ARMA(String, vals) { LOG_TODO("Terminator::SwitchValue (string) - " << ty << " " << v); @@ -1989,7 +2002,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { LOG_TODO("rust_begin_unwind"); } - // GCC unwinding panics + // libunwind else if( link_name == "_Unwind_RaiseException" ) { LOG_DEBUG("_Unwind_RaiseException(" << args.at(0) << ")"); @@ -1998,6 +2011,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c m_thread.panic_count += 1; m_thread.panic_value = ::std::move(args.at(0)); } + else if( link_name == "_Unwind_DeleteException" ) + { + LOG_DEBUG("_Unwind_DeleteException(" << args.at(0) << ")"); + } #ifdef _WIN32 // WinAPI functions used by libstd else if( link_name == "AddVectoredExceptionHandler" ) @@ -2548,7 +2565,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { rv = Value(); } - else if( name == "atomic_store" || name == "atomic_store_relaxed" ) + else if( name == "atomic_store" || name == "atomic_store_relaxed" || name == "atomic_store_rel" ) { auto& ptr_val = args.at(0); auto& data_val = args.at(1); @@ -2620,7 +2637,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: val_l.get().write_to_value( ptr_alloc.alloc(), ptr_ofs ); } - else if( name == "atomic_xchg" ) + else if( name == "atomic_xchg" || name == "atomic_xchg_acqrel" ) { const auto& ty_T = ty_params.tys.at(0); auto data_ref = args.at(0).read_pointer_valref_mut(0, ty_T.get_size()); @@ -2808,10 +2825,16 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: ::std::vector sub_args; sub_args.push_back( ::std::move(arg) ); - this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)->bool{ + this->m_stack.push_back(StackFrame::make_wrapper([=](Value& out_rv, Value /*rv*/)mutable->bool{ if( m_thread.panic_active ) { - LOG_TODO("Panic caught in `try` - " << m_thread.panic_value); + assert(m_thread.panic_count > 0); + m_thread.panic_active = false; + m_thread.panic_count --; + LOG_ASSERT(m_thread.panic_value.size() == out_panic_value.m_size, "Panic value " << m_thread.panic_value << " doesn't fit in " << out_panic_value); + out_panic_value.m_alloc.alloc().write_value( out_panic_value.m_offset, ::std::move(m_thread.panic_value) ); + out_rv = Value::new_u32(1); + return true; } else { -- cgit v1.2.3 From c1fe76bfbe373207c531519a9345cafb4166c667 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 8 Aug 2019 18:53:19 +0800 Subject: Standalone MIRI - Fix size of allocations --- tools/standalone_miri/miri.cpp | 4 +-- tools/standalone_miri/value.cpp | 61 ++++++++++++++++++++--------------------- tools/standalone_miri/value.hpp | 18 ++++++------ 3 files changed, 41 insertions(+), 42 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index e7280476..c8326283 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -430,6 +430,7 @@ struct MirHelpers } else { + LOG_DEBUG("sizeof(" << ty << ") = " << ty.get_size()); LOG_ASSERT(vr.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << vr << ") - " << vr << ": " << ptr_ty); size = ty.get_size(); if( !alloc ) { @@ -1943,8 +1944,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 + 8-1) / 8 ); - alloc.mask.resize( (newsize + 8-1) / 8 ); + alloc.resize(newsize); // TODO: Should this instead make a new allocation to catch use-after-free? rv = ::std::move(args.at(0)); } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 16842d82..7c3e205a 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -66,8 +66,9 @@ 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 + rv->m_size = size; + rv->m_data.resize( (size + 8-1) / 8 ); // QWORDS + rv->m_mask.resize( (size + 8-1) / 8 ); // bitmap bytes //LOG_DEBUG(rv << " ALLOC"); LOG_DEBUG(rv); return AllocationHandle(rv); @@ -337,8 +338,9 @@ void Allocation::resize(size_t new_size) //size_t old_size = this->size(); //size_t extra_bytes = (new_size > old_size ? new_size - old_size : 0); - this->data.resize( (new_size + 8-1) / 8 ); - this->mask.resize( (new_size + 8-1) / 8 ); + this->m_size = new_size; + this->m_data.resize( (new_size + 8-1) / 8 ); + this->m_mask.resize( (new_size + 8-1) / 8 ); } void Allocation::check_bytes_valid(size_t ofs, size_t size) const @@ -348,7 +350,7 @@ 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->m_mask[i/8] & (1 << (i%8))) ) { LOG_ERROR("Invalid bytes in value - " << ofs << "+" << size << " - " << *this); throw "ERROR"; @@ -357,16 +359,16 @@ void Allocation::check_bytes_valid(size_t ofs, size_t size) const } void Allocation::mark_bytes_valid(size_t ofs, size_t size) { - assert( ofs+size <= this->mask.size() * 8 ); + assert( ofs+size <= this->m_mask.size() * 8 ); for(size_t i = ofs; i < ofs + size; i++) { - this->mask[i/8] |= (1 << (i%8)); + this->m_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); + //TRACE_FUNCTION_R("Allocation::read_value " << this << " " << ofs << "+" << size, *this << " | " << size << "=" << rv); if( this->is_freed ) LOG_ERROR("Use of freed memory " << this); LOG_DEBUG(*this); @@ -401,10 +403,10 @@ Value Allocation::read_value(size_t ofs, size_t size) const size_t j = ofs + i; 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; + bool v = (this->m_mask[j/8] & test_mask) != 0; if( v ) { - rv.allocation->mask[i/8] |= set_mask; + rv.allocation->m_mask[i/8] |= set_mask; } } } @@ -422,7 +424,7 @@ Value Allocation::read_value(size_t ofs, size_t size) const size_t j = ofs + i; 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; + bool v = (this->m_mask[j/8] & tst_mask) != 0; if( v ) { rv.direct_data.mask[i/8] |= set_mask; @@ -436,7 +438,7 @@ 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); + //LOG_DEBUG("Allocation::read_bytes " << this << " " << ofs << "+" << count); if(count == 0) return ; @@ -461,7 +463,7 @@ void Allocation::write_value(size_t ofs, Value v) size_t v_size = v.allocation->size(); const auto& src_alloc = *v.allocation; // Take a copy of the source mask - auto s_mask = src_alloc.mask; + auto s_mask = src_alloc.m_mask; // Save relocations first, because `Foo = Foo` is valid. ::std::vector new_relocs = src_alloc.relocations; @@ -489,9 +491,9 @@ void Allocation::write_value(size_t ofs, Value v) { uint8_t dbit = 1 << ((ofs+i) % 8); if( s_mask[i/8] & (1 << (i %8)) ) - this->mask[ (ofs+i) / 8 ] |= dbit; + this->m_mask[ (ofs+i) / 8 ] |= dbit; else - this->mask[ (ofs+i) / 8 ] &= ~dbit; + this->m_mask[ (ofs+i) / 8 ] &= ~dbit; } } else @@ -499,7 +501,7 @@ void Allocation::write_value(size_t ofs, Value v) // Copy the mask bytes directly for(size_t i = 0; i < v_size / 8; i ++) { - this->mask[ofs/8+i] = s_mask[i]; + this->m_mask[ofs/8+i] = s_mask[i]; } } } @@ -512,9 +514,9 @@ void Allocation::write_value(size_t ofs, Value v) { uint8_t dbit = 1 << ((ofs+i) % 8); if( v.direct_data.mask[i/8] & (1 << (i %8)) ) - this->mask[ (ofs+i) / 8 ] |= dbit; + this->m_mask[ (ofs+i) / 8 ] |= dbit; else - this->mask[ (ofs+i) / 8 ] &= ~dbit; + this->m_mask[ (ofs+i) / 8 ] &= ~dbit; } } } @@ -588,7 +590,7 @@ void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc) if( i != 0 ) os << " "; - if( x.mask[i/8] & (1 << (i%8)) ) + if( x.m_mask[i/8] & (1 << (i%8)) ) { os << ::std::setw(2) << ::std::setfill('0') << (int)x.data_ptr()[i]; } @@ -657,26 +659,21 @@ 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) = Allocation::PTR_BASE; - rv.allocation->mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes + rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path)); return rv; } Value Value::new_ffiptr(FFIPointer ffi) { Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) ); rv.create_allocation(); - rv.allocation->relocations.push_back(Relocation { 0, RelocationPtr::new_ffi(ffi) }); - 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 + rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi)); return rv; } Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) { assert(ty.get_wrapper()); assert(ty.get_wrapper()->type == TypeWrapper::Ty::Borrow || ty.get_wrapper()->type == TypeWrapper::Ty::Pointer); Value rv(ty); - rv.write_usize(0, v); - rv.allocation->relocations.push_back(Relocation { 0, /*POINTER_SIZE,*/ ::std::move(r) }); + rv.write_ptr(0, v, ::std::move(r)); return rv; } Value Value::new_usize(uint64_t v) { @@ -710,10 +707,10 @@ void Value::create_allocation() assert(!this->allocation); 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]; + this->allocation->m_mask[0] = this->direct_data.mask[0]; if( this->direct_data.size > 8 ) - this->allocation->mask[1] = this->direct_data.mask[1]; - ::std::memcpy(this->allocation->data.data(), this->direct_data.data, this->direct_data.size); + this->allocation->m_mask[1] = this->direct_data.mask[1]; + ::std::memcpy(this->allocation->data_ptr(), this->direct_data.data, this->direct_data.size); } void Value::check_bytes_valid(size_t ofs, size_t size) const { @@ -900,7 +897,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) if( i != 0 ) os << " "; - if( alloc.mask[i/8] & (1 << i%8) ) + if( alloc.m_mask[i/8] & (1 << i%8) ) { os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; } @@ -953,7 +950,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) if( i != 0 ) os << " "; - if( alloc.mask[i/8] & (1 << i%8) ) + if( alloc.m_mask[i/8] & (1 << i%8) ) { os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 1ba3382e..ab7add8c 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -249,8 +249,14 @@ class Allocation: friend class AllocationHandle; ::std::string m_tag; size_t refcount; + size_t m_size; // TODO: Read-only flag? bool is_freed = false; + + ::std::vector m_data; +public: + ::std::vector m_mask; + ::std::vector relocations; public: virtual ~Allocation() {} static AllocationHandle new_alloc(size_t size, ::std::string tag); @@ -258,15 +264,11 @@ public: // 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; } + const uint8_t* data_ptr() const { return reinterpret_cast(this->m_data.data()); } + uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->m_data.data()); } + size_t size() const { return m_size; } const ::std::string& tag() const { return m_tag; } - ::std::vector data; - ::std::vector mask; - ::std::vector relocations; - RelocationPtr get_relocation(size_t ofs) const override { for(const auto& r : relocations) { if(r.slot_ofs == ofs) @@ -277,7 +279,7 @@ public: void mark_as_freed() { is_freed = true; relocations.clear(); - for(auto& v : mask) + for(auto& v : m_mask) v = 0; } -- cgit v1.2.3 From 657a5a99edf0722c9db5956ca9d42db65c9e683e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 9 Aug 2019 17:37:10 +0800 Subject: Standalone MIRI - More thread hackery --- tools/standalone_miri/lex.cpp | 4 +++- tools/standalone_miri/miri.cpp | 5 +++++ tools/standalone_miri/module_tree.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/lex.cpp b/tools/standalone_miri/lex.cpp index 07427bde..79e94224 100644 --- a/tools/standalone_miri/lex.cpp +++ b/tools/standalone_miri/lex.cpp @@ -7,6 +7,8 @@ */ #include "lex.hpp" #include +#include +#include "debug.hpp" #include bool Token::operator==(TokenClass tc) const @@ -25,7 +27,7 @@ bool Token::operator==(const char* s) const uint64_t Token::integer() const { if( this->type != TokenClass::Integer ) - throw ""; + throw ::std::runtime_error(FMT_STRING("Expected interger, got " << *this)); return this->numbers.int_val; } double Token::real() const diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index c8326283..7407baf7 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -2272,6 +2272,11 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c rv = Value::new_i32(EPERM); } } + else if( link_name == "pthread_detach" ) + { + // "detach" - Prevent the need to explitly join a thread + rv = Value::new_i32(0); + } else if( link_name == "pthread_cond_init" || link_name == "pthread_cond_destroy" ) { rv = Value::new_i32(0); diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index f6b20fae..71a545fa 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -884,7 +884,7 @@ bool Parser::parse_one() ::std::vector targets; while(lex.next() != '{') { - targets.push_back( static_cast(lex.consume().integer()) ); + targets.push_back( static_cast(lex.check_consume(TokenClass::Integer).integer()) ); if( !lex.consume_if(',') ) break; } -- cgit v1.2.3 From 66a176784df8801a9ef6fabd2f489c125554e0f5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Wed, 14 Aug 2019 20:06:45 +0800 Subject: Standalone MIRI - Instruction counting --- tools/standalone_miri/miri.cpp | 3 ++- tools/standalone_miri/miri.hpp | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 7407baf7..97343714 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -636,7 +636,8 @@ 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 << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, ""); + auto instr_idx = this->m_instruction_count++; + TRACE_FUNCTION_R("#" << instr_idx << " " << cur_frame.fcn->my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, "#" << instr_idx); const auto& bb = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx ); const size_t MAX_STACK_DEPTH = 60; diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 0b0f8f39..0b7fd4d6 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -62,11 +62,13 @@ class InterpreterThread ModuleTree& m_modtree; ThreadState m_thread; + size_t m_instruction_count; ::std::vector m_stack; public: InterpreterThread(ModuleTree& modtree): - m_modtree(modtree) + m_modtree(modtree), + m_instruction_count(0) { } ~InterpreterThread(); -- cgit v1.2.3 From 096831d89d1f70db1cf7b62fb61a763a6b1a6890 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 16 Aug 2019 18:46:31 +0800 Subject: Standalone MIRI - More u128, general improvements in running a proc macro --- tools/standalone_miri/miri.cpp | 101 ++++++++++++++++++++++---- tools/standalone_miri/u128.hpp | 155 ++++++++++++++++++++++++++++++++++++++++ tools/standalone_miri/value.hpp | 2 + 3 files changed, 244 insertions(+), 14 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 97343714..55ac81bb 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -341,6 +341,7 @@ struct MirHelpers auto len = vr.m_metadata->read_usize(0); LOG_ASSERT(idx < len, "Slice index out of range"); vr.m_offset += ty.get_size() * idx; + vr.m_metadata.reset(); } else { @@ -433,8 +434,8 @@ struct MirHelpers LOG_DEBUG("sizeof(" << ty << ") = " << ty.get_size()); LOG_ASSERT(vr.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << vr << ") - " << vr << ": " << ptr_ty); size = ty.get_size(); - if( !alloc ) { - LOG_ERROR("Deref of a value with no relocation - " << vr); + if( !alloc && size > 0 ) { + LOG_ERROR("Deref of a non-ZST pointer with no relocation - " << vr); } } @@ -502,7 +503,11 @@ struct MirHelpers ty = ::HIR::TypeRef(ce.t); Value val = Value(ty); val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian - // TODO: i128/u128 need the upper bytes cleared+valid + // i128/u128 need the upper bytes cleared+valid + if( ce.t.raw_type == RawType::U128 ) { + uint64_t zero = 0; + val.write_bytes(8, &zero, 8); + } return val; } break; TU_ARM(c, Bool, ce) { @@ -799,8 +804,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Bool: throw "ERROR"; case RawType::F32: throw "BUG"; case RawType::F64: dst_val = static_cast( src_value.read_f64(0) ); break; - case RawType::USize: throw "TODO";// /*dst_val = src_value.read_usize();*/ break; - case RawType::ISize: throw "TODO";// /*dst_val = src_value.read_isize();*/ break; + case RawType::USize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_usize();*/ break; + case RawType::ISize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_isize();*/ break; case RawType::U8: dst_val = static_cast( src_value.read_u8 (0) ); break; case RawType::I8: dst_val = static_cast( src_value.read_i8 (0) ); break; case RawType::U16: dst_val = static_cast( src_value.read_u16(0) ); break; @@ -809,8 +814,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::I32: dst_val = static_cast( src_value.read_i32(0) ); break; case RawType::U64: dst_val = static_cast( src_value.read_u64(0) ); break; case RawType::I64: dst_val = static_cast( src_value.read_i64(0) ); break; - case RawType::U128: throw "TODO";// /*dst_val = src_value.read_u128();*/ break; - case RawType::I128: throw "TODO";// /*dst_val = src_value.read_i128();*/ break; + case RawType::U128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_u128();*/ break; + case RawType::I128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_i128();*/ break; } new_val.write_f32(0, dst_val); } break; @@ -990,6 +995,13 @@ bool InterpreterThread::step_one(Value& out_thread_result) if(0) case RawType::I64: dst_val = static_cast( src_value.read_i64(0) ); + if(0) + case RawType::U128: + dst_val = static_cast( src_value.read_u128(0) ); + if(0) + case RawType::I128: + LOG_TODO("Cast i128 to " << re.type); + //dst_val = static_cast( src_value.read_i128(0) ); switch(re.type.inner_type) { @@ -1027,13 +1039,20 @@ bool InterpreterThread::step_one(Value& out_thread_result) throw ""; } break; - case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break; - case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break; } } break; case RawType::U128: - case RawType::I128: - LOG_TODO("Cast to " << re.type); + case RawType::I128: { + U128 dst_val; + switch(src_ty.inner_type) + { + case RawType::U8: dst_val = src_value.read_u8 (0); break; + case RawType::I8: dst_val = src_value.read_i8 (0); break; + default: + LOG_TODO("Cast " << src_ty << " to " << re.type); + } + new_val.write_u128(0, dst_val); + } break; } } } break; @@ -1150,6 +1169,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; case RawType::Bool: res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0)); break; // TODO: `read_bool` that checks for bool values? + case RawType::U128: res = res != 0 ? res : Ops::do_compare(v_l.read_u128(0), v_r.read_u128(0)); break; + case RawType::I128: res = res != 0 ? res : Ops::do_compare(v_l.read_i128(0), v_r.read_i128(0)); break; default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1197,6 +1218,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) switch(ty_l.inner_type) { // TODO: U128 + case RawType::U128: new_val.write_u128(0, Ops::do_bitwise(v_l.read_u128(0), U128(shift), re.op)); break; case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast(shift), re.op)); break; case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast(shift), re.op)); break; case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast(shift), re.op)); break; @@ -1217,7 +1239,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) new_val = Value(ty_l); switch(ty_l.inner_type) { - // TODO: U128/I128 + case RawType::U128: + case RawType::I128: + new_val.write_u128( 0, Ops::do_bitwise(v_l.read_u128(0), v_r.read_u128(0), re.op) ); + break; case RawType::U64: case RawType::I64: new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) ); @@ -1621,6 +1646,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::U64: switch_val = v.read_u64(0); break; case RawType::U128: LOG_TODO("Terminator::SwitchValue::Unsigned with u128"); case RawType::USize: switch_val = v.read_usize(0); break; + case RawType::Char: switch_val = v.read_u32(0); break; default: LOG_ERROR("Terminator::SwitchValue::Unsigned with unexpected type - " << ty); } @@ -1913,7 +1939,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c return reinterpret_cast(v.read_pointer_const(0, len + 1)); // Final read will trigger an error if the NUL isn't there } }; - if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) + if( link_name == "__rust_allocate" || link_name == "__rust_alloc" || link_name == "__rust_alloc_zeroed" ) { static unsigned s_alloc_count = 0; @@ -1921,11 +1947,16 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c 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 << "): name=" << alloc_name); + LOG_DEBUG(link_name << "(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 ); + if( link_name == "__rust_alloc_zeroed" ) + { + alloc->mark_bytes_valid(0, size); + } + // TODO: Use the alignment when making an allocation? rv = Value::new_pointer(rty, Allocation::PTR_BASE, RelocationPtr::new_alloc(::std::move(alloc))); } @@ -2412,6 +2443,23 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(-1); } + else if( link_name == "memcmp" ) + { + auto n = args.at(2).read_usize(0); + int rv_i; + if( n > 0 ) + { + const void* ptr_b = args.at(1).read_pointer_const(0, n); + const void* ptr_a = args.at(0).read_pointer_const(0, n); + + rv_i = memcmp(ptr_a, ptr_b, n); + } + else + { + rv_i = 0; + } + rv = Value::new_i32(rv_i); + } // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { @@ -2696,6 +2744,31 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = ::std::move(args.at(0)); rv.write_ptr(0, Allocation::PTR_BASE + new_ofs, ptr_alloc); } + else if( name == "arith_offset" ) // Doesn't check validity, and allows wrapping + { + 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); + auto new_ofs = ptr_ofs + delta_counts * ty_params.tys.at(0).get_size(); + if(POINTER_SIZE != 8) { + new_ofs &= 0xFFFFFFFF; + } + //new_ofs += Allocation::PTR_BASE; + + rv = ::std::move(args.at(0)); + if( ptr_alloc ) + { + rv.write_ptr(0, new_ofs, ptr_alloc); + } + else + { + rv.write_usize(0, new_ofs); + } + } // effectively ptr::write else if( name == "move_val_init" ) { diff --git a/tools/standalone_miri/u128.hpp b/tools/standalone_miri/u128.hpp index 03c004d9..8403b94a 100644 --- a/tools/standalone_miri/u128.hpp +++ b/tools/standalone_miri/u128.hpp @@ -2,9 +2,126 @@ class U128 { + friend class I128; uint64_t lo, hi; public: U128(): lo(0), hi(0) {} + + U128(uint8_t v): lo(v), hi(0) {} + U128(int8_t v): lo(v), hi(v < 0 ? -1 : 0) {} + + void fmt(::std::ostream& os) const { os << hi << ":" << lo; } + + int cmp(U128 v) const { + if( hi != v.hi ) { + return (hi < v.hi ? -1 : 1); + } + if( lo != v.lo ) { + return (lo < v.lo ? -1 : 1); + } + return 0; + } + int cmp(unsigned v) const { + if(hi) + return 1; + if(lo < v) + return -1; + if(lo > v) + return 1; + return 0; + } + + template bool operator< (const T& v) const { return this->cmp(v) < 0; } + template bool operator<=(const T& v) const { return this->cmp(v) <= 0; } + template bool operator> (const T& v) const { return this->cmp(v) > 0; } + template bool operator>=(const T& v) const { return this->cmp(v) >= 0; } + template bool operator==(const T& v) const { return this->cmp(v) == 0; } + template bool operator!=(const T& v) const { return this->cmp(v) != 0; } + + operator uint8_t() const { return static_cast(lo); } + + U128 operator&(U128 x) const { + U128 rv; + rv.lo = this->lo & x.lo; + rv.hi = this->hi & x.hi; + return rv; + } + U128 operator|(U128 x) const { + U128 rv; + rv.lo = this->lo | x.lo; + rv.hi = this->hi | x.hi; + return rv; + } + U128 operator^(U128 x) const { + U128 rv; + rv.lo = this->lo ^ x.lo; + rv.hi = this->hi ^ x.hi; + return rv; + } + + U128 operator<<(U128 n) const + { + if( n < 128 ) + { + return *this << static_cast(n); + } + else + { + return U128(); + } + } + U128 operator<<(uint8_t n) const + { + if(n == 0) + { + return *this; + } + else if( n < 64 ) + { + U128 rv; + rv.lo = lo << n; + rv.hi = (hi << n) | (lo >> (64-n)); + return rv; + } + else if( n < 128 ) + { + U128 rv; + rv.lo = 0; + rv.hi = (lo << (n-64)); + return rv; + } + else + { + return U128(); + } + } + U128 operator>>(uint8_t n) const + { + if(n == 0) + { + return *this; + } + else if( n < 64 ) + { + U128 rv; + rv.lo = (lo >> n) | (hi << (64-n)); + rv.hi = (hi >> n); + return rv; + } + else if( n < 128 ) + { + U128 rv; + rv.lo = (hi >> (n-64)); + rv.hi = 0; + return rv; + } + else + { + return U128(); + } + } + + friend ::std::ostream& operator<<(::std::ostream& os, const U128& x) { x.fmt(os); return os; } }; class I128 @@ -12,4 +129,42 @@ class I128 U128 v; public: I128() {} + + int cmp(I128 x) const { + if(v.hi != x.v.hi) + return (static_cast(v.hi) < static_cast(x.v.hi) ? -1 : 1); + if(v.lo != x.v.lo) + { + if( static_cast(v.hi) < 0 ) + { + // Negative, so larger raw value is the smaller + return (v.lo > x.v.lo ? -1 : 1); + } + else + { + return (v.lo < x.v.lo ? -1 : 1); + } + } + return 0; + } + //int cmp(int v) const { + // if(hi) + // return 1; + // if(lo < v) + // return -1; + // if(lo > v) + // return 1; + // return 0; + //} + + template bool operator< (const T& v) const { return this->cmp(v) < 0; } + template bool operator<=(const T& v) const { return this->cmp(v) <= 0; } + template bool operator> (const T& v) const { return this->cmp(v) > 0; } + template bool operator>=(const T& v) const { return this->cmp(v) >= 0; } + template bool operator==(const T& v) const { return this->cmp(v) == 0; } + template bool operator!=(const T& v) const { return this->cmp(v) != 0; } + + void fmt(::std::ostream& os) const { os << v.hi << ":" << v.lo; } + + friend ::std::ostream& operator<<(::std::ostream& os, const I128& x) { x.fmt(os); return os; } }; diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 764df8fa..dea4c890 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -235,10 +235,12 @@ struct ValueCommonWrite: void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); } void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); } void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); } + void write_u128(size_t ofs, U128 v) { write_bytes(ofs, &v, 16); } void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast(v)); } void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast(v)); } void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast(v)); } void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast(v)); } + void write_i128(size_t ofs, I128 v) { write_bytes(ofs, &v, 16); } void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); } void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } void write_usize(size_t ofs, uint64_t v); -- cgit v1.2.3 From 50278961cc1b355dac83b4e79c8beb2635fd897d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 17 Aug 2019 08:43:42 +0800 Subject: Standalone MIRI - SwitchValue string --- tools/standalone_miri/miri.cpp | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 55ac81bb..11c620ec 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -8,6 +8,7 @@ #include #include "module_tree.hpp" #include "value.hpp" +#include "string_view.hpp" #include #include #include "debug.hpp" @@ -478,11 +479,14 @@ struct MirHelpers ::HIR::TypeRef ty; auto base_value = get_value_and_type(lv, ty); - if(base_value.m_alloc) { - base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val)); - } - else { - base_value.m_value->write_value(base_value.m_offset, ::std::move(val)); + if( val.size() > 0 ) + { + if(!base_value.m_value) { + base_value.m_alloc.alloc().write_value(base_value.m_offset, ::std::move(val)); + } + else { + base_value.m_value->write_value(base_value.m_offset, ::std::move(val)); + } } } @@ -1695,7 +1699,22 @@ bool InterpreterThread::step_one(Value& out_thread_result) } } TU_ARMA(String, vals) { - LOG_TODO("Terminator::SwitchValue (string) - " << ty << " " << v); + auto size = v.read_usize(POINTER_SIZE); + const char* sv_ptr = reinterpret_cast(v.read_pointer_const(0, size)); + auto switch_val = ::stdx::string_view(sv_ptr, sv_ptr+size); + + auto it = ::std::find_if(vals.begin(), vals.end(), [&](const ::std::string& x){ return switch_val == x; }); + if( it != vals.end() ) + { + auto idx = it - vals.begin(); + LOG_TRACE("- '" << switch_val << "' matched arm " << idx); + cur_frame.bb_idx = te.targets.at(idx); + } + else + { + LOG_TRACE("- '" << switch_val << "' not matched, taking default arm"); + cur_frame.bb_idx = te.def_target; + } } } } -- cgit v1.2.3 From fdd60793c48493584f6b2b691207a89a618e656d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 17 Aug 2019 17:22:50 +0800 Subject: Standalone MIRI - Refactor Value to allow one relocation inline --- tools/standalone_miri/miri.cpp | 49 ++--- tools/standalone_miri/module_tree.cpp | 8 +- tools/standalone_miri/value.cpp | 334 +++++++++++++++------------------- tools/standalone_miri/value.hpp | 127 ++++++++++--- 4 files changed, 274 insertions(+), 244 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 11c620ec..1a235880 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -562,7 +562,8 @@ 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, Allocation::PTR_BASE + 0, RelocationPtr::new_alloc(s->val.allocation)); + LOG_ASSERT(s->val.m_inner.is_alloc, "Statics should already have an allocation assigned"); + return Value::new_pointer(ty, Allocation::PTR_BASE + 0, RelocationPtr::new_alloc(s->val.m_inner.alloc.alloc)); } LOG_ERROR("Constant::ItemAddr - " << *ce << " - not found"); } break; @@ -683,11 +684,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) if( !alloc && src_base_value.m_value ) { LOG_DEBUG("Borrow - Creating allocation for " << src_base_value); - if( !src_base_value.m_value->allocation ) - { - src_base_value.m_value->create_allocation(); - } - alloc = RelocationPtr::new_alloc( src_base_value.m_value->allocation ); + alloc = RelocationPtr::new_alloc( src_base_value.m_value->borrow("Borrow") ); } if( alloc.is_alloc() ) LOG_DEBUG("Borrow - alloc=" << alloc << " (" << alloc.alloc() << ")"); @@ -1275,8 +1272,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) if( auto r = v_l.get_relocation(0) ) { LOG_DEBUG("- Restore relocation " << r); - new_val.create_allocation(); - new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), r); + new_val.set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), r); } break; @@ -1321,8 +1317,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) val_l.get().write_to_value(new_val, 0); if( new_val_reloc ) { - new_val.create_allocation(); - new_val.allocation->set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), ::std::move(new_val_reloc)); + new_val.set_reloc(0, ::std::min(POINTER_SIZE, new_val.size()), ::std::move(new_val_reloc)); } break; } @@ -1518,15 +1513,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) auto v = state.get_value_and_type(se.slot, 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 = RelocationPtr::new_alloc( v.m_value->allocation ); - } + auto alloc = (v.m_value ? RelocationPtr::new_alloc(v.m_value->borrow("drop")) : v.m_alloc); size_t ofs = v.m_offset; //LOG_ASSERT(ty.get_meta_type() == RawType::Unreachable, "Dropping an unsized type with Statement::Drop - " << ty); @@ -1587,6 +1574,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) auto v = state.get_value_and_type(te.val, ty); LOG_ASSERT(ty.get_wrapper() == nullptr, "Matching on wrapped value - " << ty); LOG_ASSERT(ty.inner_type == RawType::Composite, "Matching on non-coposite - " << ty); + LOG_DEBUG("Switch v = " << v); // TODO: Convert the variant list into something that makes it easier to switch on. size_t found_target = SIZE_MAX; @@ -1615,6 +1603,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) continue ; if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 ) { + LOG_DEBUG("Explicit match " << i); found_target = i; break ; } @@ -1623,6 +1612,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) if( found_target == SIZE_MAX ) { + LOG_DEBUG("Default match " << default_target); found_target = default_target; } if( found_target == SIZE_MAX ) @@ -1825,7 +1815,8 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) assert( blk.terminator.is_Call() ); const auto& te = blk.terminator.as_Call(); - LOG_DEBUG(te.ret_val << " = " << res_v << " (resume " << cur_frame.fcn->my_path << ")"); + LOG_DEBUG("Resume " << cur_frame.fcn->my_path); + LOG_DEBUG(te.ret_val << " = " << res_v); cur_frame.stmt_idx = 0; // If a panic is in progress (in thread state), take the panic block instead @@ -1967,6 +1958,8 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); LOG_DEBUG(link_name << "(size=" << size << ", align=" << align << "): name=" << alloc_name); + + // TODO: Use the alignment when making an allocation? 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 ); @@ -1976,12 +1969,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c alloc->mark_bytes_valid(0, size); } - // TODO: Use the alignment when making an allocation? 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); auto oldsize = args.at(1).read_usize(0); @@ -2001,7 +1992,6 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c } else if( link_name == "__rust_deallocate" || link_name == "__rust_dealloc" ) { - 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 == Allocation::PTR_BASE, "__rust_deallocate with offset pointer"); @@ -2350,10 +2340,9 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { 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); + rv.set_reloc(0, POINTER_SIZE, e.second); } } else @@ -2490,11 +2479,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c const void* ret = memchr(ptr, c, n); rv = Value(::HIR::TypeRef(RawType::USize)); - rv.create_allocation(); if( ret ) { - rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); - rv.allocation->relocations.push_back({ 0, ptr_alloc }); + auto rv_ofs = args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) ); + rv.write_ptr(0, rv_ofs, ptr_alloc); } else { @@ -2511,11 +2499,10 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c const void* ret = memrchr(ptr, c, n); rv = Value(::HIR::TypeRef(RawType::USize)); - rv.create_allocation(); if( ret ) { - rv.write_usize(0, args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) )); - rv.allocation->relocations.push_back({ 0, ptr_alloc }); + auto rv_ofs = args.at(0).read_usize(0) + ( static_cast(ret) - static_cast(ptr) ); + rv.write_ptr(0, rv_ofs, ptr_alloc); } else { diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 71a545fa..2d1eb838 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -152,8 +152,7 @@ bool Parser::parse_one() Static s; s.val = Value(ty); // - Statics need to always have an allocation (for references) - if( !s.val.allocation ) - s.val.create_allocation(); + s.val.ensure_allocation(); s.val.write_bytes(0, data.data(), data.size()); s.ty = ty; @@ -173,14 +172,13 @@ bool Parser::parse_one() auto reloc_str = ::std::move(lex.consume().strval); 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)) }); + s.val.set_reloc( ofs, size, RelocationPtr::new_alloc(::std::move(a)) ); } else if( lex.next() == "::" || lex.next() == "<" ) { auto reloc_path = parse_path(); - s.val.allocation->relocations.push_back({ ofs, /*size,*/ RelocationPtr::new_fcn(reloc_path) }); + s.val.set_reloc( ofs, size, RelocationPtr::new_fcn(reloc_path) ); } else { diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 8860c8d9..a497f0bd 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -21,6 +21,37 @@ namespace { return false; return ofs + size <= max_size; } + + void set_bit(uint8_t* p, size_t i, bool v) + { + if(v) { + p[i/8] |= 1 << (i%8); + } + else { + p[i/8] &= ~(1 << (i%8)); + } + } + bool get_bit(const uint8_t* p, size_t i) { + return (p[i/8] & (1 << (i%8))) != 0; + } + void copy_bits(uint8_t* dst, size_t dst_ofs, const uint8_t* src, size_t src_ofs, size_t len) + { + // Even number of bytes, fast copy + if( dst_ofs % 8 == 0 && src_ofs % 8 == 0 && len % 8 == 0 ) + { + for(size_t i = 0; i < len/8; i ++) + { + dst[dst_ofs/8 + i] = src[src_ofs/8 + i]; + } + } + else + { + for(size_t i = 0; i < len; i ++) + { + set_bit( dst, dst_ofs+i, get_bit(src, src_ofs+i) ); + } + } + } }; ::std::ostream& operator<<(::std::ostream& os, const Allocation* x) @@ -383,57 +414,25 @@ Value Allocation::read_value(size_t ofs, size_t size) const { if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size ) { + // NOTE: A relocation at offset zero is allowed + if( r.slot_ofs == ofs ) + continue ; has_reloc = true; } } - if( has_reloc || size > sizeof(rv.direct_data.data) ) - { - rv.allocation = Allocation::new_alloc(size, FMT_STRING("Allocation::read_value(" << ofs << "," << size << ")")); - - rv.write_bytes(0, this->data_ptr() + ofs, size); + rv = Value::with_size(size, has_reloc); + rv.write_bytes(0, this->data_ptr() + ofs, size); - for(const auto& r : this->relocations) - { - if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size ) - { - rv.allocation->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; - const uint8_t test_mask = (1 << (j%8)); - const uint8_t set_mask = (1 << (i%8)); - bool v = (this->m_mask[j/8] & test_mask) != 0; - if( v ) - { - rv.allocation->m_mask[i/8] |= set_mask; - } - } - } - else + for(const auto& r : this->relocations) { - rv.direct_data.size = static_cast(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 ++) + if( ofs <= r.slot_ofs && r.slot_ofs < ofs + size ) { - size_t j = ofs + i; - const uint8_t tst_mask = 1 << (j%8); - const uint8_t set_mask = 1 << (i%8); - bool v = (this->m_mask[j/8] & tst_mask) != 0; - if( v ) - { - rv.direct_data.mask[i/8] |= set_mask; - } + rv.set_reloc(r.slot_ofs - ofs, /*r.size*/POINTER_SIZE, r.backing_alloc); } } + // Copy the mask bits + copy_bits(rv.get_mask_mut(), 0, m_mask.data(), ofs, size); + return rv; } void Allocation::read_bytes(size_t ofs, void* dst, size_t count) const @@ -461,14 +460,15 @@ void Allocation::write_value(size_t ofs, Value v) LOG_ERROR("Use of freed memory " << this); //if( this->is_read_only ) // LOG_ERROR("Writing to read-only allocation " << this); - if( v.allocation ) + if( v.m_inner.is_alloc ) { - size_t v_size = v.allocation->size(); - const auto& src_alloc = *v.allocation; + const auto& src_alloc = *v.m_inner.alloc.alloc; + size_t v_size = src_alloc.size(); + assert(&src_alloc != this); // Shouldn't happen? + // Take a copy of the source mask auto s_mask = src_alloc.m_mask; - - // Save relocations first, because `Foo = Foo` is valid. + // Save relocations first, because `Foo = Foo` is valid? ::std::vector new_relocs = src_alloc.relocations; // - write_bytes removes any relocations in this region. write_bytes(ofs, src_alloc.data_ptr(), v_size); @@ -487,39 +487,16 @@ void Allocation::write_value(size_t ofs, Value v) } // Set mask in destination - if( ofs % 8 != 0 || v_size % 8 != 0 ) - { - // Lazy way, sets/clears individual bits - for(size_t i = 0; i < v_size; i ++) - { - uint8_t dbit = 1 << ((ofs+i) % 8); - if( s_mask[i/8] & (1 << (i %8)) ) - this->m_mask[ (ofs+i) / 8 ] |= dbit; - else - this->m_mask[ (ofs+i) / 8 ] &= ~dbit; - } - } - else - { - // Copy the mask bytes directly - for(size_t i = 0; i < v_size / 8; i ++) - { - this->m_mask[ofs/8+i] = s_mask[i]; - } - } + copy_bits(m_mask.data(), ofs, s_mask.data(), 0, v_size); } else { - this->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 ++) + this->write_bytes(ofs, v.data_ptr(), v.size()); + copy_bits(m_mask.data(), ofs, v.get_mask(), 0, v.size()); + // TODO: Copy relocation + if( v.m_inner.direct.reloc_0 ) { - uint8_t dbit = 1 << ((ofs+i) % 8); - if( v.direct_data.mask[i/8] & (1 << (i %8)) ) - this->m_mask[ (ofs+i) / 8 ] |= dbit; - else - this->m_mask[ (ofs+i) / 8 ] &= ~dbit; + this->set_reloc(ofs, POINTER_SIZE, ::std::move(v.m_inner.direct.reloc_0)); } } } @@ -618,58 +595,55 @@ void Allocation::set_reloc(size_t ofs, size_t len, RelocationPtr reloc) Value::Value() { - this->direct_data.size = 0; - memset(this->direct_data.mask, 0, sizeof(this->direct_data.mask)); + memset(&m_inner, 0, sizeof(m_inner)); } Value::Value(::HIR::TypeRef ty) { size_t size = ty.get_size(); // Support inline data if the data will fit within the inline region (which is the size of the metadata) - if( ty.get_size() <= sizeof(this->direct_data.data) ) + if( size <= sizeof(m_inner.direct.data) ) { // AND the type doesn't contain a pointer (of any kind) - if( ! ty.has_pointer() ) + // TODO: Pointers _are_ allowed now (but only one) + if( true || ! ty.has_pointer() ) { // Will fit in a inline allocation, nice. //LOG_TRACE("No pointers in " << ty << ", storing inline"); - this->direct_data.size = static_cast(size); - this->direct_data.mask[0] = 0; - this->direct_data.mask[1] = 0; + new(&m_inner.direct) Inner::Direct(size); return ; } } // Fallback: Make a new allocation //LOG_TRACE(" Creating allocation for " << ty); - this->allocation = Allocation::new_alloc(size, FMT_STRING(ty)); + new(&m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING(ty)) ); + assert(m_inner.is_alloc); } Value Value::with_size(size_t size, bool have_allocation) { Value rv; - if(have_allocation || size > sizeof(rv.direct_data.data)) + if(have_allocation || size > sizeof(m_inner.direct.data)) { - rv.allocation = Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")")); + new(&rv.m_inner.alloc) Inner::Alloc( Allocation::new_alloc(size, FMT_STRING("with_size(" << size << ")")) ); } else { - rv.direct_data.size = static_cast(size); - memset(rv.direct_data.mask, 0, sizeof(rv.direct_data.mask)); + new(&rv.m_inner.direct) Inner::Direct(size); } return rv; } Value Value::new_fnptr(const ::HIR::Path& fn_path) { Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) ); - assert(rv.allocation); - rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path)); + rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_fcn(fn_path)); return rv; } Value Value::new_ffiptr(FFIPointer ffi) { Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::USize }) ); - rv.create_allocation(); - rv.allocation->write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi)); + assert( !rv.m_inner.is_alloc ); + rv.write_ptr(0, Allocation::PTR_BASE, RelocationPtr::new_ffi(ffi)); return rv; } Value Value::new_pointer(::HIR::TypeRef ty, uint64_t v, RelocationPtr r) { @@ -707,52 +681,49 @@ Value Value::new_i64(int64_t v) { void Value::create_allocation() { - assert(!this->allocation); - this->allocation = Allocation::new_alloc(this->direct_data.size, "create_allocation"); - if( this->direct_data.size > 0 ) - this->allocation->m_mask[0] = this->direct_data.mask[0]; - if( this->direct_data.size > 8 ) - this->allocation->m_mask[1] = this->direct_data.mask[1]; - ::std::memcpy(this->allocation->data_ptr(), this->direct_data.data, this->direct_data.size); + assert(!m_inner.is_alloc); + auto new_alloc = Allocation::new_alloc(m_inner.direct.size, "create_allocation"); // TODO: Provide a better name? + auto& direct = m_inner.direct; + if( direct.size > 0 ) + new_alloc->m_mask[0] = direct.mask[0]; + if( direct.size > 8 ) + new_alloc->m_mask[1] = direct.mask[1]; + ::std::memcpy(new_alloc->data_ptr(), direct.data, direct.size); + if( direct.reloc_0 ) + { + new_alloc->set_reloc(0, POINTER_SIZE, ::std::move(direct.reloc_0)); + } + + new(&m_inner.alloc) Inner::Alloc(::std::move(new_alloc)); } void Value::check_bytes_valid(size_t ofs, size_t size) const { if( size == 0 ) return ; - if( this->allocation ) - { - this->allocation->check_bytes_valid(ofs, size); + if( !in_bounds(ofs, size, this->size()) ) { + LOG_ERROR("Read out of bounds " << ofs+size << " >= " << this->size()); + throw "ERROR"; } - else + const auto* mask = this->get_mask(); + for(size_t i = ofs; i < ofs + size; i++) { - if( size == 0 && this->direct_data.size > 0 ) { - return ; - } - if( !in_bounds(ofs, size, this->direct_data.size) ) { - LOG_ERROR("Read out of bounds " << ofs+size << " >= " << int(this->direct_data.size)); - throw "ERROR"; - } - for(size_t i = ofs; i < ofs + size; i++) + if( !get_bit(mask, i) ) { - if( !(this->direct_data.mask[i/8] & (1 << i%8)) ) - { - LOG_ERROR("Accessing invalid bytes in value"); - throw "ERROR"; - } + LOG_ERROR("Accessing invalid bytes in value, offset " << i << " of " << *this); } } } void Value::mark_bytes_valid(size_t ofs, size_t size) { - if( this->allocation ) + if( m_inner.is_alloc ) { - this->allocation->mark_bytes_valid(ofs, size); + m_inner.alloc.alloc->mark_bytes_valid(ofs, size); } else { for(size_t i = ofs; i < ofs+size; i++) { - this->direct_data.mask[i/8] |= (1 << i%8); + m_inner.direct.mask[i/8] |= (1 << i%8); } } } @@ -760,18 +731,28 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) Value Value::read_value(size_t ofs, size_t size) const { Value rv; - //TRACE_FUNCTION_R(ofs << ", " << size << ") - " << *this, rv); - if( this->allocation ) + TRACE_FUNCTION_R(ofs << ", " << size << " - " << *this, rv); + if( m_inner.is_alloc ) { - rv = this->allocation->read_value(ofs, size); + rv = m_inner.alloc.alloc->read_value(ofs, size); } else { // Inline always fits in inline. - rv.direct_data.size = static_cast(size); - rv.write_bytes(0, this->direct_data.data+ofs, size); - rv.direct_data.mask[0] = this->direct_data.mask[0]; - rv.direct_data.mask[1] = this->direct_data.mask[1]; + if( ofs == 0 && size == this->size() ) + { + rv = Value(*this); + } + else + { + rv.m_inner.direct.size = static_cast(size); + memcpy(rv.m_inner.direct.data, this->data_ptr() + ofs, size); + copy_bits(rv.m_inner.direct.mask, 0, this->get_mask(), ofs, size); + if( ofs == 0 ) + { + rv.m_inner.direct.reloc_0 = RelocationPtr(m_inner.direct.reloc_0); + } + } } return rv; } @@ -779,20 +760,14 @@ void Value::read_bytes(size_t ofs, void* dst, size_t count) const { if(count == 0) return ; - if( this->allocation ) + if( m_inner.is_alloc ) { - this->allocation->read_bytes(ofs, dst, count); + m_inner.alloc.alloc->read_bytes(ofs, dst, count); } else { check_bytes_valid(ofs, count); - - // TODO: Redundant due to above? - if( !in_bounds(ofs, count, this->direct_data.size) ) { - LOG_ERROR("Out of bounds read, " << ofs << "+" << count << " > " << this->size()); - throw "ERROR"; - } - ::std::memcpy(dst, this->direct_data.data + ofs, count); + ::std::memcpy(dst, m_inner.direct.data + ofs, count); } } @@ -800,82 +775,65 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) { if( count == 0 ) return ; - if( this->allocation ) + if( m_inner.is_alloc ) { - this->allocation->write_bytes(ofs, src, count); + m_inner.alloc.alloc->write_bytes(ofs, src, count); } else { - if( !in_bounds(ofs, count, this->direct_data.size) ) { - LOG_BUG("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")"); + auto& direct = m_inner.direct; + if( !in_bounds(ofs, count, direct.size) ) { + LOG_ERROR("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)direct.size << ")"); } - ::std::memcpy(this->direct_data.data + ofs, src, count); + ::std::memcpy(direct.data + ofs, src, count); mark_bytes_valid(ofs, count); + if( 0 <= ofs && ofs < POINTER_SIZE ) { + direct.reloc_0 = RelocationPtr(); + } } } void Value::write_value(size_t ofs, Value v) { - if( this->allocation ) + if( m_inner.is_alloc ) { - this->allocation->write_value(ofs, ::std::move(v)); + m_inner.alloc.alloc->write_value(ofs, ::std::move(v)); } else { - if( v.allocation && !v.allocation->relocations.empty() ) - { - this->create_allocation(); - this->allocation->write_value(ofs, ::std::move(v)); - } - else - { - write_bytes(ofs, v.direct_data.data, v.direct_data.size); + write_bytes(ofs, v.data_ptr(), v.size()); + // - Copy mask + copy_bits(this->get_mask_mut(), ofs, v.get_mask(), 0, v.size()); - // Lazy way, sets/clears individual bits - for(size_t i = 0; i < v.direct_data.size; i ++) + // TODO: Faster way of knowing where there are relocations + for(size_t i = 0; i < v.size(); i ++) + { + if( auto r = v.get_relocation(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; + this->set_reloc(ofs + i, POINTER_SIZE, r); } } } } void Value::write_ptr(size_t ofs, size_t ptr_ofs, RelocationPtr reloc) { - if( !this->allocation ) + if( m_inner.is_alloc ) { - LOG_ERROR("Writing a pointer with no allocation"); - } - this->allocation->write_ptr(ofs, ptr_ofs, ::std::move(reloc)); -} - -::std::ostream& operator<<(::std::ostream& os, const Value& v) -{ - if( v.allocation ) - { - os << *v.allocation; + m_inner.alloc.alloc->write_ptr(ofs, ptr_ofs, ::std::move(reloc)); } else { - auto flags = os.flags(); - os << ::std::hex; - for(size_t i = 0; i < v.direct_data.size; i++) + write_usize(ofs, ptr_ofs); + if( ofs != 0 ) { - if( i != 0 ) - os << " "; - if( v.direct_data.mask[i/8] & (1 << i%8) ) - { - os << ::std::setw(2) << ::std::setfill('0') << (int)v.direct_data.data[i]; - } - else - { - os << "--"; - } + LOG_ERROR("Writing a pointer with no allocation"); } - os.setf(flags); + m_inner.direct.reloc_0 = ::std::move(reloc); } +} + +::std::ostream& operator<<(::std::ostream& os, const Value& v) +{ + os << ValueRef(const_cast(v), 0, v.size()); return os; } extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) @@ -940,9 +898,9 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) break; } } - else if( v.m_value && v.m_value->allocation ) + else if( v.m_value && v.m_value->m_inner.is_alloc ) { - const auto& alloc = *v.m_value->allocation; + const auto& alloc = *v.m_value->m_inner.alloc.alloc; os << &alloc << "@" << v.m_offset << "+" << v.m_size << " "; @@ -976,7 +934,7 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } else if( v.m_value ) { - const auto& direct = v.m_value->direct_data; + const auto& direct = v.m_value->m_inner.direct; auto flags = os.flags(); os << ::std::hex; @@ -994,6 +952,10 @@ extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) } } os.setf(flags); + if(direct.reloc_0) + { + os << " { " << direct.reloc_0 << " }"; + } } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index dea4c890..a76e922b 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -313,39 +313,85 @@ extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); struct Value: public ValueCommonWrite { - // TODO: Use this union for more compact representation +//private: union Inner { bool is_alloc; - struct { + struct Alloc { bool is_alloc; AllocationHandle alloc; + + Alloc(AllocationHandle alloc): + is_alloc(true), + alloc(::std::move(alloc)) + { + } } alloc; // Sizeof = 4+8+8 = 20b (plus vtable?) - struct { + struct Direct { bool is_alloc; uint8_t size; uint8_t mask[2]; uint8_t data[2*8]; RelocationPtr reloc_0; // Relocation only for 0+POINTER_SIZE + + Direct(size_t size): + is_alloc(false), + size(static_cast(size)), + mask{0,0} + { + } } direct; - }; - // If NULL, data is direct - AllocationHandle allocation; - // TODO: Use an enum and a single relocation slot - struct { - // NOTE: Can't pack the mask+size tighter, need 4 bits of size (8-15) leaving 12 bits of mask - uint8_t data[2*8-3]; // 13 data bytes, plus 16bit mask, plus size = 16 bytes - uint8_t mask[2]; - uint8_t size; - } direct_data; + Inner(): + direct(0) + { + } + ~Inner() { + if(is_alloc) { + alloc.~Alloc(); + } + else { + direct.~Direct(); + } + } + Inner(const Inner& x) { + if(x.is_alloc) { + new(&this->alloc) Alloc(x.alloc); + } + else { + new(&this->direct) Direct(x.direct); + } + } + Inner(Inner&& x) { + if(x.is_alloc) { + new(&this->alloc) Alloc(::std::move(x.alloc)); + } + else { + new(&this->direct) Direct(::std::move(x.direct)); + } + } + Inner& operator=(Inner&& x) { + this->~Inner(); + new(this) Inner(x); + return *this; + } + Inner& operator=(const Inner& x) { + this->~Inner(); + new(this) Inner(x); + return *this; + } + } m_inner; + +public: Value(); Value(::HIR::TypeRef ty); + ~Value() { + } - //Value(const Value&) = delete; - //Value(Value&&) = default; - //Value& operator=(const Value&) = delete; - //Value& operator=(Value&&) = default; + Value(const Value&) = default; + Value(Value&&) = default; + Value& operator=(const Value& x) = delete; + Value& operator=(Value&& x) = default; static Value with_size(size_t size, bool have_allocation); static Value new_fnptr(const ::HIR::Path& fn_path); @@ -357,16 +403,49 @@ struct Value: static Value new_i32(int32_t v); static Value new_i64(int64_t v); + AllocationHandle borrow(::std::string loc) { + if( !m_inner.is_alloc ) + create_allocation(/*loc*/); + return m_inner.alloc.alloc; + } + void ensure_allocation() { + if( !m_inner.is_alloc ) + create_allocation(); + } void create_allocation(); - size_t size() const { return allocation ? allocation->size() : direct_data.size; } - const uint8_t* data_ptr() const { return allocation ? allocation->data_ptr() : direct_data.data; } - uint8_t* data_ptr() { return allocation ? allocation->data_ptr() : direct_data.data; } + size_t size() const { return m_inner.is_alloc ? m_inner.alloc.alloc->size() : m_inner.direct.size; } + const uint8_t* data_ptr() const { return m_inner.is_alloc ? m_inner.alloc.alloc->data_ptr() : m_inner.direct.data; } + uint8_t* data_ptr() { return m_inner.is_alloc ? m_inner.alloc.alloc->data_ptr() : m_inner.direct.data; } + const uint8_t* get_mask() const { return m_inner.is_alloc ? m_inner.alloc.alloc->m_mask.data() : m_inner.direct.mask; } + uint8_t* get_mask_mut() { return m_inner.is_alloc ? m_inner.alloc.alloc->m_mask.data() : m_inner.direct.mask; } RelocationPtr get_relocation(size_t ofs) const override { - if( this->allocation && this->allocation ) - return this->allocation->get_relocation(ofs); + if( m_inner.is_alloc ) + return m_inner.alloc.alloc->get_relocation(ofs); + else if(ofs == 0) + { + return m_inner.direct.reloc_0; + } else + { return RelocationPtr(); + } + } + void set_reloc(size_t ofs, size_t size, RelocationPtr p) /*override*/ { + if( m_inner.is_alloc ) + { + m_inner.alloc.alloc->set_reloc(ofs, size, ::std::move(p)); + } + else if( ofs == 0 /*&& size == POINTER_SIZE*/ ) + { + m_inner.direct.reloc_0 = ::std::move(p); + } + else + { + this->create_allocation(); + assert( m_inner.is_alloc ); + m_inner.alloc.alloc->set_reloc(ofs, size, ::std::move(p)); + } } void check_bytes_valid(size_t ofs, size_t size) const; @@ -557,3 +636,7 @@ struct ValueRef: bool compare(size_t offset, const void* other, size_t other_len) const; }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); +//struct ValueRefMut: +// public ValueCommonWrite +//{ +//}; -- cgit v1.2.3 From 3817f9e19020b04d1a39a5c2a8f30814eb0bc065 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 18 Aug 2019 09:23:33 +0800 Subject: Standalone MIRI - Correct handling of function types --- tools/standalone_miri/hir_sim.cpp | 68 ++++++++++++++++++++--------------- tools/standalone_miri/hir_sim.hpp | 32 ++++++++++++++--- tools/standalone_miri/miri.cpp | 35 +++++++++++------- tools/standalone_miri/module_tree.cpp | 11 ++++-- tools/standalone_miri/module_tree.hpp | 20 +++++++++++ 5 files changed, 118 insertions(+), 48 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index dc03ca8a..135ea214 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -42,18 +42,18 @@ size_t HIR::TypeRef::get_size(size_t ofs) const // Need to look up the metadata type for the actual type if( this->inner_type == RawType::Composite ) { - if( this->composite_type->dst_meta == RawType::Unreachable ) + if( this->composite_type().dst_meta == RawType::Unreachable ) { return POINTER_SIZE; } // Special case: extern types (which appear when a type is only ever used by pointer) - if( this->composite_type->dst_meta == RawType::Unit ) + if( this->composite_type().dst_meta == RawType::Unit ) { return POINTER_SIZE; } // 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(); + return POINTER_SIZE + this->composite_type().dst_meta.get_size(); } else if( this->inner_type == RawType::Str ) return POINTER_SIZE*2; @@ -77,8 +77,8 @@ 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; + 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); case RawType::TraitObject: @@ -126,8 +126,8 @@ size_t HIR::TypeRef::get_align(size_t ofs) const 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; + 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; @@ -217,7 +217,7 @@ bool HIR::TypeRef::has_pointer() const if( this->inner_type == RawType::Composite ) { // Still not sure, check the inner for any pointers. - for(const auto& fld : this->composite_type->fields) + for(const auto& fld : this->composite_type().fields) { if( fld.second.has_pointer() ) return true; @@ -245,13 +245,13 @@ const HIR::TypeRef* HIR::TypeRef::get_unsized_type(size_t& running_inner_size) c switch(this->inner_type) { case RawType::Composite: - if(!this->composite_type->variants.empty()) + if(!this->composite_type().variants.empty()) return nullptr; - if(this->composite_type->fields.empty()) + if(this->composite_type().fields.empty()) return nullptr; - running_inner_size = this->composite_type->fields.back().first; + running_inner_size = this->composite_type().fields.back().first; size_t tmp; - return this->composite_type->fields.back().second.get_unsized_type(tmp); + return this->composite_type().fields.back().second.get_unsized_type(tmp); case RawType::TraitObject: case RawType::Str: return this; @@ -278,11 +278,12 @@ HIR::TypeRef HIR::TypeRef::get_meta_type() const switch(this->inner_type) { case RawType::Composite: - if( this->composite_type->dst_meta == RawType::Unreachable ) + if( this->composite_type().dst_meta == RawType::Unreachable ) return TypeRef(RawType::Unreachable); - return this->composite_type->dst_meta; + return this->composite_type().dst_meta; case RawType::TraitObject: - return ::HIR::TypeRef(this->composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) ); + LOG_ASSERT(this->ptr.composite_type, "get_meta_type - " << *this); + return ::HIR::TypeRef(this->ptr.composite_type).wrap( TypeWrapper::Ty::Pointer, static_cast(BorrowType::Shared) ); case RawType::Str: return TypeRef(RawType::USize); default: @@ -316,9 +317,9 @@ 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; + 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; } else { @@ -330,14 +331,14 @@ size_t HIR::TypeRef::get_field_ofs(size_t base_idx, const ::std::vector& { assert(this->wrappers.size() == 0); assert(this->inner_type == RawType::Composite); - size_t ofs = this->composite_type->fields.at(base_idx).first; - const auto* ty_p = &this->composite_type->fields.at(base_idx).second; + size_t ofs = this->composite_type().fields.at(base_idx).first; + const auto* ty_p = &this->composite_type().fields.at(base_idx).second; for(auto idx : other_idx) { assert(ty_p->wrappers.size() == 0); assert(ty_p->inner_type == RawType::Composite); - ofs += ty_p->composite_type->fields.at(idx).first; - ty_p = &ty_p->composite_type->fields.at(idx).second; + ofs += ty_p->composite_type().fields.at(idx).first; + ty_p = &ty_p->composite_type().fields.at(idx).second; } ty = *ty_p; return ofs; @@ -394,19 +395,30 @@ namespace HIR { os << "()"; break; case RawType::Composite: - os << x.composite_type->my_path; + os << x.composite_type().my_path; //os << "composite_" << x.composite_type; break; case RawType::Unreachable: os << "!"; break; - case RawType::Function: - os << "function_?"; - break; + case RawType::Function: { + assert( x.ptr.function_type ); + const auto& ft = *x.ptr.function_type; + if( ft.unsafe ) + os << "unsafe "; + if( ft.abi != "Rust" ) + os << "extern \"" << ft.abi << "\" "; + os << "fn( "; + for(const auto& a : ft.args) + os << a << ", "; + os << ")"; + if( ft.ret != RawType::Unit ) + os << "-> " << ft.ret; + } break; case RawType::TraitObject: os << "dyn "; - if( x.composite_type ) - os << x.composite_type->my_path; + if( x.ptr.composite_type ) + os << x.composite_type().my_path; else os << "?"; break; diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 9483f1bb..81d3635a 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -28,6 +28,7 @@ enum Ordering #endif struct DataType; +struct FunctionType; enum class RawType { @@ -77,7 +78,6 @@ struct TypeWrapper } }; - namespace HIR { enum class BorrowType @@ -97,24 +97,35 @@ namespace HIR { // Top to bottom list of wrappers (first entry is the outermost wrapper) ::std::vector wrappers; RawType inner_type = RawType::Unit; - const DataType* composite_type = nullptr; + union { + const DataType* composite_type; + const FunctionType* function_type; + } ptr; TypeRef() { + ptr.composite_type = nullptr; } explicit TypeRef(const DataType* dt): - inner_type(RawType::Composite), - composite_type(dt) + inner_type(RawType::Composite) + { + ptr.composite_type = dt; + } + explicit TypeRef(const FunctionType* fp): + inner_type(RawType::Function) { + ptr.function_type = fp; } explicit TypeRef(RawType rt): inner_type(rt) { + ptr.composite_type = nullptr; } explicit TypeRef(CoreType ct): inner_type(ct.raw_type) { + ptr.composite_type = nullptr; } static TypeRef diverge() { TypeRef rv; @@ -165,6 +176,17 @@ namespace HIR { // Get the offset and type of a field (recursing using `other_idx`) size_t get_field_ofs(size_t idx, const ::std::vector& other_idx, TypeRef& ty) const; + const DataType& composite_type() const { + assert(inner_type == RawType::Composite || inner_type == RawType::TraitObject); + assert(ptr.composite_type); + return *ptr.composite_type; + } + const FunctionType& function_type() const { + assert(inner_type == RawType::Function); + assert(ptr.function_type); + return *ptr.function_type; + } + bool operator==(const RawType& x) const { if( this->wrappers.size() != 0 ) return false; @@ -176,7 +198,7 @@ namespace HIR { Ordering ord(const TypeRef& x) const { __ORD(wrappers); __ORD_C(int, inner_type); - __ORD_C(uintptr_t, composite_type); + __ORD_C(uintptr_t, ptr.composite_type); // pointer comparison only return OrdEqual; } bool operator==(const TypeRef& x) const { diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 1a235880..ab7e2e22 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -909,7 +909,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Unit: LOG_FATAL("Cast of unit"); case RawType::Composite: { - const auto& dt = *src_ty.composite_type; + const auto& dt = src_ty.composite_type(); if( dt.variants.size() == 0 ) { LOG_FATAL("Cast of composite - " << src_ty); } @@ -1418,10 +1418,18 @@ bool InterpreterThread::step_one(Value& out_thread_result) state.get_value_and_type(se.dst, dst_ty); new_val = Value(dst_ty); - for(size_t i = 0; i < re.vals.size(); i++) + if( dst_ty.inner_type == RawType::Unit ) + { + LOG_ASSERT(re.vals.size() == 0 , ""); + } + else { - auto fld_ofs = dst_ty.composite_type->fields.at(i).first; - new_val.write_value(fld_ofs, state.param_to_value(re.vals[i])); + LOG_ASSERT(dst_ty.inner_type == RawType::Composite, dst_ty); + for(size_t i = 0; i < re.vals.size(); i++) + { + auto fld_ofs = dst_ty.composite_type().fields.at(i).first; + new_val.write_value(fld_ofs, state.param_to_value(re.vals[i])); + } } } break; TU_ARM(se.src, Array, re) { @@ -1489,7 +1497,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) ::HIR::TypeRef dst_ty; state.get_value_and_type(se.dst, dst_ty); new_val = Value(dst_ty); - LOG_ASSERT(dst_ty.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input"); + LOG_ASSERT(dst_ty.inner_type == RawType::Composite, dst_ty); + LOG_ASSERT(dst_ty.ptr.composite_type == &data_ty, "Destination type of RValue::Struct isn't the same as the input"); for(size_t i = 0; i < re.vals.size(); i++) { @@ -1579,9 +1588,9 @@ bool InterpreterThread::step_one(Value& out_thread_result) // TODO: Convert the variant list into something that makes it easier to switch on. size_t found_target = SIZE_MAX; size_t default_target = SIZE_MAX; - for(size_t i = 0; i < ty.composite_type->variants.size(); i ++) + for(size_t i = 0; i < ty.composite_type().variants.size(); i ++) { - const auto& var = ty.composite_type->variants[i]; + const auto& var = ty.composite_type().variants[i]; if( var.tag_data.size() == 0 ) { // Save as the default, error for multiple defaults @@ -2589,10 +2598,10 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: size_t fallback = SIZE_MAX; size_t found_index = SIZE_MAX; - assert(ty.composite_type); - for(size_t i = 0; i < ty.composite_type->variants.size(); i ++) + LOG_ASSERT(ty.inner_type == RawType::Composite, "discriminant_value " << ty); + for(size_t i = 0; i < ty.composite_type().variants.size(); i ++) { - const auto& var = ty.composite_type->variants[i]; + const auto& var = ty.composite_type().variants[i]; if( var.tag_data.size() == 0 ) { // Only seen in Option @@ -3135,10 +3144,10 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ m_stack.insert( m_stack.end() - 1, StackFrame::make_wrapper([this,pty,ity,ptr_reloc,count, i,ofs](Value& rv, Value drop_rv) mutable { assert(i < count); i ++; + ofs += ity.get_size(); if( i < count ) { auto ptr = Value::new_pointer(pty, ofs, ptr_reloc); - ofs += ity.get_size(); assert(!drop_value(ptr, ity)); return false; } @@ -3162,12 +3171,12 @@ bool InterpreterThread::drop_value(Value ptr, const ::HIR::TypeRef& ty, bool is_ { if( ty.inner_type == RawType::Composite ) { - if( ty.composite_type->drop_glue != ::HIR::Path() ) + if( ty.composite_type().drop_glue != ::HIR::Path() ) { LOG_DEBUG("Drop - " << ty); Value tmp; - return this->call_path(tmp, ty.composite_type->drop_glue, { ptr }); + return this->call_path(tmp, ty.composite_type().drop_glue, { ptr }); } else { diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 2d1eb838..91d82d85 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -1229,7 +1229,14 @@ RawType Parser::parse_core_type() { ret_ty = ::HIR::TypeRef::unit(); } - return ::HIR::TypeRef(RawType::Function); + auto ft = FunctionType { + is_unsafe, + ::std::move(abi), + ::std::move(args), + ::std::move(ret_ty) + }; + const auto* ft_p = &*tree.function_types.insert(::std::move(ft)).first; + return ::HIR::TypeRef(ft_p); // TODO: Use abi/ret_ty/args as part of that } else if( lex.consume_if("dyn") ) @@ -1294,7 +1301,7 @@ RawType Parser::parse_core_type() 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) ); + rv.ptr.composite_type = this->get_composite( ::std::move(vtable_path) ); } else { diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index 5da8439f..299aa51c 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -49,6 +49,8 @@ class ModuleTree // Hack: Tuples are stored as `::""::` ::std::map<::HIR::GenericPath, ::std::unique_ptr> data_types; + ::std::set function_types; // note: insertion doesn't invaliate pointers. + ::std::map<::std::string, const Function*> ext_functions; public: ModuleTree(); @@ -95,3 +97,21 @@ struct DataType }; ::std::vector variants; }; + +struct FunctionType +{ + bool unsafe; + ::std::string abi; + ::std::vector args; + HIR::TypeRef ret; + + bool operator<(const FunctionType& x) const { + #define _(f) if(f != x.f) return f < x.f + _(unsafe); + _(abi); + _(args); + _(ret); + #undef _ + return false; + } +}; -- cgit v1.2.3 From fe4720652a185c25bfa462c334bf3893888a4a2a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Mon, 19 Aug 2019 07:30:18 +0800 Subject: Stanalone MIRI - Track frame counts (easier to step back across calls) --- tools/standalone_miri/debug.cpp | 1 + tools/standalone_miri/miri.cpp | 30 ++++++++++++++++++++---------- tools/standalone_miri/miri.hpp | 3 +++ 3 files changed, 24 insertions(+), 10 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp index be3c9ec4..534790cd 100644 --- a/tools/standalone_miri/debug.cpp +++ b/tools/standalone_miri/debug.cpp @@ -20,6 +20,7 @@ DebugSink::~DebugSink() { m_inner << "\n"; m_inner.flush(); + m_inner.flags({}); if( m_stderr_too ) { ::std::cerr << ::std::endl; diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index ab7e2e22..21c39a1e 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -616,7 +616,7 @@ InterpreterThread::~InterpreterThread() for(size_t i = 0; i < m_stack.size(); i++) { const auto& frame = m_stack[m_stack.size() - 1 - i]; - ::std::cout << "#" << i << ": "; + ::std::cout << "#" << i << ": F" << frame.frame_index << " "; if( frame.cb ) { ::std::cout << "WRAPPER"; @@ -650,7 +650,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) TRACE_FUNCTION_R("#" << instr_idx << " " << cur_frame.fcn->my_path << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx, "#" << instr_idx); const auto& bb = cur_frame.fcn->m_mir.blocks.at( cur_frame.bb_idx ); - const size_t MAX_STACK_DEPTH = 60; + const size_t MAX_STACK_DEPTH = 90; if( this->m_stack.size() > MAX_STACK_DEPTH ) { LOG_ERROR("Maximum stack depth of " << MAX_STACK_DEPTH << " exceeded"); @@ -661,7 +661,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) if( cur_frame.stmt_idx < bb.statements.size() ) { const auto& stmt = bb.statements[cur_frame.stmt_idx]; - LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx << ": " << stmt); + LOG_DEBUG("=== F" << cur_frame.frame_index << " BB" << cur_frame.bb_idx << "/" << cur_frame.stmt_idx << ": " << stmt); switch(stmt.tag()) { case ::MIR::Statement::TAGDEAD: throw ""; @@ -1098,7 +1098,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) res = 1; break; default: - LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations"); + LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations (" << reloc_l << " != " << reloc_r << ")"); } // - Equality will always fail // - Ordering is a bug @@ -1113,6 +1113,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) // Only one side // - Ordering is a bug // - Equalities are allowed, but only for `0`? + // > TODO: If the side with no reloation doesn't have value `0` then error? switch(re.op) { case ::MIR::eBinOp::EQ: @@ -1120,7 +1121,12 @@ bool InterpreterThread::step_one(Value& out_thread_result) // - Allow success, as addresses can be masked down break; default: - LOG_FATAL("Unable to compare " << v_l << " and " << v_r << " - different relocations"); + if( reloc_l ) + res = 1; + else// if( reloc_r ) + res = -1; + //LOG_FATAL("Unable to order " << v_l << " and " << v_r << " - different relocations"); + break; } } else @@ -1554,7 +1560,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) } else { - LOG_DEBUG("=== BB" << cur_frame.bb_idx << "/TERM: " << bb.terminator); + LOG_DEBUG("=== F" << cur_frame.frame_index << " BB" << cur_frame.bb_idx << "/TERM: " << bb.terminator); switch(bb.terminator.tag()) { case ::MIR::Terminator::TAGDEAD: throw ""; @@ -1825,7 +1831,7 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) const auto& te = blk.terminator.as_Call(); LOG_DEBUG("Resume " << cur_frame.fcn->my_path); - LOG_DEBUG(te.ret_val << " = " << res_v); + LOG_DEBUG("F" << cur_frame.frame_index << " " << te.ret_val << " = " << res_v); cur_frame.stmt_idx = 0; // If a panic is in progress (in thread state), take the panic block instead @@ -1846,7 +1852,9 @@ bool InterpreterThread::pop_stack(Value& out_thread_result) } } +unsigned InterpreterThread::StackFrame::s_next_frame_index = 0; InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vector args): + frame_index(s_next_frame_index++), fcn(&fcn), ret( fcn.ret_ty == RawType::Unreachable ? Value() : Value(fcn.ret_ty) ), args( ::std::move(args) ), @@ -1855,7 +1863,7 @@ InterpreterThread::StackFrame::StackFrame(const Function& fcn, ::std::vectorlocals.reserve( fcn.m_mir.locals.size() ); for(const auto& ty : fcn.m_mir.locals) { @@ -2747,11 +2755,13 @@ 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); - auto new_ofs = ptr_ofs + delta_counts * ty_params.tys.at(0).get_size(); + auto ty_size = ty_params.tys.at(0).get_size(); + LOG_DEBUG("\"offset\": 0x" << ::std::hex << ptr_ofs << " + 0x" << delta_counts << " * 0x" << ty_size); + ptr_ofs -= Allocation::PTR_BASE; + auto new_ofs = ptr_ofs + delta_counts * ty_size; if(POINTER_SIZE != 8) { new_ofs &= 0xFFFFFFFF; } diff --git a/tools/standalone_miri/miri.hpp b/tools/standalone_miri/miri.hpp index 0b7fd4d6..f835fedb 100644 --- a/tools/standalone_miri/miri.hpp +++ b/tools/standalone_miri/miri.hpp @@ -41,6 +41,9 @@ class InterpreterThread friend struct MirHelpers; struct StackFrame { + static unsigned s_next_frame_index; + unsigned frame_index; + ::std::function cb; const Function* fcn; Value ret; -- cgit v1.2.3 From 9ce35b65e5be4ce75b3b7aabe29c432128a17279 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 26 Oct 2019 16:09:24 +0800 Subject: All - Compilation fixes on VS2015 (constructors, warnings, missing files, class/struct disagreement, ) --- src/ast/crate.cpp | 38 ++++++++++++++++++---- src/hir/from_ast.cpp | 4 +-- src/hir/hir.hpp | 16 +++++++++ src/hir/type.hpp | 9 +++++ src/hir_expand/vtable.cpp | 11 +++---- src/hir_typeck/expr_visit.cpp | 7 ++++ src/include/span.hpp | 3 +- src/macro_rules/parse.cpp | 6 ++-- src/mir/from_hir.cpp | 1 + src/mir/mir.cpp | 1 + src/mir/mir.hpp | 2 +- src/rc_string.cpp | 1 + tools/standalone_miri/hir_sim.cpp | 2 ++ tools/standalone_miri/mir.cpp | 1 + tools/standalone_miri/miri.cpp | 13 ++++---- tools/standalone_miri/value.hpp | 5 ++- tools/testrunner/main.cpp | 3 ++ vsproject/minicargo/minicargo.vcxproj | 9 +++++ vsproject/minicargo/minicargo.vcxproj.filters | 3 ++ vsproject/mrustc.vcxproj | 7 ++-- vsproject/mrustc.vcxproj.filters | 21 ++++++++---- vsproject/standalone_miri/standalone_miri.vcxproj | 9 +++-- .../standalone_miri.vcxproj.filters | 3 ++ 23 files changed, 138 insertions(+), 37 deletions(-) (limited to 'tools/standalone_miri/miri.cpp') diff --git a/src/ast/crate.cpp b/src/ast/crate.cpp index e788f6e0..19a19381 100644 --- a/src/ast/crate.cpp +++ b/src/ast/crate.cpp @@ -12,7 +12,12 @@ #include // HIR::Crate #include // HIR_Deserialise #include -#include +#ifdef _WIN32 +# define NOGDI // prevent ERROR from being defined +# include +#else +# include +#endif ::std::vector<::std::string> AST::g_crate_load_dirs = { }; ::std::map<::std::string, ::std::string> AST::g_crate_overrides; @@ -167,6 +172,17 @@ RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::st path = ""; // Search for `p+"/lib"+name+"-*.rlib" (which would match e.g. libnum-0.11.rlib) +#ifdef _WIN32 + WIN32_FIND_DATA find_data; + auto mask = p + "\\*"; + HANDLE find_handle = FindFirstFile( mask.c_str(), &find_data ); + if( find_handle == INVALID_HANDLE_VALUE ) { + continue ; + } + do + { + const auto* fname = find_data.cFileName; +#else auto dp = opendir(p.c_str()); if( !dp ) { continue ; @@ -174,12 +190,15 @@ RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::st struct dirent *ent; while( (ent = readdir(dp)) != nullptr && path == "" ) { + const auto* fname = ent->d_name; +#endif + // AND the start is "lib"+name - size_t len = strlen(ent->d_name); - if( len > (sizeof(RLIB_SUFFIX)-1) && strcmp(ent->d_name + len - (sizeof(RLIB_SUFFIX)-1), RLIB_SUFFIX) == 0 ) + size_t len = strlen(fname); + if( len > (sizeof(RLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RLIB_SUFFIX)-1), RLIB_SUFFIX) == 0 ) { } - else if( len > (sizeof(RDYLIB_SUFFIX)-1) && strcmp(ent->d_name + len - (sizeof(RDYLIB_SUFFIX)-1), RDYLIB_SUFFIX) == 0 ) + else if( len > (sizeof(RDYLIB_SUFFIX)-1) && strcmp(fname + len - (sizeof(RDYLIB_SUFFIX)-1), RDYLIB_SUFFIX) == 0 ) { } else @@ -187,14 +206,19 @@ RcString Crate::load_extern_crate(Span sp, const RcString& name, const ::std::st continue ; } - DEBUG(ent->d_name << " vs " << name_prefix); + DEBUG(fname << " vs " << name_prefix); // Check if the entry ends with .rlib - if( strncmp(name_prefix.c_str(), ent->d_name, name_prefix.size()) != 0 ) + if( strncmp(name_prefix.c_str(), fname, name_prefix.size()) != 0 ) continue ; - paths.push_back( p + "/" + ent->d_name ); + paths.push_back( p + "/" + fname ); +#ifdef _WIN32 + } while( FindNextFile(find_handle, &find_data) ); + FindClose(find_handle); +#else } closedir(dp); +#endif if( paths.size() > 0 ) break; } diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index 54644806..4cde40fc 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -31,10 +31,10 @@ const ::AST::Crate* g_ast_crate_ptr; // -------------------------------------------------------------------- HIR::LifetimeRef LowerHIR_LifetimeRef(const ::AST::LifetimeRef& r) { - return HIR::LifetimeRef { + return HIR::LifetimeRef( // TODO: names? r.binding() - }; + ); } ::HIR::GenericParams LowerHIR_GenericParams(const ::AST::GenericParams& gp, bool* self_is_sized) diff --git a/src/hir/hir.hpp b/src/hir/hir.hpp index bdfc8d0b..8b718b4f 100644 --- a/src/hir/hir.hpp +++ b/src/hir/hir.hpp @@ -323,6 +323,22 @@ public: (Named, t_struct_fields) ); + Struct(GenericParams params, Repr repr, Data data) + :m_params(mv$(params)) + ,m_repr(mv$(repr)) + ,m_data(mv$(data)) + { + } + Struct(GenericParams params, Repr repr, Data data, unsigned align, TraitMarkings tm, StructMarkings sm) + :m_params(mv$(params)) + ,m_repr(mv$(repr)) + ,m_data(mv$(data)) + ,m_forced_alignment(align) + ,m_markings(mv$(tm)) + ,m_struct_markings(mv$(sm)) + { + } + GenericParams m_params; Repr m_repr; Data m_data; diff --git a/src/hir/type.hpp b/src/hir/type.hpp index fe28deed..cbc2e94a 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -93,6 +93,15 @@ struct LifetimeRef // Values below 2^16 are parameters/static, values above are per-function region IDs allocated during region inferrence. uint32_t binding = UNKNOWN; + LifetimeRef() + :binding(UNKNOWN) + { + } + LifetimeRef(uint32_t binding) + :binding(binding) + { + } + static LifetimeRef new_static() { LifetimeRef rv; rv.binding = STATIC; diff --git a/src/hir_expand/vtable.cpp b/src/hir_expand/vtable.cpp index cd7b3413..d2afff5d 100644 --- a/src/hir_expand/vtable.cpp +++ b/src/hir_expand/vtable.cpp @@ -231,12 +231,11 @@ namespace { } } // TODO: Would like to have access to the publicity marker - auto item_path = m_new_type(true, RcString::new_interned(FMT(p.get_name() << "#vtable")), ::HIR::Struct { - mv$(args), - ::HIR::Struct::Repr::Rust, - ::HIR::Struct::Data(mv$(fields)), - {} - }); + auto item_path = m_new_type( + true, + RcString::new_interned(FMT(p.get_name() << "#vtable")), + ::HIR::Struct(mv$(args), ::HIR::Struct::Repr::Rust, ::HIR::Struct::Data(mv$(fields))) + ); tr.m_vtable_path = item_path; DEBUG("Vtable structure created - " << item_path); ::HIR::GenericPath path( mv$(item_path), mv$(params) ); diff --git a/src/hir_typeck/expr_visit.cpp b/src/hir_typeck/expr_visit.cpp index c655bc52..df27b7d7 100644 --- a/src/hir_typeck/expr_visit.cpp +++ b/src/hir_typeck/expr_visit.cpp @@ -65,6 +65,12 @@ namespace typeck { TU_ARMA(Function, e) { m_item_generics = &e.m_params; } + TU_ARMA(Constant, e) { + m_item_generics = &e.m_params; + } + TU_ARMA(Static, e) { + m_item_generics = nullptr; + } } } else if( ip.parent->ty ) @@ -91,6 +97,7 @@ namespace typeck { } TU_ARMA(StructConstant, _e) BUG(sp, ip << " is StructConstant"); TU_ARMA(StructConstructor, _e) BUG(sp, ip << " is StructConstructor"); + TU_ARMA(Import, _e) BUG(sp, ip << " is Import"); } } } diff --git a/src/include/span.hpp b/src/include/span.hpp index 68d6bfdf..51c3440c 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -29,8 +29,9 @@ struct ProtoSpan unsigned int start_line; unsigned int start_ofs; }; -struct Span +class Span { +public: ::std::shared_ptr outer_span; // Expansion target for macros RcString filename; diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 97e1f8f9..43ffb097 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -58,7 +58,9 @@ public: switch( GET_TOK(tok, lex) ) { // TODO: Allow any reserved word - case TOK_RWORD_PUB ... TOK_RWORD_UNSIZED: + default: + if( !(TOK_RWORD_PUB <= tok.type() && tok.type() <= TOK_RWORD_UNSIZED) ) + throw ParseError::Unexpected(lex, tok); case TOK_IDENT: { auto name = tok.type() == TOK_IDENT ? tok.istr() : RcString::new_interned(FMT(tok)); GET_CHECK_TOK(tok, lex, TOK_COLON); @@ -123,8 +125,6 @@ public: throw ParseError::Unexpected(lex, tok); } break; } - default: - throw ParseError::Unexpected(lex, tok); } break; case TOK_EOF: diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 4ab1bf00..697f8141 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -19,6 +19,7 @@ #include #include #include // Target_GetSizeAndAlignOf - for `box` +#include // isdigit namespace { diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 8e3045d6..a0def040 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -6,6 +6,7 @@ * - MIR (Middle Intermediate Representation) definitions */ #include +#include // std::min namespace MIR { ::std::ostream& operator<<(::std::ostream& os, const Constant& v) { diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index f3d61dfa..99698134 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -655,7 +655,7 @@ public: ~EnumCachePtr(); EnumCachePtr(EnumCachePtr&& x): p(x.p) { x.p = nullptr; } EnumCachePtr& operator=(EnumCachePtr&& x) { this->~EnumCachePtr(); p = x.p; x.p = nullptr; return *this; } - operator bool() { return p; } + operator bool() { return p != nullptr; } const EnumCache& operator*() const { return *p; } const EnumCache* operator->() const { return p; } }; diff --git a/src/rc_string.cpp b/src/rc_string.cpp index 38f6b15d..260ba90a 100644 --- a/src/rc_string.cpp +++ b/src/rc_string.cpp @@ -9,6 +9,7 @@ #include #include #include +#include // std::max RcString::RcString(const char* s, unsigned int len): m_ptr(nullptr) diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 135ea214..9d497054 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -156,6 +156,8 @@ size_t HIR::TypeRef::get_align(size_t ofs) const case RawType::USize: case RawType::ISize: return POINTER_SIZE; + case RawType::Unreachable: + LOG_BUG("Getting alignment of unreachable type"); } throw ""; } diff --git a/tools/standalone_miri/mir.cpp b/tools/standalone_miri/mir.cpp index 4a5df067..bc456ca6 100644 --- a/tools/standalone_miri/mir.cpp +++ b/tools/standalone_miri/mir.cpp @@ -9,6 +9,7 @@ #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" #include +#include // std::min #if 0 namespace std { diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 21c39a1e..4eadac66 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -5,6 +5,7 @@ * miri.cpp * - Interpreter core */ +#define _CRT_SECURE_NO_WARNINGS #include #include "module_tree.hpp" #include "value.hpp" @@ -15,13 +16,14 @@ #include "miri.hpp" // VVV FFI #include // memrchr +#include +#include #ifdef _WIN32 # define NOMINMAX # include +#else +# include #endif -#include -#include -#include #undef DEBUG unsigned ThreadState::s_next_tls_key = 1; @@ -2082,7 +2084,6 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c } else if( link_name == "GetModuleHandleW" ) { - LOG_ASSERT(args.at(0).allocation, ""); const auto& tgt_alloc = args.at(0).get_relocation(0); const void* arg0 = (tgt_alloc ? tgt_alloc.alloc().data_ptr() : nullptr); //extern void* GetModuleHandleW(const void* s); @@ -2096,7 +2097,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto ret = GetModuleHandleW(static_cast(arg0)); if(ret) { - rv = Value::new_ffiptr(FFIPointer { "GetModuleHandleW", ret, 0 }); + rv = Value::new_ffiptr(FFIPointer::new_void("GetModuleHandleW", ret)); } else { @@ -2121,7 +2122,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c if( ret ) { - rv = Value::new_ffiptr(FFIPointer { "GetProcAddress", ret, 0 }); + rv = Value::new_ffiptr(FFIPointer::new_void("GetProcAddress", ret)); } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index a76e922b..03a21970 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -57,6 +57,9 @@ struct FFIPointer const char* tag_name; ::std::shared_ptr layout; + static FFIPointer new_void(const char* name, const void* v) { + return FFIPointer { const_cast(v), name, ::std::make_shared() }; + } 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)) }; }; @@ -511,7 +514,7 @@ struct ValueRef: LOG_NOTICE("ValueRef exceeds bounds of FFI buffer - " << ofs << "+" << size << " > " << m_alloc.ffi().get_size()); } break; - default: + case RelocationPtr::Ty::Function: LOG_TODO(""); } } diff --git a/tools/testrunner/main.cpp b/tools/testrunner/main.cpp index 148fff9d..a634d87a 100644 --- a/tools/testrunner/main.cpp +++ b/tools/testrunner/main.cpp @@ -170,12 +170,15 @@ int main(int argc, const char* argv[]) return v; } +#ifdef _WIN32 +#else { struct sigaction sa = {0}; sa.sa_handler = sigalrm_handler; sigaction(SIGALRM, &sa, NULL); signal(SIGINT, sigint_handler); } +#endif ::std::vector<::std::string> skip_list; // > Filter out tests listed in an exceptions file (newline separated, supports comments) diff --git a/vsproject/minicargo/minicargo.vcxproj b/vsproject/minicargo/minicargo.vcxproj index 25ffbe03..c632cee2 100644 --- a/vsproject/minicargo/minicargo.vcxproj +++ b/vsproject/minicargo/minicargo.vcxproj @@ -75,6 +75,8 @@ Disabled true ..\..\tools\common + + $(OutDir) @@ -87,6 +89,8 @@ Disabled true ..\..\tools\common + + $(OutDir) @@ -101,6 +105,8 @@ true true ..\..\tools\common + + true @@ -117,6 +123,8 @@ true true ..\..\tools\common + + true @@ -127,6 +135,7 @@ + diff --git a/vsproject/minicargo/minicargo.vcxproj.filters b/vsproject/minicargo/minicargo.vcxproj.filters index 8fcee797..b9066a85 100644 --- a/vsproject/minicargo/minicargo.vcxproj.filters +++ b/vsproject/minicargo/minicargo.vcxproj.filters @@ -27,6 +27,9 @@ Source Files + + Source Files + diff --git a/vsproject/mrustc.vcxproj b/vsproject/mrustc.vcxproj index 13c4a23e..6cd135f4 100644 --- a/vsproject/mrustc.vcxproj +++ b/vsproject/mrustc.vcxproj @@ -157,6 +157,8 @@ + + @@ -166,6 +168,7 @@ + @@ -193,6 +196,7 @@ + @@ -204,9 +208,9 @@ + - @@ -259,7 +263,6 @@ - diff --git a/vsproject/mrustc.vcxproj.filters b/vsproject/mrustc.vcxproj.filters index 755013af..9d9dbcb4 100644 --- a/vsproject/mrustc.vcxproj.filters +++ b/vsproject/mrustc.vcxproj.filters @@ -98,9 +98,6 @@ Source Files\hir_expand - - Source Files\hir_expand - Source Files\hir_conv @@ -212,9 +209,6 @@ Source Files\trans - - Source Files\trans - Source Files\expand @@ -392,6 +386,21 @@ Source Files + + Source Files\trans + + + Source Files\trans + + + Source Files\hir_conv + + + Source Files\hir + + + Source Files\expand + diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj b/vsproject/standalone_miri/standalone_miri.vcxproj index 5c235353..6b3c317c 100644 --- a/vsproject/standalone_miri/standalone_miri.vcxproj +++ b/vsproject/standalone_miri/standalone_miri.vcxproj @@ -90,7 +90,8 @@ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true $(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories) - 4062;4061;%(TreatSpecificWarningsAsErrors) + 4062;%(TreatSpecificWarningsAsErrors) + 4061 Console @@ -106,7 +107,8 @@ _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true $(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories) - 4062;4061;%(TreatSpecificWarningsAsErrors) + 4062;%(TreatSpecificWarningsAsErrors) + 4061 Console @@ -125,6 +127,7 @@ true $(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories) 4062;%(TreatSpecificWarningsAsErrors) + 4061 Console @@ -145,6 +148,7 @@ true $(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories) 4062;%(TreatSpecificWarningsAsErrors) + 4061 Console @@ -165,6 +169,7 @@ + diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj.filters b/vsproject/standalone_miri/standalone_miri.vcxproj.filters index 3b25bbfb..5e7af341 100644 --- a/vsproject/standalone_miri/standalone_miri.vcxproj.filters +++ b/vsproject/standalone_miri/standalone_miri.vcxproj.filters @@ -62,5 +62,8 @@ Source Files + + Source Files + \ No newline at end of file -- cgit v1.2.3