pub struct CfaState { /* private fields */ }
Implementations§
source§impl CfaState
impl CfaState
sourcepub fn new(stack: AbstractStack) -> Self
pub fn new(stack: AbstractStack) -> Self
Examples found in repository?
src/cfa.rs (line 43)
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
pub fn push(self, val: AbstractValue) -> Self {
CfaState::new(self.stack.push(val))
}
pub fn pop(self) -> Self {
CfaState::new(self.stack.pop())
}
pub fn set(self, n:usize, val: AbstractValue) -> Self {
CfaState::new(self.stack.set(n,val))
}
}
impl Clone for CfaState {
fn clone(&self) -> Self {
CfaState::new(self.stack.clone())
}
}
impl fmt::Display for CfaState {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f,"{}",self.stack)
}
}
impl AbstractState for CfaState {
fn is_reachable(&self) -> bool { !self.stack.is_bottom() }
fn branch(&self, _pc: usize, insn: &Instruction) -> Self {
match insn {
JUMPI => self.clone().pop().pop(),
JUMP => self.clone().pop(),
_ => {
unreachable!()
}
}
}
fn peek(&self, n: usize) -> AbstractValue {
self.stack.peek(n)
}
fn merge(&mut self, other: Self) -> bool {
if *self != other {
if !other.is_bottom() {
if self.is_bottom() {
*self = other;
return true;
} else {
return self.stack.merge_into(&other.stack);
}
}
}
false
}
fn bottom() -> Self { CfaState::new(BOTTOM_STACK) }
fn origin() -> Self {
CfaState::new(EMPTY_STACK)
}
sourcepub fn is_bottom(&self) -> bool
pub fn is_bottom(&self) -> bool
Examples found in repository?
src/cfa.rs (line 84)
82 83 84 85 86 87 88 89 90 91 92 93 94
fn merge(&mut self, other: Self) -> bool {
if *self != other {
if !other.is_bottom() {
if self.is_bottom() {
*self = other;
return true;
} else {
return self.stack.merge_into(&other.stack);
}
}
}
false
}
pub fn len(&self) -> Interval
sourcepub fn push(self, val: AbstractValue) -> Self
pub fn push(self, val: AbstractValue) -> Self
Examples found in repository?
src/cfa.rs (line 112)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
fn transfer(self, insn: &Instruction) -> CfaState {
match insn {
STOP => CfaState::bottom(),
// 0s: Stop and Arithmetic Operations
ADD|MUL|SUB|DIV|SDIV|MOD|SMOD|EXP|SIGNEXTEND => {
self.pop().pop().push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop().pop().pop().push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop().push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop().pop().push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop().pop().push(UNKNOWN)
}
// 20s: Keccak256
// 30s: Environmental Information
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop().push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
// 40s: Block Information
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(),
MLOAD => self.pop().push(UNKNOWN),
MSTORE => self.pop().pop(),
SLOAD => self.pop().push(UNKNOWN),
SSTORE => self.pop().pop(),
JUMPI => self.pop().pop(),
JUMPDEST(_) => self, // nop
// 60 & 70s: Push Operations
PUSH(bytes) => {
let n = util::from_be_bytes(&bytes);
if n <= MAX_CODE_SIZE {
self.push(AbstractValue::Known(n as usize))
} else {
self.push(UNKNOWN)
}
}
// 80s: Duplicate Operations
DUP(n) => {
let m = (*n - 1) as usize;
let nth = self.peek(m);
self.push(nth)
}
// 90s: Swap Operations
SWAP(n) => {
let m = (*n - 1) as usize;
let x = self.peek(m);
let y = self.peek(0);
self.set(0,x).set(m,y)
}
// 90s: Exchange Operations
// a0s: Logging Operations
// f0s: System Operations
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
_ => {
// This is a catch all to ensure no instructions are
// missed above.
panic!("unknown instruction ({:?})",insn);
}
}
}
sourcepub fn pop(self) -> Self
pub fn pop(self) -> Self
Examples found in repository?
src/cfa.rs (line 70)
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
fn branch(&self, _pc: usize, insn: &Instruction) -> Self {
match insn {
JUMPI => self.clone().pop().pop(),
JUMP => self.clone().pop(),
_ => {
unreachable!()
}
}
}
fn peek(&self, n: usize) -> AbstractValue {
self.stack.peek(n)
}
fn merge(&mut self, other: Self) -> bool {
if *self != other {
if !other.is_bottom() {
if self.is_bottom() {
*self = other;
return true;
} else {
return self.stack.merge_into(&other.stack);
}
}
}
false
}
fn bottom() -> Self { CfaState::new(BOTTOM_STACK) }
fn origin() -> Self {
CfaState::new(EMPTY_STACK)
}
// ============================================================================
// Abstract Instruction Semantics (stack)
// ============================================================================
/// Update an abstract state with the effects of a given instruction.
fn transfer(self, insn: &Instruction) -> CfaState {
match insn {
STOP => CfaState::bottom(),
// 0s: Stop and Arithmetic Operations
ADD|MUL|SUB|DIV|SDIV|MOD|SMOD|EXP|SIGNEXTEND => {
self.pop().pop().push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop().pop().pop().push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop().push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop().pop().push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop().pop().push(UNKNOWN)
}
// 20s: Keccak256
// 30s: Environmental Information
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop().push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
// 40s: Block Information
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(),
MLOAD => self.pop().push(UNKNOWN),
MSTORE => self.pop().pop(),
SLOAD => self.pop().push(UNKNOWN),
SSTORE => self.pop().pop(),
JUMPI => self.pop().pop(),
JUMPDEST(_) => self, // nop
// 60 & 70s: Push Operations
PUSH(bytes) => {
let n = util::from_be_bytes(&bytes);
if n <= MAX_CODE_SIZE {
self.push(AbstractValue::Known(n as usize))
} else {
self.push(UNKNOWN)
}
}
// 80s: Duplicate Operations
DUP(n) => {
let m = (*n - 1) as usize;
let nth = self.peek(m);
self.push(nth)
}
// 90s: Swap Operations
SWAP(n) => {
let m = (*n - 1) as usize;
let x = self.peek(m);
let y = self.peek(0);
self.set(0,x).set(m,y)
}
// 90s: Exchange Operations
// a0s: Logging Operations
// f0s: System Operations
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
_ => {
// This is a catch all to ensure no instructions are
// missed above.
panic!("unknown instruction ({:?})",insn);
}
}
}
sourcepub fn set(self, n: usize, val: AbstractValue) -> Self
pub fn set(self, n: usize, val: AbstractValue) -> Self
Examples found in repository?
src/cfa.rs (line 163)
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
fn transfer(self, insn: &Instruction) -> CfaState {
match insn {
STOP => CfaState::bottom(),
// 0s: Stop and Arithmetic Operations
ADD|MUL|SUB|DIV|SDIV|MOD|SMOD|EXP|SIGNEXTEND => {
self.pop().pop().push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop().pop().pop().push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop().push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop().pop().push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop().pop().push(UNKNOWN)
}
// 20s: Keccak256
// 30s: Environmental Information
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop().push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
// 40s: Block Information
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(),
MLOAD => self.pop().push(UNKNOWN),
MSTORE => self.pop().pop(),
SLOAD => self.pop().push(UNKNOWN),
SSTORE => self.pop().pop(),
JUMPI => self.pop().pop(),
JUMPDEST(_) => self, // nop
// 60 & 70s: Push Operations
PUSH(bytes) => {
let n = util::from_be_bytes(&bytes);
if n <= MAX_CODE_SIZE {
self.push(AbstractValue::Known(n as usize))
} else {
self.push(UNKNOWN)
}
}
// 80s: Duplicate Operations
DUP(n) => {
let m = (*n - 1) as usize;
let nth = self.peek(m);
self.push(nth)
}
// 90s: Swap Operations
SWAP(n) => {
let m = (*n - 1) as usize;
let x = self.peek(m);
let y = self.peek(0);
self.set(0,x).set(m,y)
}
// 90s: Exchange Operations
// a0s: Logging Operations
// f0s: System Operations
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
_ => {
// This is a catch all to ensure no instructions are
// missed above.
panic!("unknown instruction ({:?})",insn);
}
}
}
Trait Implementations§
source§impl AbstractState for CfaState
impl AbstractState for CfaState
source§fn transfer(self, insn: &Instruction) -> CfaState
fn transfer(self, insn: &Instruction) -> CfaState
Update an abstract state with the effects of a given instruction.
source§fn is_reachable(&self) -> bool
fn is_reachable(&self) -> bool
Determines whether a given block is considered reachable or
not.
source§fn branch(&self, _pc: usize, insn: &Instruction) -> Self
fn branch(&self, _pc: usize, insn: &Instruction) -> Self
Apply a given branch to this stage, yielding an updated state
at the point of the branch.