diff --git a/VTIL-Architecture/symex/pointer.hpp b/VTIL-Architecture/symex/pointer.hpp index eb82c35..fc91f43 100644 --- a/VTIL-Architecture/symex/pointer.hpp +++ b/VTIL-Architecture/symex/pointer.hpp @@ -66,7 +66,7 @@ namespace vtil::symbolic // Construct from symbolic expression. // pointer( const expression::reference& base ); - pointer( const expression& base ) : pointer( ( ( expression::reference&& ) make_local_reference( &base ) ) ) {} + pointer( const expression& base ) : pointer( make_local_reference( &base ) ) {} // Default copy/move. // diff --git a/VTIL-Architecture/symex/translation.hpp b/VTIL-Architecture/symex/translation.hpp index f232eb9..063810f 100644 --- a/VTIL-Architecture/symex/translation.hpp +++ b/VTIL-Architecture/symex/translation.hpp @@ -47,9 +47,9 @@ namespace vtil return tbl; }(); - fassert( lookup_table.size() > ( size_t ) op ); + dassert( lookup_table.size() > ( size_t ) op ); const instruction_desc* desc = lookup_table[ ( size_t ) op ]; - fassert( desc ); + dassert( desc ); return desc; } diff --git a/VTIL-Architecture/trace/tracer.cpp b/VTIL-Architecture/trace/tracer.cpp index 54d486b..fa6e0ba 100644 --- a/VTIL-Architecture/trace/tracer.cpp +++ b/VTIL-Architecture/trace/tracer.cpp @@ -274,7 +274,7 @@ namespace vtil ref.simplify(); return false; } - ref = {}; + ref.reset(); return *result; } @@ -414,7 +414,7 @@ namespace vtil { symbolic::variable&& var = std::move( ( +exp )->uid.get() ); var.is_branch_dependant = true; - *+exp = { var, exp->size() }; + exp = symbolic::expression{ var, exp->size() }; } }, true, false ); } diff --git a/VTIL-Architecture/vm/interface.cpp b/VTIL-Architecture/vm/interface.cpp index a347482..11e958a 100644 --- a/VTIL-Architecture/vm/interface.cpp +++ b/VTIL-Architecture/vm/interface.cpp @@ -61,7 +61,7 @@ namespace vtil // else { - fassert( op.is_immediate() ); + dassert( op.is_immediate() ); return { op.imm().i64, op.imm().bit_count }; } }; @@ -186,7 +186,7 @@ namespace vtil // Operand 0 should always be the result for this class. // - fassert( ins.base->operand_types[ 0 ] >= operand_type::write ); + dassert( ins.base->operand_types[ 0 ] >= operand_type::write ); return vm_exit_reason::none; } // If NOP: diff --git a/VTIL-Common/io/formatting.hpp b/VTIL-Common/io/formatting.hpp index dc0c077..8dbbcd3 100644 --- a/VTIL-Common/io/formatting.hpp +++ b/VTIL-Common/io/formatting.hpp @@ -160,7 +160,7 @@ namespace vtil::format template static auto as_string( const T& x ); template - concept StringConvertible = requires( T v ) { !is_specialization_v; }; + concept StringConvertible = requires( std::string res, T v ) { res = as_string( v ); }; template __forceinline static auto as_string( const T& x ) @@ -190,7 +190,7 @@ namespace vtil::format } else if constexpr ( std::is_same_v ) { - return std::string{ x ? "true" : "false" }; + return x ? "true"s : "false"s; } else if constexpr ( StdStringConvertible ) { @@ -248,7 +248,7 @@ namespace vtil::format }(); if constexpr ( std::tuple_size_v == 0 ) - return "{}"; + return "{}"s; else if constexpr ( is_tuple_str_cvtable ) { std::string res = std::apply( [ ] ( auto&&... args ) { @@ -265,7 +265,7 @@ namespace vtil::format if ( x.has_value() ) return as_string( x.value() ); else - return std::string{ "nullopt" }; + return "nullopt"s; } else return type_tag{}; } @@ -277,11 +277,11 @@ namespace vtil::format } else if constexpr ( Iterable ) { - if constexpr ( StringConvertible ) + if constexpr ( StringConvertible> ) { std::string items = {}; for ( auto&& entry : x ) - items += as_string( entry ) + ", "; + items += as_string( entry ) + ", "s; if ( !items.empty() ) items.resize( items.size() - 2 ); return "{" + items + "}"; } diff --git a/VTIL-Common/io/logger.hpp b/VTIL-Common/io/logger.hpp index 2a4326c..639201c 100644 --- a/VTIL-Common/io/logger.hpp +++ b/VTIL-Common/io/logger.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "formatting.hpp" #include "../util/intrinsics.hpp" #include "../util/literals.hpp" @@ -176,68 +177,84 @@ namespace vtil::logger // Main function used when logging. // + namespace impl + { + template + static int log_w( FILE* dst, console_color color, const char* fmt, ... ) + { + // Hold the lock for the critical section guarding ::log. + // + std::lock_guard g( logger_state ); + + // Do not execute if logs are disabled. + // + if ( logger_state.mute ) return 0; + + // If we should pad this output: + // + int out_cnt = 0; + if ( logger_state.padding > 0 ) + { + // If it was not carried from previous: + // + if ( int pad_by = logger_state.padding - logger_state.padding_carry ) + { + for ( int i = 0; i < pad_by; i++ ) + { + if ( ( i + 1 ) == pad_by ) + { + out_cnt += fprintf( dst, "%*c", log_padding_step - 1, ' ' ); + if ( fmt[ 0 ] == ' ' ) putchar( log_padding_c ); + } + else + { + out_cnt += fprintf( dst, "%*c%c", log_padding_step - 1, ' ', log_padding_c ); + } + } + } + + // Set or clear the carry for next. + // + if ( fmt[ strlen( fmt ) - 1 ] == '\n' ) + logger_state.padding_carry = 0; + else + logger_state.padding_carry = logger_state.padding; + } + + // Set to requested color and redirect to printf. + // + set_color( color ); + + // If string literal with no parameters, use puts instead. + // + if ( has_args ) + { + va_list args; + va_start( args, fmt ); + out_cnt += vfprintf( dst, fmt, args ); + va_end( args ); + } + else + { + out_cnt += fputs( fmt, dst ); + } + + // Reset to defualt color. + // + set_color( CON_DEF ); + return out_cnt; + } + }; + template static int log( console_color color, const char* fmt, params&&... ps ) { - // Hold the lock for the critical section guarding ::log. - // - std::lock_guard g( logger_state ); - - // Do not execute if logs are disabled. - // - if ( logger_state.mute ) return 0; - - // If we should pad this output: - // - int out_cnt = 0; - if ( logger_state.padding > 0 ) - { - // If it was not carried from previous: - // - if ( int pad_by = logger_state.padding - logger_state.padding_carry ) - { - for ( int i = 0; i < pad_by; i++ ) - { - if ( ( i + 1 ) == pad_by ) - { - out_cnt += fprintf( VTIL_LOGGER_DST, "%*c", log_padding_step - 1, ' ' ); - if ( fmt[ 0 ] == ' ' ) putchar( log_padding_c ); - } - else - { - out_cnt += fprintf( VTIL_LOGGER_DST, "%*c%c", log_padding_step - 1, ' ', log_padding_c ); - } - } - } - - // Set or clear the carry for next. - // - if ( fmt[ strlen( fmt ) - 1 ] == '\n' ) - logger_state.padding_carry = 0; - else - logger_state.padding_carry = logger_state.padding; - } - - // Set to requested color and redirect to printf. - // - set_color( color ); - - // If string literal with no parameters, use puts instead. - // - if ( sizeof...( ps ) == 0 ) - out_cnt += fputs( fmt, VTIL_LOGGER_DST ); - else - out_cnt += fprintf( VTIL_LOGGER_DST, fmt, format::fix_parameter( std::forward( ps ) )... ); - - // Reset to defualt color. - // - set_color( CON_DEF ); - return out_cnt; + return impl::log_w( VTIL_LOGGER_DST, color, fmt, format::fix_parameter( std::forward( ps ) )... ); } template static int log( const char* fmt, params&&... ps ) { - return log( color, fmt, std::forward( ps )... ); + return impl::log_w( VTIL_LOGGER_DST, color, fmt, format::fix_parameter( std::forward( ps ) )... ); } // Prints a warning message. diff --git a/VTIL-Common/util/copy_on_write.hpp b/VTIL-Common/util/copy_on_write.hpp index 447fdb6..6608fb6 100644 --- a/VTIL-Common/util/copy_on_write.hpp +++ b/VTIL-Common/util/copy_on_write.hpp @@ -42,33 +42,6 @@ namespace vtil { namespace impl { - template struct first_of { using type = std::tuple_element_t<0, std::tuple>; }; - template<> struct first_of<> { using type = void; }; - - template - using first_of_t = typename first_of::type; - - template - static constexpr bool should_invoke_constructor() - { - // Constructor should be always invoked if we have more than one parameter and - // never if we have zero parameters. - // - if constexpr ( sizeof...( params ) != 1 ) - { - return sizeof...( params ) != 0; - } - else - { - // Invoke if not equal to the reference type. - // - return !std::is_base_of_v>>; - } - } - - template - using enable_if_constructor = typename std::enable_if_t(), int>; - template inline static T* reloc_const( const T* ptr, const void* src, void* dst ) { @@ -87,7 +60,7 @@ namespace vtil // Used to implement shared and extremely fast Copy-on-Write memory. // template - struct shared_reference + struct base_shared_reference { // Declare the object entry and its pool. // @@ -138,25 +111,24 @@ namespace vtil // Null reference construction. // - constexpr shared_reference() : combined_value( 0 ) {} - constexpr shared_reference( std::nullptr_t ) : shared_reference() {} - constexpr shared_reference( std::nullopt_t ) : shared_reference() {} + constexpr base_shared_reference() : combined_value( 0 ) {} + constexpr base_shared_reference( std::nullptr_t ) : base_shared_reference() {} // Owning reference constructor. // - template, params...> = 0> - shared_reference( params&&... p ) + template requires ( Constructable && sizeof...( Tx ) > 0 ) + base_shared_reference( Tx&&... p ) { combined_value = ( uint64_t ) object_pool::construct ( - /*Object itself*/ T( std::forward( p )... ), + /*Object itself*/ T( std::forward( p )... ), /*Reference counter*/ 1 ); } // Shared reference constructor. // - shared_reference( const shared_reference& ref ) + base_shared_reference( const base_shared_reference& ref ) : combined_value( ref.combined_value ) { // If object is null, return. @@ -173,7 +145,7 @@ namespace vtil else inc_ref( get_entry() ); } - shared_reference& operator=( const shared_reference& o ) + base_shared_reference& operator=( const base_shared_reference& o ) { // If object is null, reset and return. // @@ -225,15 +197,44 @@ namespace vtil // Construction and assignment operator for rvalue references. // - shared_reference( shared_reference&& ref ) + base_shared_reference( base_shared_reference&& ref ) : combined_value( std::exchange( ref.combined_value, 0 ) ) {} - shared_reference& operator=( shared_reference&& o ) + base_shared_reference& operator=( base_shared_reference&& o ) { uint64_t value = std::exchange( o.combined_value, 0 ); reset().combined_value = value; return *this; } + // Assignment of value. + // + template requires Constructable + base_shared_reference& operator=( Tv&& value ) + { + // If we have valid memory: + // + if ( combined_value ) + { + // If it's unique memory, move over it and return, otherwise dereference. + // + if ( is_temporary() || get_ref( get_entry() ) == 1 ) + { + *( T* ) pointer = std::forward( value ); + return *this; + } + dec_ref( get_entry() ); + } + + // Construct a new object and return. + // + combined_value = ( uint64_t ) object_pool::construct + ( + /*Object itself*/ std::forward( value ), + /*Reference counter*/ 1 + ); + return *this; + } + // Gets object entry. // constexpr object_entry* get_entry() const { dassert( !is_temporary() ); return _entry; } @@ -292,8 +293,8 @@ namespace vtil // Basic comparison operators are redirected to the pointer type. // - constexpr bool operator==( const shared_reference& o ) const { return combined_value == o.combined_value; } - constexpr bool operator<( const shared_reference& o ) const { return combined_value < o.combined_value; } + constexpr bool operator==( const base_shared_reference& o ) const { return combined_value == o.combined_value; } + constexpr bool operator<( const base_shared_reference& o ) const { return combined_value < o.combined_value; } // Redirect pointer and dereferencing operator to the reference and cast to const-qualified equivalent. // @@ -312,7 +313,7 @@ namespace vtil // Resets the reference to nullptr. // - __forceinline shared_reference& reset() + __forceinline base_shared_reference& reset() { // If non-temporary and non-null, decrement reference count, if // it reaches 0, destroy the object and deallocate. @@ -328,9 +329,16 @@ namespace vtil // Constructor invokes reset. // - ~shared_reference() { reset(); } + ~base_shared_reference() { reset(); } }; + // Can be overloaded to implement customization. + // + template + struct specialized_shared_reference { using type = base_shared_reference; }; + template + using shared_reference = typename specialized_shared_reference::type; + // Weak references are used to store shared references without implying // ownership. This class should not be used together with temporaries. // diff --git a/VTIL-Common/util/hashable.hpp b/VTIL-Common/util/hashable.hpp index d960515..43c9ff4 100644 --- a/VTIL-Common/util/hashable.hpp +++ b/VTIL-Common/util/hashable.hpp @@ -123,12 +123,17 @@ namespace vtil // else if constexpr ( Iterable ) { - hash_t hash = {}; - size_t i = 0; - for ( const auto& entry : value ) - hash = combine_hash( hash, hasher>{}( entry ) ), i++; - hash.add_bytes( sizeof( T ) + i ); - return hash; + using value_type = std::decay_t>; + + if constexpr ( !std::is_void_v{}( std::declval() ) ) > ) + { + hash_t hash = {}; + size_t i = 0; + for ( const auto& entry : value ) + hash = combine_hash( hash, hasher{}( entry ) ), i++; + hash.add_bytes( sizeof( T ) + i ); + return hash; + } } // If hash, combine with default seed. // diff --git a/VTIL-Common/util/reducable.hpp b/VTIL-Common/util/reducable.hpp index 6515661..ce21789 100644 --- a/VTIL-Common/util/reducable.hpp +++ b/VTIL-Common/util/reducable.hpp @@ -73,34 +73,6 @@ #pragma warning(disable: 4305) namespace vtil { - namespace impl - { - // Applies type modifier over each element in pair/tuple. - // - template typename F, typename T> - struct apply_each { using type = F; }; - template typename F, typename... T> - struct apply_each> { using type = std::pair...>; }; - template typename F, typename... T> - struct apply_each> { using type = std::tuple...>; }; - template typename F, typename T> - using apply_each_t = typename apply_each::type; - }; - - // Mask of requested reducable auto declarations. - // - enum reducable_auto_decl_id : uint8_t - { - reducable_none = 0x00, - reducable_equ = 1 << 0, - reducable_nequ = 1 << 1, - reducable_leq = 1 << 2, - reducable_greq = 1 << 3, - reducable_less = 1 << 4, - reducable_greater = 1 << 5, - reducable_all = 0xFF, - }; - // Reducable tag let's us check if a type is reducable without having // to template for proxied type or the auto-decl flags. // @@ -113,7 +85,7 @@ namespace vtil // The main definition of the helper: // - template + template struct reducable : reducable_tag_t { protected: @@ -132,18 +104,9 @@ namespace vtil public: // Define basic comparison operators using std::tuple. // - template = 0> - __forceinline constexpr auto operator==( const T& other ) const { return &other == this || reduce_proxy( ( T& ) *this ) == reduce_proxy( other ); } - template = 0> - __forceinline constexpr auto operator!=( const T& other ) const { return &other != this && reduce_proxy( ( T& ) *this ) != reduce_proxy( other ); } - template = 0> - __forceinline constexpr auto operator<=( const T& other ) const { return &other == this || reduce_proxy( ( T& ) *this ) <= reduce_proxy( other ); } - template = 0> - __forceinline constexpr auto operator>=( const T& other ) const { return &other == this || reduce_proxy( ( T& ) *this ) >= reduce_proxy( other ); } - template = 0> - __forceinline constexpr auto operator< ( const T& other ) const { return &other != this && reduce_proxy( ( T& ) *this ) < reduce_proxy( other ); } - template = 0> - __forceinline constexpr auto operator> ( const T& other ) const { return &other != this && reduce_proxy( ( T& ) *this ) > reduce_proxy( other ); } + __forceinline constexpr auto operator==( const T& other ) const { return &other == this || reduce_proxy( ( const T& ) *this ) == reduce_proxy( other ); } + __forceinline constexpr auto operator!=( const T& other ) const { return &other != this && reduce_proxy( ( const T& ) *this ) != reduce_proxy( other ); } + __forceinline constexpr auto operator< ( const T& other ) const { return &other != this && reduce_proxy( ( const T& ) *this ) > reduce_proxy( other ); } // Define VTIL hash using a simple VTIL tuple hasher. // diff --git a/VTIL-Common/util/type_helpers.hpp b/VTIL-Common/util/type_helpers.hpp index 6b34865..4c0791f 100644 --- a/VTIL-Common/util/type_helpers.hpp +++ b/VTIL-Common/util/type_helpers.hpp @@ -149,10 +149,20 @@ namespace vtil template typename Tmp, typename T> concept Specialization = is_specialization_v; template - concept Constructable = requires { T( std::declval()... ); }; + concept Constructable = requires( Args&&... a ) { T( a... ); }; template concept Assignable = requires( T r, X v ) { r = v; }; + // Comparison traits. + // + template concept ThreeWayComparable = requires( T&& a, O&& b ) { a <=> b; }; + template concept LessEqualComparable = requires( T&& a, O&& b ) { a <= b; }; + template concept LessComparable = requires( T&& a, O&& b ) { a < b; }; + template concept EqualComparable = requires( T&& a, O&& b ) { a == b; }; + template concept NotEqualComparable = requires( T&& a, O&& b ) { a != b; }; + template concept GreatComparable = requires( T&& a, O&& b ) { a > b; }; + template concept GreatEqualComparable = requires( T&& a, O&& b ) { a >= b; }; + // Functor traits. // template @@ -207,7 +217,7 @@ namespace vtil // Atomicity-related traits. // template - concept Lockable = requires( T & x ) { x.lock(); x.unlock(); }; + concept Lockable = requires( T& x ) { x.lock(); x.unlock(); }; template concept Atomic = is_specialization_v; diff --git a/VTIL-Compiler/analysis/symbolic_analysis.hpp b/VTIL-Compiler/analysis/symbolic_analysis.hpp index 9b0e3f4..a391688 100644 --- a/VTIL-Compiler/analysis/symbolic_analysis.hpp +++ b/VTIL-Compiler/analysis/symbolic_analysis.hpp @@ -144,7 +144,7 @@ namespace vtil::analysis branch_targets.emplace_back( cvt_operand( 0 ) ); is_branch_real = true; is_branch_exiting = ins.base == &ins::vexit; - branch_cc = nullptr; + branch_cc.reset(); return vm_exit_reason::stream_end; } // If unconditional jump: @@ -153,7 +153,7 @@ namespace vtil::analysis { branch_targets.emplace_back( cvt_operand( 0 ) ); is_branch_real = false; - branch_cc = nullptr; + branch_cc.reset(); return vm_exit_reason::stream_end; } // If conditional jump: @@ -351,12 +351,12 @@ namespace vtil::analysis if ( exp_approx == approx ) { if ( pexp->equals( ccexp ) ) - *+pexp = { expected_value, 1 }; + pexp = symbolic::expression{ expected_value, 1 }; } else if ( inv_approx == approx ) { if ( pexp->equals( inv_cc ) ) - *+pexp = { !expected_value, 1 }; + pexp = symbolic::expression{ !expected_value, 1 }; } } }; diff --git a/VTIL-Compiler/common/auxiliaries.cpp b/VTIL-Compiler/common/auxiliaries.cpp index 949401b..06a153f 100644 --- a/VTIL-Compiler/common/auxiliaries.cpp +++ b/VTIL-Compiler/common/auxiliaries.cpp @@ -342,7 +342,7 @@ namespace vtil::optimizer::aux { auto& var = ex->uid.get(); if ( var.is_register() && var.reg() == REG_IMGBASE ) - *+ex = { 0, ex->size() }; + ex = symbolic::expression{ 0, ex->size() }; } }, true, false ).simplify( true ); @@ -393,12 +393,12 @@ namespace vtil::optimizer::aux { if ( exp->is_identical( *cnd_out ) ) { - *+exp = symbolic::expression{ state, exp->size() }; + exp = symbolic::expression{ state, exp->size() }; confirmed |= !state; } else if ( exp->is_identical( ~cnd_out ) ) { - *+exp = symbolic::expression{ state ^ 1, exp->size() }; + exp = symbolic::expression{ state ^ 1, exp->size() }; confirmed |= !state; } } @@ -420,7 +420,7 @@ namespace vtil::optimizer::aux dst->enumerate( explore_cc_space ); if ( cnd_out ) dst.transform( transform_cc ); - if ( !confirmed ) cnd_out = {}; + if ( !confirmed ) cnd_out.reset(); }; symbolic::expression::reference cc = {}; diff --git a/VTIL-Compiler/optimizer/symbolic/preliminary_register_elimination.cpp b/VTIL-Compiler/optimizer/symbolic/preliminary_register_elimination.cpp index 807d8fa..022c1fc 100644 --- a/VTIL-Compiler/optimizer/symbolic/preliminary_register_elimination.cpp +++ b/VTIL-Compiler/optimizer/symbolic/preliminary_register_elimination.cpp @@ -198,7 +198,7 @@ namespace vtil::optimizer if ( !( math::fill( vctx.linear_store[ n ].size(), n ) & read_mask ) ) { math::bit_reset( vctx.bitmap, n ); - vctx.linear_store[ n ] = nullptr; + vctx.linear_store[ n ].reset(); cnt++; } // Otherwise, or with value mask. diff --git a/VTIL-SymEx/directives/directive.hpp b/VTIL-SymEx/directives/directive.hpp index 475f74c..3f3ef4c 100644 --- a/VTIL-SymEx/directives/directive.hpp +++ b/VTIL-SymEx/directives/directive.hpp @@ -178,7 +178,7 @@ namespace vtil::symbolic::directive // and type of expressions it can match. // const char* id = nullptr; - int lookup_index = 0; + uint32_t lookup_index = 0xFFFFFFFF; matching_type mtype = match_any; // Priority hint for transformer. @@ -215,7 +215,7 @@ namespace vtil::symbolic::directive for ( auto [out, idx] : zip( signatures, iindices ) ) out = { make_copy( value ).resize( math::narrow_cast( idx + 1 ) ) }; } - instance( const char* id, int lookup_index, matching_type mtype = match_any ) : + instance( const char* id, uint32_t lookup_index, matching_type mtype = match_any ) : id( id ), lookup_index( lookup_index ), mtype( mtype ), num_nodes( 1 ) {} // Constructor for directive representing the result of an unary operator. @@ -292,9 +292,9 @@ namespace vtil::symbolic::directive // Special variables, one per type: // - static const instance V = { "Π", 7, match_variable }; - static const instance U = { "Σ", 8, match_constant }; - static const instance Q = { "Ω", 9, match_expression }; + static const instance V = { "Π", 7, match_variable }; + static const instance U = { "Σ", 8, match_constant }; + static const instance Q = { "Ω", 9, match_expression }; static const instance W = { "Ψ", 10, match_non_constant }; static const instance X = { "Θ", 11, match_non_expression }; diff --git a/VTIL-SymEx/directives/fast_matcher.hpp b/VTIL-SymEx/directives/fast_matcher.hpp index 94887de..bc7ee51 100644 --- a/VTIL-SymEx/directives/fast_matcher.hpp +++ b/VTIL-SymEx/directives/fast_matcher.hpp @@ -41,7 +41,11 @@ namespace vtil::symbolic::directive // Adds the mapping of a variable to an expression. // bool add( const instance* dir, expression::weak_reference exp ) - { + { + // Assert the looked up type is variable. + // + dassert( dir->op == math::operator_id::invalid && !dir->is_constant() ); + // If it's the first time this variable is being used: // if ( !lookup_table[ dir->lookup_index ] ) @@ -78,7 +82,7 @@ namespace vtil::symbolic::directive { // Assert the looked up type is variable. // - fassert( dir->op == math::operator_id::invalid && !dir->is_constant() ); + dassert( dir->op == math::operator_id::invalid && !dir->is_constant() ); // Translate using the lookup table. // diff --git a/VTIL-SymEx/directives/transformer.cpp b/VTIL-SymEx/directives/transformer.cpp index c8ab48a..d707925 100644 --- a/VTIL-SymEx/directives/transformer.cpp +++ b/VTIL-SymEx/directives/transformer.cpp @@ -195,7 +195,7 @@ namespace vtil::symbolic // Return the unknown mask. // - return ( *+exp = expression{ exp->unknown_mask(), exp->size() }, exp ); + return exp = expression{ exp->unknown_mask(), exp->size() }; } break; } @@ -207,7 +207,7 @@ namespace vtil::symbolic { // Return the unknown mask. // - return ( *+exp = expression{ exp->known_one(), exp->size() }, exp ); + return exp = expression{ exp->known_one(), exp->size() }; } break; } @@ -219,7 +219,7 @@ namespace vtil::symbolic { // Return the unknown mask. // - return ( *+exp = expression{ exp->known_zero(), exp->size() }, exp ); + return exp = expression{ exp->known_zero(), exp->size() }; } break; } diff --git a/VTIL-SymEx/directives/transformer.hpp b/VTIL-SymEx/directives/transformer.hpp index 306aaa2..c958321 100644 --- a/VTIL-SymEx/directives/transformer.hpp +++ b/VTIL-SymEx/directives/transformer.hpp @@ -96,7 +96,7 @@ namespace vtil::symbolic // if ( exp_new->is_constant() ) { - exp_new = { *exp_new->value.get(), exp->size() }; + exp_new = expression{ *exp_new->value.get(), exp->size() }; } else { diff --git a/VTIL-SymEx/expressions/expression.cpp b/VTIL-SymEx/expressions/expression.cpp index d4c8e8b..e486863 100644 --- a/VTIL-SymEx/expressions/expression.cpp +++ b/VTIL-SymEx/expressions/expression.cpp @@ -351,7 +351,7 @@ namespace vtil::symbolic // else { - *+rhs = new_size; + rhs = expression{ new_size, 8 }; return update( false ); } break; @@ -361,7 +361,7 @@ namespace vtil::symbolic case math::operator_id::cast: // Signed cast should not be used to shrink. // - fassert( lhs->size() <= rhs->get().value() ); + dassert( lhs->size() <= rhs->get().value() ); // If sizes match, escape cast operator. // @@ -373,7 +373,7 @@ namespace vtil::symbolic // else if ( signed_cast ) { - *+rhs = new_size; + rhs = expression{ new_size, 8 }; return update( false ); } // Else, convert to unsigned cast since top bits will be zero. @@ -490,7 +490,7 @@ namespace vtil::symbolic // if ( ( is_lazy || auto_simplify ) && value.is_known() ) { - lhs = {}; rhs = {}; + lhs.reset(); rhs.reset(); op = math::operator_id::invalid; is_lazy = false; return update( false ); @@ -531,7 +531,7 @@ namespace vtil::symbolic // if ( ( is_lazy || auto_simplify ) && value.is_known() ) { - lhs = {}; rhs = {}; + lhs.reset(); rhs.reset(); op = math::operator_id::invalid; is_lazy = false; return update( false ); @@ -718,7 +718,7 @@ namespace vtil::symbolic // this way and additionally we avoid copying where an operand is being simplified // as that can be replaced by a simple swap of shared references. // - reference ref = ( reference&& ) make_local_reference( this ); + reference ref = make_local_reference( this ); simplify_expression( ref, prettify ); // Set the simplifier hint to indicate skipping further calls to simplify_expression. @@ -816,8 +816,8 @@ namespace vtil::symbolic // Simplify both expressions. // - expression::reference a = make_local_reference( this ); - expression::reference b = make_local_reference( &other ); + reference a = make_local_reference( this ); + reference b = make_local_reference( &other ); a.simplify(); b.simplify(); diff --git a/VTIL-SymEx/expressions/expression.hpp b/VTIL-SymEx/expressions/expression.hpp index 6f04dab..b57f127 100644 --- a/VTIL-SymEx/expressions/expression.hpp +++ b/VTIL-SymEx/expressions/expression.hpp @@ -44,41 +44,25 @@ // Allow expression::reference to be used with expression type directly as operable. // -namespace vtil::symbolic { struct expression; struct expression_reference; }; +namespace vtil::symbolic { struct expression; struct expression_reference; struct expression_delegate; }; namespace vtil::math { template<> struct resolve_alias { using type = symbolic::expression; }; }; +// Specialize reference. +// +namespace vtil +{ + template<> + struct specialized_shared_reference + { + using type = symbolic::expression_reference; + }; +}; + namespace vtil::symbolic { - struct expression; - - // Expression delegates used to implement copyless write detection - // in case the reference is already owning. - // - struct expression_delegate - { - shared_reference& ref; - bool dirty; - - expression_delegate( shared_reference& ref ) : ref( ref ), dirty( false ) {} - expression_delegate( const expression_delegate& ) = delete; - expression_delegate& operator=( const expression_delegate& ) = delete; - - template, expression_delegate>, int> = 0> - expression_delegate& operator=( T&& value ) - { - ref = std::forward( value ); - dirty = true; - return *this; - } - - const expression* operator->() const { return ref.get(); } - const expression& operator*() const { return *ref.get(); } - expression* operator+() { dirty = 1; return ref.own(); } - }; - // Expression references. // - struct expression_reference : shared_reference + struct expression_reference : base_shared_reference { // Declare hasher and equivalence checker. // @@ -99,21 +83,25 @@ namespace vtil::symbolic // Forward operators and constructor. // - template - expression_reference( Tx&&... args ) - : shared_reference( std::forward( args )...) {} + template requires ( Constructable && sizeof...(Tx) > 0 ) + expression_reference( Tx&&... args ) : base_shared_reference( std::forward( args )... ) {} + constexpr expression_reference() {} + constexpr expression_reference( std::nullptr_t ) {} - using shared_reference::operator bool; - using shared_reference::operator*; - using shared_reference::operator+; - using shared_reference::operator->; + expression_reference( expression_reference&& o ) : base_shared_reference( std::move( o ) ) {} + expression_reference( const expression_reference& o ) : base_shared_reference( o ) {} + expression_reference& operator=( expression_reference&& o ) { base_shared_reference::operator=( std::move( o ) ); return *this; } + expression_reference& operator=( const expression_reference& o ) { base_shared_reference::operator=( o ); return *this; } - // Basic comparison operators are redirected to the pointer type. - // - bool operator<( const shared_reference& o ) const { return combined_value < o.combined_value; } - bool operator==( const shared_reference& o ) const { return combined_value == o.combined_value; } - bool operator<( const expression_reference& o ) const { return combined_value < o.combined_value; } - bool operator==( const expression_reference& o ) const { return combined_value == o.combined_value; } + template requires Constructable + expression_reference& operator=( Tv&& o ) { base_shared_reference::operator=( std::forward( o ) ); return *this; } + + using base_shared_reference::operator bool; + using base_shared_reference::operator*; + using base_shared_reference::operator+; + using base_shared_reference::operator->; + using base_shared_reference::operator<; + using base_shared_reference::operator==; // Implement some helpers to conditionally copy. // @@ -178,6 +166,31 @@ namespace vtil::symbolic } }; + // Expression delegates used to implement copyless write detection + // in case the reference is already owning. + // + struct expression_delegate + { + expression_reference& ref; + bool dirty; + + expression_delegate( expression_reference& ref ) : ref( ref ), dirty( false ) {} + expression_delegate( const expression_delegate& ) = delete; + expression_delegate& operator=( const expression_delegate& ) = delete; + + template, expression_delegate>, int> = 0> + expression_delegate& operator=( T&& value ) + { + ref = std::forward( value ); + dirty = true; + return *this; + } + + const expression* operator->() const { return ref.get(); } + const expression& operator*() const { return *ref.get(); } + expression* operator+() { dirty = 1; return ref.own(); } + }; + // Expression descriptor. // struct expression : math::operable diff --git a/VTIL-SymEx/simplifier/simplifier.cpp b/VTIL-SymEx/simplifier/simplifier.cpp index 444f1f7..a0675af 100644 --- a/VTIL-SymEx/simplifier/simplifier.cpp +++ b/VTIL-SymEx/simplifier/simplifier.cpp @@ -515,7 +515,7 @@ namespace vtil::symbolic // if ( exp->value.is_known() ) { - *+exp = expression{ exp->value.known_one(), exp->value.size() }; + exp = expression{ exp->value.known_one(), exp->value.size() }; #if VTIL_SYMEX_SIMPLIFY_VERBOSE log( "= %s [By evaluation]\n", *exp ); #endif diff --git a/VTIL-SymEx/simplifier/simplifier.hpp b/VTIL-SymEx/simplifier/simplifier.hpp index 08f82eb..5a98471 100644 --- a/VTIL-SymEx/simplifier/simplifier.hpp +++ b/VTIL-SymEx/simplifier/simplifier.hpp @@ -49,7 +49,7 @@ #define VTIL_SYMEX_LRU_CACHE_SIZE 0x18000 #endif #ifndef VTIL_SYMEX_LRU_PRUNE_COEFF - #define VTIL_SYMEX_LRU_PRUNE_COEFF 0.2 + #define VTIL_SYMEX_LRU_PRUNE_COEFF 0.2f #endif #ifndef VTIL_SYMEX_HASH_COLLISION_MAX #define VTIL_SYMEX_HASH_COLLISION_MAX 8