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 101 102 103 104 105
pub fn push(self, val: AbstractValue) -> Self {
CfaState::new(self.stack.push(val))
}
pub fn pop(mut self, n: usize) -> Self {
assert!(n > 0);
let mut stack = self.stack;
for i in 0..n {
stack = stack.pop();
}
CfaState::new(stack)
}
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(2),
JUMP => self.clone().pop(1),
_ => {
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 89)
87 88 89 90 91 92 93 94 95 96 97 98 99
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 117)
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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
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(2).push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop(3).push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop(1).push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop(2).push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop(2).push(UNKNOWN)
}
// 20s: Keccak256
KECCAK256 => {
// NOTE: there is some kind of compiler bug which is
// preventing me from putting this case in the
// expected position.
self.pop(2).push(UNKNOWN)
}
// 30s: Environmental Information
ADDRESS => self.push(UNKNOWN),
BALANCE => self.pop(1).push(UNKNOWN),
ORIGIN => self.push(UNKNOWN),
CALLER => self.push(UNKNOWN),
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop(1).push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
CALLDATACOPY => self.pop(3),
CODESIZE => self.push(UNKNOWN),
CODECOPY => self.pop(3),
GASPRICE => self.push(UNKNOWN),
EXTCODESIZE => self.pop(1).push(UNKNOWN),
EXTCODECOPY => self.pop(4),
RETURNDATASIZE => self.push(UNKNOWN),
RETURNDATACOPY => self.pop(3),
EXTCODEHASH => self.pop(1).push(UNKNOWN),
// 40s: Block Information
BLOCKHASH => self.pop(1).push(UNKNOWN),
COINBASE => self.push(UNKNOWN),
TIMESTAMP => self.push(UNKNOWN),
NUMBER => self.push(UNKNOWN),
DIFFICULTY => self.push(UNKNOWN),
GASLIMIT => self.push(UNKNOWN),
CHAINID => self.push(UNKNOWN),
SELFBALANCE => self.push(UNKNOWN),
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(1),
MLOAD => self.pop(1).push(UNKNOWN),
MSTORE|MSTORE8 => self.pop(2),
SLOAD => self.pop(1).push(UNKNOWN),
SSTORE => self.pop(2),
JUMPI => self.pop(2),
PC|MSIZE|GAS => self.push(UNKNOWN),
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: Exchange 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)
}
// a0s: Logging Operations
LOG(n) => {
self.pop((n+2) as usize)
}
// f0s: System Operations
CREATE => self.pop(3).push(UNKNOWN),
CALL|CALLCODE => self.pop(7).push(UNKNOWN),
DELEGATECALL|STATICCALL => self.pop(6).push(UNKNOWN),
CREATE2 => self.pop(4).push(UNKNOWN),
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
SELFDESTRUCT => self.pop(1),
_ => {
// This is a catch all to ensure no instructions are
// missed above.
panic!("unknown instruction ({:?})",insn);
}
}
}
sourcepub fn pop(self, n: usize) -> Self
pub fn pop(self, n: usize) -> Self
Examples found in repository?
src/cfa.rs (line 75)
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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
fn branch(&self, _pc: usize, insn: &Instruction) -> Self {
match insn {
JUMPI => self.clone().pop(2),
JUMP => self.clone().pop(1),
_ => {
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(2).push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop(3).push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop(1).push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop(2).push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop(2).push(UNKNOWN)
}
// 20s: Keccak256
KECCAK256 => {
// NOTE: there is some kind of compiler bug which is
// preventing me from putting this case in the
// expected position.
self.pop(2).push(UNKNOWN)
}
// 30s: Environmental Information
ADDRESS => self.push(UNKNOWN),
BALANCE => self.pop(1).push(UNKNOWN),
ORIGIN => self.push(UNKNOWN),
CALLER => self.push(UNKNOWN),
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop(1).push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
CALLDATACOPY => self.pop(3),
CODESIZE => self.push(UNKNOWN),
CODECOPY => self.pop(3),
GASPRICE => self.push(UNKNOWN),
EXTCODESIZE => self.pop(1).push(UNKNOWN),
EXTCODECOPY => self.pop(4),
RETURNDATASIZE => self.push(UNKNOWN),
RETURNDATACOPY => self.pop(3),
EXTCODEHASH => self.pop(1).push(UNKNOWN),
// 40s: Block Information
BLOCKHASH => self.pop(1).push(UNKNOWN),
COINBASE => self.push(UNKNOWN),
TIMESTAMP => self.push(UNKNOWN),
NUMBER => self.push(UNKNOWN),
DIFFICULTY => self.push(UNKNOWN),
GASLIMIT => self.push(UNKNOWN),
CHAINID => self.push(UNKNOWN),
SELFBALANCE => self.push(UNKNOWN),
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(1),
MLOAD => self.pop(1).push(UNKNOWN),
MSTORE|MSTORE8 => self.pop(2),
SLOAD => self.pop(1).push(UNKNOWN),
SSTORE => self.pop(2),
JUMPI => self.pop(2),
PC|MSIZE|GAS => self.push(UNKNOWN),
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: Exchange 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)
}
// a0s: Logging Operations
LOG(n) => {
self.pop((n+2) as usize)
}
// f0s: System Operations
CREATE => self.pop(3).push(UNKNOWN),
CALL|CALLCODE => self.pop(7).push(UNKNOWN),
DELEGATECALL|STATICCALL => self.pop(6).push(UNKNOWN),
CREATE2 => self.pop(4).push(UNKNOWN),
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
SELFDESTRUCT => self.pop(1),
_ => {
// 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 196)
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 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
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(2).push(UNKNOWN)
}
ADDMOD|MULMOD => {
self.pop(3).push(UNKNOWN)
}
// 0s: Stop and Arithmetic Operations
ISZERO|NOT => {
self.pop(1).push(UNKNOWN)
}
// Binary Comparators
LT|GT|SLT|SGT|EQ => {
self.pop(2).push(UNKNOWN)
}
// Binary bitwise operators
AND|OR|XOR|BYTE|SHL|SHR|SAR => {
self.pop(2).push(UNKNOWN)
}
// 20s: Keccak256
KECCAK256 => {
// NOTE: there is some kind of compiler bug which is
// preventing me from putting this case in the
// expected position.
self.pop(2).push(UNKNOWN)
}
// 30s: Environmental Information
ADDRESS => self.push(UNKNOWN),
BALANCE => self.pop(1).push(UNKNOWN),
ORIGIN => self.push(UNKNOWN),
CALLER => self.push(UNKNOWN),
CALLVALUE => self.push(UNKNOWN),
CALLDATALOAD => self.pop(1).push(UNKNOWN),
CALLDATASIZE => self.push(UNKNOWN),
CALLDATACOPY => self.pop(3),
CODESIZE => self.push(UNKNOWN),
CODECOPY => self.pop(3),
GASPRICE => self.push(UNKNOWN),
EXTCODESIZE => self.pop(1).push(UNKNOWN),
EXTCODECOPY => self.pop(4),
RETURNDATASIZE => self.push(UNKNOWN),
RETURNDATACOPY => self.pop(3),
EXTCODEHASH => self.pop(1).push(UNKNOWN),
// 40s: Block Information
BLOCKHASH => self.pop(1).push(UNKNOWN),
COINBASE => self.push(UNKNOWN),
TIMESTAMP => self.push(UNKNOWN),
NUMBER => self.push(UNKNOWN),
DIFFICULTY => self.push(UNKNOWN),
GASLIMIT => self.push(UNKNOWN),
CHAINID => self.push(UNKNOWN),
SELFBALANCE => self.push(UNKNOWN),
// 50s: Stack, Memory, Storage and Flow Operations
POP => self.pop(1),
MLOAD => self.pop(1).push(UNKNOWN),
MSTORE|MSTORE8 => self.pop(2),
SLOAD => self.pop(1).push(UNKNOWN),
SSTORE => self.pop(2),
JUMPI => self.pop(2),
PC|MSIZE|GAS => self.push(UNKNOWN),
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: Exchange 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)
}
// a0s: Logging Operations
LOG(n) => {
self.pop((n+2) as usize)
}
// f0s: System Operations
CREATE => self.pop(3).push(UNKNOWN),
CALL|CALLCODE => self.pop(7).push(UNKNOWN),
DELEGATECALL|STATICCALL => self.pop(6).push(UNKNOWN),
CREATE2 => self.pop(4).push(UNKNOWN),
INVALID|JUMP|RETURN|REVERT => {
CfaState::bottom()
}
SELFDESTRUCT => self.pop(1),
_ => {
// 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.
source§fn peek(&self, n: usize) -> AbstractValue
fn peek(&self, n: usize) -> AbstractValue
Determine value on top of stack