44
55import re
66import copy
7- from typing import Union , Optional , Dict , List
7+ from typing import Union , Optional , Dict , Tuple
88
99
1010class ExpressionException (SmtlibError ):
@@ -15,10 +15,59 @@ class ExpressionException(SmtlibError):
1515 pass
1616
1717
18- class Expression :
18+ class XSlotted (type ):
19+ """
20+ Metaclass that will propagate slots on multi-inheritance classes
21+ Every class should define __xslots__ (instead of __slots__)
22+
23+ class Base(object, metaclass=XSlotted, abstract=True):
24+ pass
25+
26+ class A(Base, abstract=True):
27+ __xslots__ = ('a',)
28+ pass
29+
30+ class B(Base, abstract=True):
31+ __xslots__ = ('b',)
32+ pass
33+
34+ class C(A, B):
35+ pass
36+
37+ # Normal case / baseline
38+ class X(object):
39+ __slots__ = ('a', 'b')
40+
41+ c = C()
42+ c.a = 1
43+ c.b = 2
44+
45+ x = X()
46+ x.a = 1
47+ x.b = 2
48+
49+ import sys
50+ print (sys.getsizeof(c),sys.getsizeof(x)) #same value
51+ """
52+
53+ def __new__ (cls , clsname , bases , attrs , abstract = False ):
54+ xslots = frozenset (attrs .get ("__xslots__" , ()))
55+ # merge the xslots of all the bases with the one defined here
56+ for base in bases :
57+ xslots = xslots .union (getattr (base , "__xslots__" , ()))
58+ attrs ["__xslots__" ] = tuple (xslots )
59+ if abstract :
60+ attrs ["__slots__" ] = tuple ()
61+ else :
62+ attrs ["__slots__" ] = attrs ["__xslots__" ]
63+ attrs ["__hash__" ] = object .__hash__
64+ return super ().__new__ (cls , clsname , bases , attrs )
65+
66+
67+ class Expression (object , metaclass = XSlotted , abstract = True ):
1968 """ Abstract taintable Expression. """
2069
21- __slots__ = [ "_taint" ]
70+ __xslots__ : Tuple [ str , ...] = ( "_taint" ,)
2271
2372 def __init__ (self , taint : Union [tuple , frozenset ] = ()):
2473 if self .__class__ is Expression :
@@ -114,8 +163,8 @@ def taint_with(arg, *taints, value_bits=256, index_bits=256):
114163
115164###############################################################################
116165# Booleans
117- class Bool (Expression ):
118- __slots__ : List [ str ] = []
166+ class Bool (Expression , abstract = True ):
167+ """Bool expressions represent symbolic value of truth"""
119168
120169 def __init__ (self , * operands , ** kwargs ):
121170 super ().__init__ (* operands , ** kwargs )
@@ -169,7 +218,7 @@ def __bool__(self):
169218
170219
171220class BoolVariable (Bool ):
172- __slots__ = [ "_name" ]
221+ __xslots__ : Tuple [ str , ...] = ( "_name" ,)
173222
174223 def __init__ (self , name : str , * args , ** kwargs ):
175224 assert " " not in name
@@ -195,11 +244,11 @@ def declaration(self):
195244
196245
197246class BoolConstant (Bool ):
198- __slots__ = [ "_value" ]
247+ __xslots__ : Tuple [ str , ...] = ( "_value" ,)
199248
200249 def __init__ (self , value : bool , * args , ** kwargs ):
201- self ._value = value
202250 super ().__init__ (* args , ** kwargs )
251+ self ._value = value
203252
204253 def __bool__ (self ):
205254 return self .value
@@ -209,8 +258,10 @@ def value(self):
209258 return self ._value
210259
211260
212- class BoolOperation (Bool ):
213- __slots__ = ["_operands" ]
261+ class BoolOperation (Bool , abstract = True ):
262+ """ An operation that results in a Bool """
263+
264+ __xslots__ : Tuple [str , ...] = ("_operands" ,)
214265
215266 def __init__ (self , * operands , ** kwargs ):
216267 self ._operands = operands
@@ -250,10 +301,10 @@ def __init__(self, cond: "Bool", true: "Bool", false: "Bool", **kwargs):
250301 super ().__init__ (cond , true , false , ** kwargs )
251302
252303
253- class BitVec (Expression ):
254- """ This adds a bitsize to the Expression class """
304+ class BitVec (Expression , abstract = True ):
305+ """ BitVector expressions have a fixed bit size """
255306
256- __slots__ = [ "size" ]
307+ __xslots__ : Tuple [ str , ...] = ( "size" ,)
257308
258309 def __init__ (self , size , * operands , ** kwargs ):
259310 super ().__init__ (* operands , ** kwargs )
@@ -456,7 +507,7 @@ def Bool(self):
456507
457508
458509class BitVecVariable (BitVec ):
459- __slots__ = [ "_name" ]
510+ __xslots__ : Tuple [ str , ...] = ( "_name" ,)
460511
461512 def __init__ (self , size : int , name : str , * args , ** kwargs ):
462513 assert " " not in name
@@ -482,7 +533,7 @@ def declaration(self):
482533
483534
484535class BitVecConstant (BitVec ):
485- __slots__ = [ "_value" ]
536+ __xslots__ : Tuple [ str , ...] = ( "_value" ,)
486537
487538 def __init__ (self , size : int , value : int , * args , ** kwargs ):
488539 MASK = (1 << size ) - 1
@@ -512,8 +563,10 @@ def signed_value(self):
512563 return self ._value
513564
514565
515- class BitVecOperation (BitVec ):
516- __slots__ = ["_operands" ]
566+ class BitVecOperation (BitVec , abstract = True ):
567+ """ An operation that results in a BitVec """
568+
569+ __xslots__ : Tuple [str , ...] = ("_operands" ,)
517570
518571 def __init__ (self , size , * operands , ** kwargs ):
519572 self ._operands = operands
@@ -670,8 +723,15 @@ def __init__(self, a, b, *args, **kwargs):
670723
671724###############################################################################
672725# Array BV32 -> BV8 or BV64 -> BV8
673- class Array (Expression ):
674- __slots__ = ["_index_bits" , "_index_max" , "_value_bits" ]
726+ class Array (Expression , abstract = True ):
727+ """An Array expression is an unmutable mapping from bitvector to bitvector
728+
729+ array.index_bits is the number of bits used for addressing a value
730+ array.value_bits is the number of bits used in the values
731+ array.index_max counts the valid indexes starting at 0. Accessing outside the bound is undefined
732+ """
733+
734+ __xslots__ : Tuple [str , ...] = ("_index_bits" , "_index_max" , "_value_bits" )
675735
676736 def __init__ (
677737 self , index_bits : int , index_max : Optional [int ], value_bits : int , * operands , ** kwargs
@@ -764,7 +824,7 @@ def store(self, index, value):
764824
765825 def write (self , offset , buf ):
766826 if not isinstance (buf , (Array , bytearray )):
767- raise TypeError ("Array or bytearray expected got {:s}" . format ( type (buf )) )
827+ raise TypeError (f "Array or bytearray expected got { type (buf )} " )
768828 arr = self
769829 for i , val in enumerate (buf ):
770830 arr = arr .store (offset + i , val )
@@ -820,18 +880,18 @@ def read_BE(self, address, size):
820880 bytes = []
821881 for offset in range (size ):
822882 bytes .append (self .get (address + offset , 0 ))
823- return BitVecConcat (size * self .value_bits , * bytes )
883+ return BitVecConcat (size * self .value_bits , tuple ( bytes ) )
824884
825885 def read_LE (self , address , size ):
826886 address = self .cast_index (address )
827887 bytes = []
828888 for offset in range (size ):
829889 bytes .append (self .get (address + offset , 0 ))
830- return BitVecConcat (size * self .value_bits , * reversed (bytes ))
890+ return BitVecConcat (size * self .value_bits , tuple ( reversed (bytes ) ))
831891
832892 def write_BE (self , address , value , size ):
833893 address = self .cast_index (address )
834- value = BitVec (size * self .value_bits ).cast (value )
894+ value = BitVecConstant (size * self .value_bits , value = 0 ).cast (value )
835895 array = self
836896 for offset in range (size ):
837897 array = array .store (
@@ -842,7 +902,7 @@ def write_BE(self, address, value, size):
842902
843903 def write_LE (self , address , value , size ):
844904 address = self .cast_index (address )
845- value = BitVec (size * self .value_bits ).cast (value )
905+ value = BitVecConstant (size * self .value_bits , value = 0 ).cast (value )
846906 array = self
847907 for offset in reversed (range (size )):
848908 array = array .store (
@@ -903,7 +963,7 @@ def __radd__(self, other):
903963
904964
905965class ArrayVariable (Array ):
906- __slots__ = [ "_name" ]
966+ __xslots__ : Tuple [ str , ...] = ( "_name" ,)
907967
908968 def __init__ (self , index_bits , index_max , value_bits , name , * args , ** kwargs ):
909969 assert " " not in name
@@ -929,7 +989,9 @@ def declaration(self):
929989
930990
931991class ArrayOperation (Array ):
932- __slots__ = ["_operands" ]
992+ """An operation that result in an Array"""
993+
994+ __xslots__ : Tuple [str , ...] = ("_operands" ,)
933995
934996 def __init__ (self , array : Array , * operands , ** kwargs ):
935997 self ._operands = (array , * operands )
@@ -989,6 +1051,8 @@ def __setstate__(self, state):
9891051
9901052
9911053class ArraySlice (ArrayOperation ):
1054+ __xslots__ : Tuple [str , ...] = ("_slice_offset" , "_slice_size" )
1055+
9921056 def __init__ (
9931057 self , array : Union ["Array" , "ArrayProxy" ], offset : int , size : int , * args , ** kwargs
9941058 ):
@@ -1033,6 +1097,15 @@ def store(self, index, value):
10331097
10341098
10351099class ArrayProxy (Array ):
1100+ __xslots__ : Tuple [str , ...] = (
1101+ "constraints" ,
1102+ "_default" ,
1103+ "_concrete_cache" ,
1104+ "_written" ,
1105+ "_array" ,
1106+ "_name" ,
1107+ )
1108+
10361109 def __init__ (self , array : Array , default : Optional [int ] = None ):
10371110 self ._default = default
10381111 self ._concrete_cache : Dict [int , int ] = {}
@@ -1229,7 +1302,7 @@ def get(self, index, default=None):
12291302
12301303
12311304class ArraySelect (BitVec ):
1232- __slots__ = [ "_operands" ]
1305+ __xslots__ : Tuple [ str , ...] = ( "_operands" ,)
12331306
12341307 def __init__ (self , array : "Array" , index : "BitVec" , * operands , ** kwargs ):
12351308 assert index .size == array .index_bits
@@ -1257,20 +1330,26 @@ def __repr__(self):
12571330
12581331
12591332class BitVecSignExtend (BitVecOperation ):
1333+ __xslots__ : Tuple [str , ...] = ("extend" ,)
1334+
12601335 def __init__ (self , operand : "BitVec" , size_dest : int , * args , ** kwargs ):
12611336 assert size_dest >= operand .size
12621337 super ().__init__ (size_dest , operand , * args , ** kwargs )
12631338 self .extend = size_dest - operand .size
12641339
12651340
12661341class BitVecZeroExtend (BitVecOperation ):
1342+ __xslots__ : Tuple [str , ...] = ("extend" ,)
1343+
12671344 def __init__ (self , size_dest : int , operand : "BitVec" , * args , ** kwargs ):
12681345 assert size_dest >= operand .size
12691346 super ().__init__ (size_dest , operand , * args , ** kwargs )
12701347 self .extend = size_dest - operand .size
12711348
12721349
12731350class BitVecExtract (BitVecOperation ):
1351+ __xslots__ : Tuple [str , ...] = ("_begining" , "_end" )
1352+
12741353 def __init__ (self , operand : "BitVec" , offset : int , size : int , * args , ** kwargs ):
12751354 assert offset >= 0 and offset + size <= operand .size
12761355 super ().__init__ (size , operand , * args , ** kwargs )
@@ -1291,7 +1370,7 @@ def end(self):
12911370
12921371
12931372class BitVecConcat (BitVecOperation ):
1294- def __init__ (self , size_dest : int , * operands , ** kwargs ):
1373+ def __init__ (self , size_dest : int , operands : Tuple , ** kwargs ):
12951374 assert all (isinstance (x , BitVec ) for x in operands )
12961375 assert size_dest == sum (x .size for x in operands )
12971376 super ().__init__ (size_dest , * operands , ** kwargs )
0 commit comments