Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
cwe_checker
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fact-depend
cwe_checker
Commits
decc1254
Unverified
Commit
decc1254
authored
Feb 08, 2023
by
van den Bosch
Committed by
GitHub
Feb 08, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Test refactoring collection (#386)
parent
dcbdac1e
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
39 changed files
with
603 additions
and
1274 deletions
+603
-1274
mod.rs
...we_checker_lib/src/analysis/expression_propagation/mod.rs
+124
-3
tests.rs
..._checker_lib/src/analysis/expression_propagation/tests.rs
+26
-0
forward_interprocedural_fixpoint.rs
...cker_lib/src/analysis/forward_interprocedural_fixpoint.rs
+2
-1
global_var_propagation.rs
...src/analysis/function_signature/global_var_propagation.rs
+2
-2
graph.rs
src/cwe_checker_lib/src/analysis/graph.rs
+5
-3
tests.rs
...ecker_lib/src/analysis/pointer_inference/context/tests.rs
+0
-0
tests.rs
...hecker_lib/src/analysis/pointer_inference/object/tests.rs
+2
-2
tests.rs
...r_lib/src/analysis/pointer_inference/object_list/tests.rs
+3
-2
mod.rs
...ker_lib/src/analysis/pointer_inference/state/tests/mod.rs
+3
-3
specialized_expressions.rs
.../pointer_inference/state/tests/specialized_expressions.rs
+2
-2
tests.rs
...er_lib/src/analysis/stack_alignment_substitution/tests.rs
+2
-6
memcpy.rs
...nalysis/string_abstraction/context/symbol_calls/memcpy.rs
+13
-12
scanf.rs
...analysis/string_abstraction/context/symbol_calls/scanf.rs
+13
-13
tests.rs
.../string_abstraction/context/symbol_calls/sprintf/tests.rs
+34
-46
strcat.rs
...nalysis/string_abstraction/context/symbol_calls/strcat.rs
+3
-4
tests.rs
...analysis/string_abstraction/context/symbol_calls/tests.rs
+9
-9
tests.rs
.../analysis/string_abstraction/context/trait_impls/tests.rs
+2
-2
tests.rs
...hecker_lib/src/analysis/string_abstraction/state/tests.rs
+30
-27
tests.rs
src/cwe_checker_lib/src/analysis/string_abstraction/tests.rs
+11
-55
state.rs
src/cwe_checker_lib/src/checkers/cwe_119/state.rs
+3
-3
blk.rs
src/cwe_checker_lib/src/intermediate_representation/blk.rs
+1
-227
def.rs
src/cwe_checker_lib/src/intermediate_representation/def.rs
+7
-38
builder.rs
...lib/src/intermediate_representation/expression/builder.rs
+0
-88
tests.rs
...r_lib/src/intermediate_representation/expression/tests.rs
+27
-37
jmp.rs
src/cwe_checker_lib/src/intermediate_representation/jmp.rs
+0
-20
mod.rs
...checker_lib/src/intermediate_representation/macros/mod.rs
+1
-1
mod.rs
src/cwe_checker_lib/src/intermediate_representation/mod.rs
+0
-44
program.rs
...we_checker_lib/src/intermediate_representation/program.rs
+0
-72
project.rs
...we_checker_lib/src/intermediate_representation/project.rs
+0
-69
propagate_control_flow.rs
...rmediate_representation/project/propagate_control_flow.rs
+4
-9
runtime_memory_image.rs
...b/src/intermediate_representation/runtime_memory_image.rs
+10
-87
sub.rs
src/cwe_checker_lib/src/intermediate_representation/sub.rs
+0
-229
term.rs
src/cwe_checker_lib/src/intermediate_representation/term.rs
+2
-1
builder.rs
...ecker_lib/src/intermediate_representation/term/builder.rs
+0
-60
builder_high_lvl.rs
.../src/intermediate_representation/term/builder_high_lvl.rs
+230
-0
builder_low_lvl.rs
...b/src/intermediate_representation/term/builder_low_lvl.rs
+0
-0
variable.rs
...e_checker_lib/src/intermediate_representation/variable.rs
+0
-15
tests.rs
...e_checker_lib/src/pcode/subregister_substitution/tests.rs
+16
-41
tests.rs
src/cwe_checker_lib/src/utils/arguments/tests.rs
+16
-41
No files found.
src/cwe_checker_lib/src/analysis/expression_propagation/mod.rs
View file @
decc1254
...
...
@@ -186,12 +186,12 @@ fn extract_results<'a>(
///
/// This uses the expression propagation of basic blocks, thus performs intra-basic-block insertion of expressions.
fn
insert_expressions
(
inser
a
tables
:
HashMap
<
Tid
,
HashMap
<
Variable
,
Expression
>>
,
insertables
:
HashMap
<
Tid
,
HashMap
<
Variable
,
Expression
>>
,
program
:
&
mut
Program
,
)
{
for
sub
in
program
.subs
.values_mut
()
{
for
block
in
sub
.term.blocks
.iter_mut
()
{
block
.propagate_input_expressions
(
insera
tables
.get
(
&
block
.tid
)
.cloned
());
propagate_input_expressions
(
block
,
inser
tables
.get
(
&
block
.tid
)
.cloned
());
}
}
}
...
...
@@ -200,11 +200,132 @@ fn insert_expressions(
fn
merge_same_var_assignments
(
project
:
&
mut
Project
)
{
for
sub
in
project
.program.term.subs
.values_mut
()
{
for
blk
in
sub
.term.blocks
.iter_mut
()
{
blk
.merge_def_assignments_to_same_var
(
);
merge_def_assignments_to_same_var
(
blk
);
}
}
}
/// Wherever possible, substitute input variables of expressions
/// with the input expression that defines the input variable.
///
/// Note that substitution is only possible
/// if the input variables of the input expression itself did not change since the definition of said variable.
///
/// The expression propagation allows more dead stores to be removed during
/// [dead variable elimination](crate::analysis::dead_variable_elimination).
pub
fn
propagate_input_expressions
(
blk
:
&
mut
Term
<
Blk
>
,
apriori_insertable_expressions
:
Option
<
HashMap
<
Variable
,
Expression
>>
,
)
{
let
mut
insertable_expressions
=
HashMap
::
new
();
if
let
Some
(
insertables
)
=
apriori_insertable_expressions
{
insertable_expressions
=
insertables
;
}
for
def
in
blk
.term.defs
.iter_mut
()
{
match
&
mut
def
.term
{
Def
::
Assign
{
var
,
value
:
expression
,
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expression
.substitute_input_var
(
input_var
,
input_expr
);
}
// expressions dependent on the assigned variable are no longer insertable
insertable_expressions
.retain
(|
input_var
,
input_expr
|
{
input_var
!=
var
&&
!
input_expr
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
});
// If the value of the assigned variable does not depend on the former value of the variable,
// then it is insertable for future expressions.
if
!
expression
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
{
insertable_expressions
.insert
(
var
.clone
(),
expression
.clone
());
}
}
Def
::
Load
{
var
,
address
:
expression
,
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expression
.substitute_input_var
(
input_var
,
input_expr
);
}
// expressions dependent on the assigned variable are no longer insertable
insertable_expressions
.retain
(|
input_var
,
input_expr
|
{
input_var
!=
var
&&
!
input_expr
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
});
}
Def
::
Store
{
address
,
value
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
address
.substitute_input_var
(
input_var
,
input_expr
);
value
.substitute_input_var
(
input_var
,
input_expr
);
}
}
}
}
for
jump
in
blk
.term.jmps
.iter_mut
()
{
match
&
mut
jump
.term
{
Jmp
::
Branch
(
_
)
|
Jmp
::
Call
{
..
}
|
Jmp
::
CallOther
{
..
}
=>
(),
Jmp
::
BranchInd
(
expr
)
|
Jmp
::
CBranch
{
condition
:
expr
,
..
}
|
Jmp
::
CallInd
{
target
:
expr
,
..
}
|
Jmp
::
Return
(
expr
)
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expr
.substitute_input_var
(
input_var
,
input_expr
);
}
}
}
}
}
/// Merge subsequent assignments to the same variable to a single assignment to that variable.
pub
fn
merge_def_assignments_to_same_var
(
blk
:
&
mut
Term
<
Blk
>
)
{
let
mut
new_defs
=
Vec
::
new
();
let
mut
last_def_opt
=
None
;
for
def
in
blk
.term.defs
.iter
()
{
if
let
Def
::
Assign
{
var
:
current_var
,
..
}
=
&
def
.term
{
if
let
Some
(
Term
{
term
:
Def
::
Assign
{
var
:
last_var
,
value
:
last_value
,
},
..
})
=
&
last_def_opt
{
if
current_var
==
last_var
{
let
mut
substituted_def
=
def
.clone
();
substituted_def
.substitute_input_var
(
last_var
,
last_value
);
last_def_opt
=
Some
(
substituted_def
);
}
else
{
new_defs
.push
(
last_def_opt
.unwrap
());
last_def_opt
=
Some
(
def
.clone
());
}
}
else
if
last_def_opt
.is_some
()
{
panic!
();
// Only assign-defs should be saved in last_def.
}
else
{
last_def_opt
=
Some
(
def
.clone
());
}
}
else
{
if
let
Some
(
last_def
)
=
last_def_opt
{
new_defs
.push
(
last_def
);
}
new_defs
.push
(
def
.clone
());
last_def_opt
=
None
;
}
}
if
let
Some
(
last_def
)
=
last_def_opt
{
new_defs
.push
(
last_def
);
}
blk
.term.defs
=
new_defs
;
}
/// Replaces variables by expressions that can be propagated within functions.
///
/// This is performed by a fixpoint computation and might panic, if it does not stabilize.
...
...
src/cwe_checker_lib/src/analysis/expression_propagation/tests.rs
View file @
decc1254
...
...
@@ -95,6 +95,32 @@ fn get_mock_entry_block() -> Term<Blk> {
}
#[test]
fn
expression_propagation
()
{
use
super
::
*
;
let
defs
=
defs!
[
"tid_1: X:8 = -(Y:8)"
,
"tid_2: Y:8 = X:8 + Y:8"
,
"tid_3: X:8 = -(X:8)"
,
"tid_4: Y:8 = -(Y:8)"
,
"tid_5: Y:8 = X:8 + Y:8"
];
let
block
=
&
mut
Blk
::
mock
();
block
.term.defs
=
defs
;
merge_def_assignments_to_same_var
(
block
);
propagate_input_expressions
(
block
,
None
);
let
result_defs
=
defs!
[
"tid_1: X:8 = -(Y:8)"
,
"tid_2: Y:8 = -(Y:8) + Y:8"
,
"tid_3: X:8 = -(X:8)"
,
"tid_5: Y:8 = X:8 + -(Y:8)"
];
assert_eq!
(
block
.term.defs
,
result_defs
);
}
#[test]
/// Tests the propagation of insertable expressions among basic blocks.
fn
inter_block_propagation
()
{
let
mut
project
=
mock_project
();
...
...
src/cwe_checker_lib/src/analysis/forward_interprocedural_fixpoint.rs
View file @
decc1254
...
...
@@ -333,6 +333,7 @@ mod tests {
create_computation_with_top_down_worklist_order
,
},
},
expr
,
intermediate_representation
::
*
,
};
use
std
::
collections
::{
BTreeMap
,
HashMap
,
HashSet
};
...
...
@@ -353,7 +354,7 @@ mod tests {
let
mut
callee_block
=
new_block
(
"callee block"
);
callee_block
.term.jmps
.push
(
Term
{
tid
:
Tid
::
new
(
"ret"
),
term
:
Jmp
::
Return
(
Expression
::
const_from_i32
(
42
)),
term
:
Jmp
::
Return
(
expr!
(
"42:4"
)),
});
let
called_function
=
Term
{
...
...
src/cwe_checker_lib/src/analysis/function_signature/global_var_propagation.rs
View file @
decc1254
...
...
@@ -235,14 +235,14 @@ pub mod tests {
// main -> callee1 -> callee2
let
mut
func
=
Sub
::
mock
(
"main"
);
let
mut
call_blk
=
Blk
::
mock_with_tid
(
"main_blk"
);
let
call
=
Jmp
::
mock_call
(
"callee1"
,
None
);
let
call
=
Jmp
::
call
(
"call_callee1"
,
"callee1"
,
None
);
call_blk
.term.jmps
.push
(
call
);
func
.term.blocks
.push
(
call_blk
);
project
.program.term.subs
.insert
(
Tid
::
new
(
"main"
),
func
);
let
mut
func
=
Sub
::
mock
(
"callee1"
);
let
mut
call_blk
=
Blk
::
mock_with_tid
(
"callee1_blk"
);
let
call
=
Jmp
::
mock_call
(
"callee2"
,
None
);
let
call
=
Jmp
::
call
(
"call_callee2"
,
"callee2"
,
None
);
call_blk
.term.jmps
.push
(
call
);
func
.term.blocks
.push
(
call_blk
);
project
.program.term.subs
.insert
(
Tid
::
new
(
"callee1"
),
func
);
...
...
src/cwe_checker_lib/src/analysis/graph.rs
View file @
decc1254
...
...
@@ -512,6 +512,8 @@ pub fn get_entry_nodes_of_subs(graph: &Graph) -> HashMap<Tid, NodeIndex> {
#[cfg(test)]
mod
tests
{
use
crate
::
expr
;
use
super
::
*
;
use
std
::
collections
::{
BTreeMap
,
BTreeSet
};
use
std
::
iter
::
FromIterator
;
...
...
@@ -526,7 +528,7 @@ mod tests {
};
let
return_term
=
Term
{
tid
:
Tid
::
new
(
"return"
.to_string
()),
term
:
Jmp
::
Return
(
Expression
::
Const
(
Bitvector
::
zero
(
64
.into
())
)),
// The return term does not matter
term
:
Jmp
::
Return
(
expr!
(
"0:8"
)),
// The return term does not matter
};
let
jmp
=
Jmp
::
Branch
(
Tid
::
new
(
"sub1_blk1"
));
let
jmp_term
=
Term
{
...
...
@@ -559,7 +561,7 @@ mod tests {
};
let
cond_jump
=
Jmp
::
CBranch
{
target
:
Tid
::
new
(
"sub1_blk1"
),
condition
:
Expression
::
Const
(
Bitvector
::
from_u8
(
0
)
),
condition
:
expr!
(
"0:1"
),
};
let
cond_jump_term
=
Term
{
tid
:
Tid
::
new
(
"cond_jump"
),
...
...
@@ -618,7 +620,7 @@ mod tests {
fn
add_indirect_jumps
()
{
let
indirect_jmp_term
=
Term
{
tid
:
Tid
::
new
(
"indrect_jmp"
.to_string
()),
term
:
Jmp
::
BranchInd
(
Expression
::
Const
(
Bitvector
::
from_u32
(
0x1000
)
)),
// At the moment the expression does not matter
term
:
Jmp
::
BranchInd
(
expr!
(
"0x1000:4"
)),
// At the moment the expression does not matter
};
let
mut
blk_tid
=
Tid
::
new
(
"blk_00001000"
);
blk_tid
.address
=
"00001000"
.to_string
();
...
...
src/cwe_checker_lib/src/analysis/pointer_inference/context/tests.rs
View file @
decc1254
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/analysis/pointer_inference/object/tests.rs
View file @
decc1254
use
super
::
*
;
use
crate
::
intermediate_representation
::
Variable
;
use
crate
::
{
intermediate_representation
::
*
,
variable
}
;
use
std
::
collections
::
BTreeMap
;
fn
new_abstract_object
()
->
AbstractObject
{
...
...
@@ -23,7 +23,7 @@ fn bv(number: i64) -> ValueDomain {
fn
new_id
(
tid
:
&
str
,
reg_name
:
&
str
)
->
AbstractIdentifier
{
AbstractIdentifier
::
new
(
Tid
::
new
(
tid
),
AbstractLocation
::
Register
(
Variable
::
mock
(
reg_name
,
ByteSize
::
new
(
8
))),
AbstractLocation
::
Register
(
variable!
(
format!
(
"{reg_name}:8"
))),
)
}
...
...
src/cwe_checker_lib/src/analysis/pointer_inference/object_list/tests.rs
View file @
decc1254
use
crate
::
intermediate_representation
::
Variable
;
use
crate
::
intermediate_representation
::
*
;
use
crate
::
variable
;
use
super
::
super
::
ValueDomain
;
use
super
::
*
;
...
...
@@ -10,7 +11,7 @@ fn bv(value: i64) -> ValueDomain {
fn
new_id
(
name
:
&
str
)
->
AbstractIdentifier
{
AbstractIdentifier
::
new
(
Tid
::
new
(
"time0"
),
AbstractLocation
::
Register
(
Variable
::
mock
(
name
,
ByteSize
::
new
(
8
))),
AbstractLocation
::
Register
(
variable!
(
format!
(
"{name}:8"
))),
)
}
...
...
src/cwe_checker_lib/src/analysis/pointer_inference/state/tests/mod.rs
View file @
decc1254
...
...
@@ -316,7 +316,7 @@ fn test_widening_hints_after_pointer_specialization() {
.add_signed_greater_equal_bound
(
&
Bitvector
::
from_i64
(
6
))
.unwrap
();
let
expected_val
=
Data
::
from_target
(
new_id
(
"func_tid"
,
"RSP"
),
offset_with_lower_bound
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"RBX"
,
8
)),
expected_val
);
assert_eq!
(
state
.get_register
(
&
variable!
(
"RBX:8"
)),
expected_val
);
}
#[test]
...
...
@@ -363,11 +363,11 @@ fn from_fn_sig() {
Data
::
from_target
(
new_id
(
"func"
,
"RSP"
),
bv
(
0
)
.into
())
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"RDI"
,
8
)),
state
.get_register
(
&
variable!
(
"RDI:8"
)),
Data
::
from_target
(
new_id
(
"func"
,
"RDI"
),
bv
(
0
)
.into
())
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"RSI"
,
8
)),
state
.get_register
(
&
variable!
(
"RSI:8"
)),
Data
::
from_target
(
new_id
(
"func"
,
"RSI"
),
bv
(
0
)
.into
())
);
}
...
...
src/cwe_checker_lib/src/analysis/pointer_inference/state/tests/specialized_expressions.rs
View file @
decc1254
...
...
@@ -167,11 +167,11 @@ fn specialize_by_binop() {
);
assert
!
(
x
.is_ok
());
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"FLAG1"
,
1u64
)),
state
.get_register
(
&
variable!
(
"FLAG1:1"
)),
bitvec!
(
"1:1"
)
.into
()
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"FLAG2"
,
1u64
)),
state
.get_register
(
&
variable!
(
"FLAG2:1"
)),
bitvec!
(
"1:1"
)
.into
()
);
// Expr = (FLAG bool_and 1 = Const)
...
...
src/cwe_checker_lib/src/analysis/stack_alignment_substitution/tests.rs
View file @
decc1254
...
...
@@ -285,9 +285,7 @@ fn supports_commutative_and() {
Expression
::
BinOp
{
op
:
BinOpType
::
IntAnd
,
lhs
:
Box
::
new
(
expr!
(
"RSP:8"
)),
rhs
:
Box
::
new
(
Expression
::
const_from_apint
(
ApInt
::
from_u64
(
0xFFFFFFFF
_FFFFFFFF
<<
4
,
// 16 Byte alignment
))),
rhs
:
Box
::
new
(
expr!
(
format!
(
"{}:8"
,
0xFFFFFFFF
_FFFFFFFF_u64
<<
4
))),
},
);
let
bitmask_and_var
=
Def
::
assign
(
...
...
@@ -330,9 +328,7 @@ fn skips_empty_blocks() {
lhs
:
Box
::
new
(
Expression
::
Var
(
Project
::
mock_x64
()
.stack_pointer_register
.clone
(),
)),
rhs
:
Box
::
new
(
Expression
::
const_from_apint
(
ApInt
::
from_u64
(
0xFFFFFFFF
_FFFFFFFF
<<
4
,
// 16 Byte alignment
))),
rhs
:
Box
::
new
(
expr!
(
format!
(
"{}:8"
,
0xFFFFFFFF
_FFFFFFFF_u64
<<
4
))),
},
);
// get project with empty block
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/symbol_calls/memcpy.rs
View file @
decc1254
...
...
@@ -7,7 +7,7 @@ use crate::{
AbstractDomain
,
DataDomain
,
DomainInsertion
,
HasTop
,
IntervalDomain
,
TryToBitvec
,
},
analysis
::
string_abstraction
::{
context
::
Context
,
state
::
State
},
intermediate_representation
::
ExternSymbol
,
intermediate_representation
::
*
,
};
use
std
::
collections
::
BTreeMap
;
...
...
@@ -206,7 +206,8 @@ mod tests {
context
::
symbol_calls
::
tests
::
Setup
,
tests
::
mock_project_with_intraprocedural_control_flow
,
},
intermediate_representation
::{
Bitvector
,
Tid
,
Variable
},
intermediate_representation
::{
Bitvector
,
Tid
},
variable
,
};
use
std
::
collections
::{
BTreeMap
,
BTreeSet
};
...
...
@@ -226,12 +227,12 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
mut
parameter_pointer
:
DataDomain
<
IntervalDomain
>
=
...
...
@@ -250,7 +251,7 @@ mod tests {
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r1"
,
4
),
parameter_pointer
);
.set_register
(
&
variable!
(
"r1:4"
),
parameter_pointer
);
setup
.state_before_call
...
...
@@ -314,7 +315,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
expected_data
:
DataDomain
<
IntervalDomain
>
=
...
...
@@ -365,12 +366,12 @@ mod tests {
let
return_targets
=
setup
.pi_state_before_symbol_call
.get_register
(
&
Variable
::
mock
(
"r0"
,
4
));
.get_register
(
&
variable!
(
"r0:4"
));
let
input_target
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
setup
.pi_state_before_symbol_call
.get_register
(
&
Variable
::
mock
(
"r1"
,
4
))
.get_register
(
&
variable!
(
"r1:4"
))
.get_absolute_value
()
.unwrap
()
.clone
(),
...
...
@@ -407,14 +408,14 @@ mod tests {
let
return_targets
=
setup
.pi_state_before_symbol_call
.get_register
(
&
Variable
::
mock
(
"r0"
,
4
))
.get_register
(
&
variable!
(
"r0:4"
))
.get_relative_values
()
.clone
();
let
input_target
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
setup
.pi_state_before_symbol_call
.get_register
(
&
Variable
::
mock
(
"r1"
,
4
))
.get_register
(
&
variable!
(
"r1:4"
))
.get_absolute_value
()
.unwrap
()
.clone
(),
...
...
@@ -462,11 +463,11 @@ mod tests {
fn
test_has_multiple_targets
()
{
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
// Test Case 1: Only one relative target.
let
mut
data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
mock_from_target_map
(
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/symbol_calls/scanf.rs
View file @
decc1254
...
...
@@ -199,7 +199,7 @@ mod tests {
use
crate
::
abstract_domain
::{
AbstractIdentifier
,
AbstractLocation
,
CharacterInclusionDomain
};
use
crate
::
analysis
::
pointer_inference
::
PointerInference
as
PointerInferenceComputation
;
use
crate
::
analysis
::
string_abstraction
::
tests
::
mock_project_with_intraprocedural_control_flow
;
use
crate
::
intermediate_representation
::{
Expression
,
V
ariable
};
use
crate
::
{
expr
,
intermediate_representation
::
*
,
v
ariable
};
#[test]
fn
test_handle_scanf_calls
()
{
...
...
@@ -222,7 +222,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
assert
!
(
new_state
...
...
@@ -285,7 +285,7 @@ mod tests {
#[test]
fn
test_create_abstract_domain_entries_for_function_return_values_with_known_values
()
{
let
r2_reg
=
Variable
::
mock
(
"r2"
,
4
);
let
r2_reg
=
variable!
(
"r2:4"
);
let
sscanf_symbol
=
ExternSymbol
::
mock_sscanf_symbol_arm
();
let
project
=
mock_project_with_intraprocedural_control_flow
(
...
...
@@ -299,7 +299,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
mut
arg_to_value_map
:
HashMap
<
Arg
,
Option
<
String
>>
=
HashMap
::
new
();
...
...
@@ -309,7 +309,7 @@ mod tests {
data_type
:
Some
(
Datatype
::
Pointer
),
};
let
stack_arg
=
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"sp"
,
4
)
),
address
:
expr!
(
"sp:4"
),
size
:
ByteSize
::
new
(
4
),
data_type
:
Some
(
Datatype
::
Pointer
),
};
...
...
@@ -361,7 +361,7 @@ mod tests {
#[test]
fn
test_create_abstract_domain_entries_for_function_return_values_with_unknown_values
()
{
let
r1_reg
=
Variable
::
mock
(
"r1"
,
4
);
let
r1_reg
=
variable!
(
"r1:4"
);
let
scanf_symbol
=
ExternSymbol
::
mock_scanf_symbol_arm
();
let
project
=
mock_project_with_intraprocedural_control_flow
(
...
...
@@ -375,7 +375,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
mut
arg_to_value_map
:
HashMap
<
Arg
,
Option
<
String
>>
=
HashMap
::
new
();
...
...
@@ -384,7 +384,7 @@ mod tests {
data_type
:
Some
(
Datatype
::
Pointer
),
};
let
stack_arg
=
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"sp"
,
4
)
),
address
:
expr!
(
"sp:4"
),
size
:
ByteSize
::
new
(
4
),
data_type
:
Some
(
Datatype
::
Pointer
),
};
...
...
@@ -448,7 +448,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
return_target
:
DataDomain
<
IntervalDomain
>
=
...
...
@@ -532,7 +532,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
new_state
=
setup
...
...
@@ -585,7 +585,7 @@ mod tests {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
new_state
=
setup
...
...
@@ -734,7 +734,7 @@ mod tests {
),
(
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"sp"
,
4
)
),
address
:
expr!
(
"sp:4"
),
size
:
ByteSize
::
new
(
4
),
data_type
:
Some
(
Datatype
::
Pointer
),
},
...
...
@@ -742,7 +742,7 @@ mod tests {
),
(
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"sp"
,
4
))
.plus_const
(
4
),
address
:
expr!
(
"sp:4 + 4:4"
),
size
:
ByteSize
::
new
(
4
),
data_type
:
Some
(
Datatype
::
Pointer
),
},
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/symbol_calls/sprintf/tests.rs
View file @
decc1254
...
...
@@ -3,13 +3,13 @@ use std::collections::BTreeSet;
use
super
::
*
;
use
crate
::
abstract_domain
::{
AbstractIdentifier
,
AbstractLocation
};
use
crate
::
analysis
::
pointer_inference
::
PointerInference
as
PointerInferenceComputation
;
use
crate
::
intermediate_representation
::{
Bitvector
,
Expression
,
Tid
,
Variable
};
use
crate
::{
abstract_domain
::{
CharacterInclusionDomain
,
CharacterSet
},
analysis
::
string_abstraction
::{
context
::
symbol_calls
::
tests
::
Setup
,
tests
::
mock_project_with_intraprocedural_control_flow
,
},
};
use
crate
::{
bitvec
,
expr
,
intermediate_representation
::
*
,
variable
};
#[test]
fn
test_handle_sprintf_and_snprintf_calls
()
{
...
...
@@ -29,10 +29,10 @@ fn test_handle_sprintf_and_snprintf_calls() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
return_pointer
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
stack_id
,
IntervalDomain
::
from
(
Bitvector
::
from_i32
(
-
84
)));
DataDomain
::
from_target
(
stack_id
,
IntervalDomain
::
from
(
bitvec!
(
"-84:4"
)));
assert_eq!
(
return_pointer
,
...
...
@@ -68,10 +68,10 @@ fn test_parse_format_string_and_add_new_string_domain() {
let
format_string_index
:
usize
=
1
;
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
return_pointer
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
stack_id
,
IntervalDomain
::
from
(
Bitvector
::
from_i32
(
-
84
)));
DataDomain
::
from_target
(
stack_id
,
IntervalDomain
::
from
(
bitvec!
(
"-84:4"
)));
let
project
=
mock_project_with_intraprocedural_control_flow
(
vec!
[(
sprintf_symbol
.clone
(),
vec!
[
true
])],
...
...
@@ -174,15 +174,15 @@ fn test_create_string_domain_using_data_type_approximations() {
fn
test_create_string_domain_using_constants_and_sub_domains
()
{
let
sprintf_symbol
=
ExternSymbol
::
mock_sprintf_symbol_arm
();
let
string_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r6"
,
4
)),
expr
:
Expression
::
Var
(
variable!
(
"r6:4"
)),
data_type
:
Some
(
Datatype
::
Pointer
),
};
let
integer_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r7"
,
4
)),
expr
:
Expression
::
Var
(
variable!
(
"r7:4"
)),
data_type
:
Some
(
Datatype
::
Integer
),
};
let
char_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r8"
,
4
)),
expr
:
Expression
::
Var
(
variable!
(
"r8:4"
)),
data_type
:
Some
(
Datatype
::
Char
),
};
...
...
@@ -199,27 +199,21 @@ fn test_create_string_domain_using_constants_and_sub_domains() {
let
mut
setup
:
Setup
<
CharacterInclusionDomain
>
=
Setup
::
new
(
&
pi_results
);
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r6"
,
4
),
&
variable!
(
"r6:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u64
(
0x3002
),
Bitvector
::
from_u64
(
0x3002
),
bitvec!
(
"0x3002:8"
),
bitvec!
(
"0x3002:8"
),
)),
);
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r7"
,
4
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u64
(
2
),
Bitvector
::
from_u64
(
2
),
)),
&
variable!
(
"r7:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
bitvec!
(
"2:8"
),
bitvec!
(
"2:8"
))),
);
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r8"
,
4
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u64
(
0x42
),
Bitvector
::
from_u64
(
0x42
),
)),
&
variable!
(
"r8:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
bitvec!
(
"0x42:8"
),
bitvec!
(
"0x42:8"
))),
);
let
result_domain
=
setup
...
...
@@ -341,15 +335,15 @@ fn test_no_specifiers() {
fn
test_fetch_constant_and_domain_for_format_specifier
()
{
let
sprintf_symbol
=
ExternSymbol
::
mock_sprintf_symbol_arm
();
let
string_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r6"
,
4
)
),
expr
:
expr!
(
"r6:4"
),
data_type
:
Some
(
Datatype
::
Pointer
),
};
let
integer_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r7"
,
4
)
),
expr
:
expr!
(
"r7:4"
),
data_type
:
Some
(
Datatype
::
Integer
),
};
let
char_arg
=
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"r8"
,
4
)
),
expr
:
expr!
(
"r8:4"
),
data_type
:
Some
(
Datatype
::
Char
),
};
...
...
@@ -408,11 +402,8 @@ fn test_fetch_constant_and_domain_for_format_specifier() {
// Test Case 4: Integer and tracked constant.
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r7"
,
4
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u64
(
2
),
Bitvector
::
from_u64
(
2
),
)),
&
variable!
(
"r7:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
bitvec!
(
"2:8"
),
bitvec!
(
"2:8"
))),
);
assert_eq!
(
...
...
@@ -429,11 +420,8 @@ fn test_fetch_constant_and_domain_for_format_specifier() {
// Test Case 5: Char and tracked constant.
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r8"
,
4
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u32
(
0x42
),
Bitvector
::
from_u32
(
0x42
),
)),
&
variable!
(
"r8:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
bitvec!
(
"0x42:4"
),
bitvec!
(
"0x42:4"
))),
);
assert_eq!
(
...
...
@@ -450,10 +438,10 @@ fn test_fetch_constant_and_domain_for_format_specifier() {
// Test Case 6: String and tracked constant.
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r6"
,
4
),
&
variable!
(
"r6:4"
),
DataDomain
::
from
(
IntervalDomain
::
new
(
Bitvector
::
from_u32
(
0x3002
),
Bitvector
::
from_u32
(
0x3002
),
bitvec!
(
"0x3002:4"
),
bitvec!
(
"0x3002:4"
),
)),
);
...
...
@@ -471,22 +459,22 @@ fn test_fetch_constant_and_domain_for_format_specifier() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
mut
pointer
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
stack_id
,
IntervalDomain
::
new
(
Bitvector
::
from_i32
(
16
),
Bitvector
::
from_i32
(
16
)),
IntervalDomain
::
new
(
bitvec!
(
"16:4"
),
bitvec!
(
"16:4"
)),
);
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r9"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r9:4"
))
.unwrap
(),
);
pointer
.insert_relative_value
(
heap_id
.clone
(),
IntervalDomain
::
new
(
Bitvector
::
from_i32
(
0
),
Bitvector
::
from_i32
(
0
)),
IntervalDomain
::
new
(
bitvec!
(
"0:4"
),
bitvec!
(
"0:4"
)),
);
setup
...
...
@@ -499,7 +487,7 @@ fn test_fetch_constant_and_domain_for_format_specifier() {
// Test Case 5: String and tracked domain.
setup
.pi_state_before_symbol_call
.set_register
(
&
Variable
::
mock
(
"r6"
,
4
),
pointer
);
.set_register
(
&
variable!
(
"r6:4"
),
pointer
);
let
expected_domain
=
CharacterInclusionDomain
::
Value
((
CharacterSet
::
Value
(
BTreeSet
::
new
()),
...
...
@@ -557,7 +545,7 @@ fn test_fetch_subdomains_if_available() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
// Test Case 2: Target value is not of type string pointer.
...
...
@@ -600,13 +588,13 @@ fn test_fetch_constant_domain_if_available() {
pi_results
.compute
(
false
);
let
setup
:
Setup
<
CharacterInclusionDomain
>
=
Setup
::
new
(
&
pi_results
);
let
string_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
Bitvector
::
from_i32
(
0x7000
));
let
string_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
bitvec!
(
"0x7000:4"
));
let
string_arg
:
Arg
=
Arg
::
mock_pointer_register
(
"r0"
,
4
);
let
integer_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
Bitvector
::
from_i32
(
2
));
let
integer_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
bitvec!
(
"2:4"
));
let
integer_arg
:
Arg
=
Arg
::
mock_register_with_data_type
(
"r0"
,
4
,
Some
(
Datatype
::
Integer
));
let
char_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
Bitvector
::
from_i32
(
0x61
));
let
char_data
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from
(
bitvec!
(
"0x61:4"
));
let
char_arg
:
Arg
=
Arg
::
mock_register_with_data_type
(
"r0"
,
4
,
Some
(
Datatype
::
Char
));
assert_eq!
(
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/symbol_calls/strcat.rs
View file @
decc1254
...
...
@@ -107,11 +107,10 @@ mod tests {
context
::
symbol_calls
::
tests
::
Setup
,
tests
::
mock_project_with_intraprocedural_control_flow
,
},
intermediate_representation
::{
ByteSize
,
Variable
},
intermediate_representation
::
*
,
variable
,
};
use
super
::
*
;
#[test]
fn
test_handle_strcat_and_strncat_calls_with_known_second_input
()
{
let
strcat_symbol
=
ExternSymbol
::
mock_strcat_symbol_arm
();
...
...
@@ -247,7 +246,7 @@ mod tests {
#[test]
fn
test_process_second_input_domain_local_and_global
()
{
let
r1_reg
=
Variable
::
mock
(
"r1"
,
ByteSize
::
new
(
4
)
);
let
r1_reg
=
variable!
(
"r1:4"
);
let
strcat_symbol
=
ExternSymbol
::
mock_strcat_symbol_arm
();
let
project
=
mock_project_with_intraprocedural_control_flow
(
vec!
[(
strcat_symbol
.clone
(),
vec!
[
false
])],
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/symbol_calls/tests.rs
View file @
decc1254
...
...
@@ -13,10 +13,10 @@ use crate::analysis::pointer_inference::PointerInference as PointerInferenceComp
use
crate
::
analysis
::
pointer_inference
::
State
as
PiState
;
use
crate
::
analysis
::
string_abstraction
::
state
::
State
;
use
crate
::
analysis
::
string_abstraction
::
tests
::
*
;
use
crate
::
intermediate_representation
::{
Bitvector
,
ExternSymbol
,
Project
,
Sub
};
use
crate
::
intermediate_representation
::
*
;
use
crate
::
variable
;
use
crate
::{
abstract_domain
::{
AbstractIdentifier
,
AbstractLocation
},
intermediate_representation
::{
Tid
,
Variable
},
utils
::
symbol_utils
::
get_symbol_map
,
};
...
...
@@ -119,7 +119,7 @@ fn test_handle_generic_symbol_calls() {
let
mut
setup
:
Setup
<
CharacterInclusionDomain
>
=
Setup
::
new
(
&
pi_results
);
setup
.state_before_call
.add_new_variable_to_pointer_entry
(
Variable
::
mock
(
"r1"
,
4
),
variable!
(
"r1:4"
),
DataDomain
::
from
(
IntervalDomain
::
from
(
Bitvector
::
from_i32
(
32
))),
);
...
...
@@ -143,7 +143,7 @@ fn test_handle_unknown_symbol_calls() {
let
mut
setup
:
Setup
<
CharacterInclusionDomain
>
=
Setup
::
new
(
&
pi_results
);
setup
.state_before_call
.add_new_variable_to_pointer_entry
(
Variable
::
mock
(
"r1"
,
4
),
variable!
(
"r1:4"
),
DataDomain
::
from
(
IntervalDomain
::
from
(
Bitvector
::
from_i32
(
32
))),
);
...
...
@@ -174,7 +174,7 @@ fn test_add_new_string_abstract_domain() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
stack_pointer
=
DataDomain
::
from_target
(
stack_id
.clone
(),
...
...
@@ -194,7 +194,7 @@ fn test_add_new_string_abstract_domain() {
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
heap_pointer
=
DataDomain
::
from_target
(
...
...
@@ -227,12 +227,12 @@ fn test_merge_domains_from_multiple_pointer_targets() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
mut
domain_pointer
:
DataDomain
<
IntervalDomain
>
=
...
...
@@ -424,7 +424,7 @@ fn test_insert_constant_string_into_format_string() {
fn
test_handle_free
()
{
let
free_symbol
=
ExternSymbol
::
mock_free_symbol_arm
();
let
malloc_symbol
=
ExternSymbol
::
mock_malloc_symbol_arm
();
let
r0_reg
=
Variable
::
mock
(
"r0"
,
4
);
let
r0_reg
=
variable!
(
"r0:4"
);
let
project
=
mock_project_with_intraprocedural_control_flow
(
vec!
[
(
malloc_symbol
.clone
(),
vec!
[]),
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/context/trait_impls/tests.rs
View file @
decc1254
...
...
@@ -28,8 +28,8 @@ fn test_update_def() {
setup
.context.block_first_def_set
=
HashSet
::
new
();
let
assign_def
=
def!
[
"assign_def: r1:4 = 0x7000:4"
];
let
load_def
=
load_var_content_from_temp_var
(
"load_def"
,
"r5"
,
"r2"
);
let
store_def
=
store_var_content_at_temp_var
(
"store_def"
,
"r0"
,
"r5"
);
let
load_def
=
Def
::
load_var_content_from_temp_var
(
"load_def"
,
"r5"
,
"r2"
);
let
store_def
=
Def
::
store_var_content_at_temp_var
(
"store_def"
,
"r0"
,
"r5"
);
let
new_state
=
setup
.context
...
...
src/cwe_checker_lib/src/analysis/string_abstraction/state/tests.rs
View file @
decc1254
...
...
@@ -5,13 +5,16 @@ use crate::{
pointer_inference
::
State
as
PiState
,
string_abstraction
::
tests
::
mock_project_with_intraprocedural_control_flow
,
},
expr
,
intermediate_representation
::
*
,
variable
,
};
use
std
::
collections
::
BTreeSet
;
impl
<
T
:
AbstractDomain
+
DomainInsertion
+
HasTop
+
Eq
+
From
<
String
>>
State
<
T
>
{
pub
fn
mock_with_default_pi_state
(
current_sub
:
Term
<
Sub
>
)
->
Self
{
let
pi_state
=
PointerInferenceState
::
new
(
&
Variable
::
mock
(
"sp"
,
4
as
u64
),
&
variable!
(
"sp:4"
),
current_sub
.tid
.clone
(),
BTreeSet
::
new
(),
);
...
...
@@ -50,7 +53,7 @@ fn test_delete_string_map_entries_if_no_pointer_targets_are_tracked() {
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
stack_pointer
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
stack_id
.clone
(),
...
...
@@ -59,7 +62,7 @@ fn test_delete_string_map_entries_if_no_pointer_targets_are_tracked() {
let
heap_id_1
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
heap_pointer_1
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
...
...
@@ -69,7 +72,7 @@ fn test_delete_string_map_entries_if_no_pointer_targets_are_tracked() {
let
heap_id_2
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r6"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r6:4"
))
.unwrap
(),
);
let
heap_pointer_2
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
...
...
@@ -79,12 +82,12 @@ fn test_delete_string_map_entries_if_no_pointer_targets_are_tracked() {
let
heap_id_3
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r7"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r7:4"
))
.unwrap
(),
);
state
.variable_to_pointer_map
.insert
(
Variable
::
mock
(
"r0"
,
4
),
stack_pointer
);
.insert
(
variable!
(
"r0:4"
),
stack_pointer
);
state
.stack_offset_to_pointer_map
.insert
(
-
8
,
heap_pointer_1
);
state
.unassigned_return_pointer
.insert
(
heap_pointer_2
);
...
...
@@ -153,10 +156,10 @@ fn test_handle_assign_and_load() {
let
sub
=
Sub
::
mock
(
"func"
);
let
mut
state
:
State
<
CharacterInclusionDomain
>
=
State
::
mock_with_default_pi_state
(
sub
.clone
());
let
runtime_memory_image
=
RuntimeMemoryImage
::
mock
();
let
output
=
Variable
::
mock
(
"r1"
,
4
);
let
output
=
variable!
(
"r1:4"
);
let
constant_input
=
Expression
::
Const
(
Bitvector
::
from_str_radix
(
16
,
"7000"
)
.unwrap
());
let
return_address_input
=
Expression
::
Const
(
Bitvector
::
from_str_radix
(
16
,
"14718"
)
.unwrap
());
let
other_input
=
Expression
::
var
(
"r6"
,
4
);
let
other_input
=
expr!
(
"r6:4"
);
let
mut
block_first_def_set
:
HashSet
<
(
Tid
,
Tid
)
>
=
HashSet
::
new
();
let
mut
return_tid
=
Tid
::
new
(
"14718"
);
...
...
@@ -211,7 +214,7 @@ fn test_handle_assign_and_load() {
// Test Case 2: Assign Def with other input
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
heap_pointer
:
DataDomain
<
IntervalDomain
>
=
DataDomain
::
from_target
(
...
...
@@ -263,19 +266,19 @@ fn test_handle_assign_and_load() {
#[test]
fn
test_add_pointer_to_variable_maps_if_tracked
()
{
let
output_var
=
Variable
::
mock
(
"r2"
,
4
);
let
origin_var
=
Variable
::
mock
(
"r5"
,
4
);
let
output_var
=
variable!
(
"r2:4"
);
let
origin_var
=
variable!
(
"r5:4"
);
let
mut
mock_state
=
State
::
<
CharacterInclusionDomain
>
::
mock_with_default_pi_state
(
Sub
::
mock
(
"func"
));
let
pi_state
=
mock_state
.get_pointer_inference_state
()
.unwrap
()
.clone
();
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r5"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r5:4"
))
.unwrap
(),
);
let
stack_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"func"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"sp"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"sp:4"
))
.unwrap
(),
);
let
mut
source_pointer
:
DataDomain
<
IntervalDomain
>
=
...
...
@@ -339,7 +342,7 @@ fn test_pointer_targets_partially_tracked() {
let
heap_id
=
AbstractIdentifier
::
new
(
Tid
::
new
(
"heap"
),
AbstractLocation
::
from_var
(
&
Variable
::
mock
(
"r0"
,
4
))
.unwrap
(),
AbstractLocation
::
from_var
(
&
variable!
(
"r0:4"
))
.unwrap
(),
);
let
stack_id
=
pi_state
.stack_id
.clone
();
...
...
@@ -367,8 +370,8 @@ fn test_pointer_targets_partially_tracked() {
#[test]
fn
test_pointer_is_in_pointer_maps
()
{
let
r2_reg
=
Variable
::
mock
(
"r2"
,
4
);
let
sp_reg
=
Variable
::
mock
(
"sp"
,
4
);
let
r2_reg
=
variable!
(
"r2:4"
);
let
sp_reg
=
variable!
(
"sp:4"
);
let
mut
mock_state
=
State
::
<
CharacterInclusionDomain
>
::
mock_with_default_pi_state
(
Sub
::
mock
(
"func"
));
...
...
@@ -401,10 +404,10 @@ fn test_pointer_is_in_pointer_maps() {
#[test]
fn
test_handle_store
()
{
let
block_first_def_set
:
HashSet
<
(
Tid
,
Tid
)
>
=
HashSet
::
new
();
let
target_var
=
Variable
::
mock
(
"r2"
,
4
);
let
value_var
=
Variable
::
mock
(
"r3"
,
4
);
let
target_var
=
variable!
(
"r2:4"
);
let
value_var
=
variable!
(
"r3:4"
);
let
value_location
=
Expression
::
Var
(
value_var
.clone
());
let
sp_reg
=
Variable
::
mock
(
"sp"
,
4
);
let
sp_reg
=
variable!
(
"sp:4"
);
let
target_location
=
Expression
::
Var
(
target_var
.clone
());
let
runtime_memory_image
=
RuntimeMemoryImage
::
mock
();
let
mut
mock_state
=
...
...
@@ -465,7 +468,7 @@ fn test_handle_store() {
mock_state
.set_all_maps_empty
();
mock_state
.variable_to_pointer_map
.insert
(
Variable
::
mock
(
"r0"
,
4
),
string_pointer
.clone
());
.insert
(
variable!
(
"r0:4"
),
string_pointer
.clone
());
mock_state
.handle_store
(
&
target_location
,
...
...
@@ -483,15 +486,15 @@ fn test_handle_store() {
mock_state
.set_all_maps_empty
();
mock_state
.variable_to_pointer_map
.insert
(
Variable
::
mock
(
"r0"
,
4
),
string_pointer
.clone
());
.insert
(
variable!
(
"r0:4"
),
string_pointer
.clone
());
// Test Case 5: Global address pointer as constant.
// Test Case 6: Global address pointer in variable.
}
#[test]
fn
test_add_pointer_to_stack_map
()
{
let
r2_reg
=
Variable
::
mock
(
"r2"
,
4
);
let
sp_reg
=
Variable
::
mock
(
"sp"
,
4
);
let
r2_reg
=
variable!
(
"r2:4"
);
let
sp_reg
=
variable!
(
"sp:4"
);
let
target
=
Expression
::
Var
(
r2_reg
.clone
());
let
mut
mock_state
=
State
::
<
CharacterInclusionDomain
>
::
mock_with_default_pi_state
(
Sub
::
mock
(
"func"
));
...
...
@@ -532,18 +535,18 @@ fn test_remove_non_callee_saved_pointer_entries_for_external_symbol() {
mock_state
.variable_to_pointer_map
.insert
(
Variable
::
mock
(
"r0"
,
4
),
top_domain
.clone
());
.insert
(
variable!
(
"r0:4"
),
top_domain
.clone
());
mock_state
.variable_to_pointer_map
.insert
(
Variable
::
mock
(
"r11"
,
4
),
top_domain
);
.insert
(
variable!
(
"r11:4"
),
top_domain
);
mock_state
.remove_non_callee_saved_pointer_entries_for_external_symbol
(
&
project
,
&
sprintf_symbol
);
assert
!
(
!
mock_state
.variable_to_pointer_map
.contains_key
(
&
Variable
::
mock
(
"r0"
,
4
)));
.contains_key
(
&
variable!
(
"r0:4"
)));
assert
!
(
mock_state
.variable_to_pointer_map
.contains_key
(
&
Variable
::
mock
(
"r11"
,
4
)));
.contains_key
(
&
variable!
(
"r11:4"
)));
}
src/cwe_checker_lib/src/analysis/string_abstraction/tests.rs
View file @
decc1254
use
crate
::{
def
,
defs
,
expr
,
intermediate_representation
::
*
,
variable
};
// FIXME: Move this function to the intermediate_representation module
pub
fn
pointer_plus_offset_to_temp_var
(
tid
:
&
str
,
tmp_name
:
&
str
,
pointer
:
&
str
,
offset
:
i64
,
)
->
Term
<
Def
>
{
Def
::
assign
(
tid
,
Variable
{
name
:
String
::
from
(
tmp_name
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
true
,
},
expr!
(
format!
(
"{}:4 + {}:4"
,
pointer
,
offset
)),
)
}
// FIXME: Move this function to the intermediate_representation module
pub
fn
store_var_content_at_temp_var
(
tid
:
&
str
,
tmp_name
:
&
str
,
var
:
&
str
)
->
Term
<
Def
>
{
Def
::
store
(
tid
,
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
tmp_name
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
true
,
}),
expr!
(
format!
(
"{}:4"
,
var
)),
)
}
// FIXME: Move this function to the intermediate_representation module
pub
fn
load_var_content_from_temp_var
(
tid
:
&
str
,
var
:
&
str
,
tmp_name
:
&
str
)
->
Term
<
Def
>
{
Def
::
load
(
tid
,
variable!
(
format!
(
"{}:4"
,
var
)),
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
tmp_name
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
true
,
}),
)
}
use
crate
::{
def
,
defs
,
intermediate_representation
::
*
};
fn
mock_defs_for_sprintf
(
format_known
:
bool
,
blk_num
:
usize
)
->
Vec
<
Term
<
Def
>>
{
/*
...
...
@@ -81,13 +37,13 @@ fn mock_defs_for_sprintf(format_known: bool, blk_num: usize) -> Vec<Term<Def>> {
.as_mut
(),
);
defs
.push
(
pointer_plus_offset_to_temp_var
(
defs
.push
(
Def
::
pointer_plus_offset_to_temp_var
(
&
format!
(
"def_6_blk_{}"
,
blk_num
),
"$U1050"
,
"sp"
,
0
,
));
defs
.push
(
store_var_content_at_temp_var
(
defs
.push
(
Def
::
store_var_content_at_temp_var
(
&
format!
(
"def_7_blk_{}"
,
blk_num
),
"$U1050"
,
"r12"
,
...
...
@@ -98,13 +54,13 @@ fn mock_defs_for_sprintf(format_known: bool, blk_num: usize) -> Vec<Term<Def>> {
blk_num
)]);
defs
.push
(
pointer_plus_offset_to_temp_var
(
defs
.push
(
Def
::
pointer_plus_offset_to_temp_var
(
&
format!
(
"def_9_blk_{}"
,
blk_num
),
"$U1050"
,
"sp"
,
4
,
));
defs
.push
(
store_var_content_at_temp_var
(
defs
.push
(
Def
::
store_var_content_at_temp_var
(
&
format!
(
"def_10_blk_{}"
,
blk_num
),
"$U1050"
,
"r12"
,
...
...
@@ -132,14 +88,14 @@ fn mock_defs_for_scanf(format_known: bool, blk_num: usize) -> Vec<Term<Def>> {
format!
(
"def_1_blk_{}: r0:4 = r11:4 - 0x3c:4"
,
blk_num
)
];
defs
.push
(
pointer_plus_offset_to_temp_var
(
defs
.push
(
Def
::
pointer_plus_offset_to_temp_var
(
&
format!
(
"def_2_blk_{}"
,
blk_num
),
"$U1050"
,
"sp"
,
0
,
));
defs
.push
(
store_var_content_at_temp_var
(
defs
.push
(
Def
::
store_var_content_at_temp_var
(
&
format!
(
"def_3_blk_{}"
,
blk_num
),
"$U1050"
,
"r0"
,
...
...
@@ -196,14 +152,14 @@ fn mock_defs_for_sscanf(source_known: bool, format_known: bool, blk_num: usize)
format!
(
"def_1_blk_{}: r3:4 = r11:4 - 0x96:4"
,
blk_num
)
];
defs
.push
(
pointer_plus_offset_to_temp_var
(
defs
.push
(
Def
::
pointer_plus_offset_to_temp_var
(
&
format!
(
"def_2_blk_{}"
,
blk_num
),
"$U1050"
,
"sp"
,
0
,
));
defs
.push
(
store_var_content_at_temp_var
(
defs
.push
(
Def
::
store_var_content_at_temp_var
(
&
format!
(
"def_3_blk_{}"
,
blk_num
),
"$U1050"
,
"r3"
,
...
...
@@ -214,13 +170,13 @@ fn mock_defs_for_sscanf(source_known: bool, format_known: bool, blk_num: usize)
blk_num
)]);
defs
.push
(
pointer_plus_offset_to_temp_var
(
defs
.push
(
Def
::
pointer_plus_offset_to_temp_var
(
&
format!
(
"def_5_blk_{}"
,
blk_num
),
"$U1050"
,
"sp"
,
4
,
));
defs
.push
(
store_var_content_at_temp_var
(
defs
.push
(
Def
::
store_var_content_at_temp_var
(
&
format!
(
"def_6_blk_{}"
,
blk_num
),
"$U1050"
,
"r3"
,
...
...
src/cwe_checker_lib/src/checkers/cwe_119/state.rs
View file @
decc1254
...
...
@@ -269,7 +269,7 @@ fn collect_tids_for_cwe_warning(
#[cfg(test)]
pub
mod
tests
{
use
super
::
*
;
use
crate
::
intermediate_representation
::
Variable
;
use
crate
::
{
intermediate_representation
::
*
,
variable
}
;
#[test]
fn
test_new
()
{
...
...
@@ -279,7 +279,7 @@ pub mod tests {
&
FunctionSignature
::
mock_x64
(),
context
.project
,
);
let
stack_id
=
AbstractIdentifier
::
from_var
(
Tid
::
new
(
"func"
),
&
Variable
::
mock
(
"RSP"
,
8
));
let
stack_id
=
AbstractIdentifier
::
from_var
(
Tid
::
new
(
"func"
),
&
variable!
(
"RSP:8"
));
assert_eq!
(
state
.stack_id
,
stack_id
);
assert_eq!
(
state
.object_lower_bounds
.len
(),
1
);
...
...
@@ -302,7 +302,7 @@ pub mod tests {
&
FunctionSignature
::
mock_x64
(),
context
.project
,
);
let
stack_id
=
AbstractIdentifier
::
from_var
(
Tid
::
new
(
"func"
),
&
Variable
::
mock
(
"RSP"
,
8
));
let
stack_id
=
AbstractIdentifier
::
from_var
(
Tid
::
new
(
"func"
),
&
variable!
(
"RSP:8"
));
// access in bounds
let
address
=
Data
::
from_target
(
stack_id
.clone
(),
Bitvector
::
from_i64
(
-
12
)
.into
());
assert
!
(
state
...
...
src/cwe_checker_lib/src/intermediate_representation/blk.rs
View file @
decc1254
use
super
::
*
;
use
crate
::
utils
::
log
::
LogMessage
;
use
std
::{
collections
::{
HashMap
,
HashSet
},
fmt
,
};
use
std
::{
collections
::
HashSet
,
fmt
};
/// A basic block is a sequence of `Def` instructions followed by up to two `Jmp` instructions.
///
...
...
@@ -70,131 +67,6 @@ impl Term<Blk> {
Err
(
logs
)
}
}
/// Wherever possible, substitute input variables of expressions
/// with the input expression that defines the input variable.
///
/// Note that substitution is only possible
/// if the input variables of the input expression itself did not change since the definition of said variable.
///
/// The expression propagation is used in [`expression_propagation` normalization pass](crate::analysis::expression_propagation)
/// to further simplify the generated expressions using a fixpoint algorithm
/// and allows more dead stores to be removed during [dead variable elimination](crate::analysis::dead_variable_elimination).
pub
fn
propagate_input_expressions
(
&
mut
self
,
apriori_insertable_expressions
:
Option
<
HashMap
<
Variable
,
Expression
>>
,
)
{
let
mut
insertable_expressions
=
HashMap
::
new
();
if
let
Some
(
insertables
)
=
apriori_insertable_expressions
{
insertable_expressions
=
insertables
;
}
for
def
in
self
.term.defs
.iter_mut
()
{
match
&
mut
def
.term
{
Def
::
Assign
{
var
,
value
:
expression
,
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expression
.substitute_input_var
(
input_var
,
input_expr
);
}
// expressions dependent on the assigned variable are no longer insertable
insertable_expressions
.retain
(|
input_var
,
input_expr
|
{
input_var
!=
var
&&
!
input_expr
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
});
// If the value of the assigned variable does not depend on the former value of the variable,
// then it is insertable for future expressions.
if
!
expression
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
{
insertable_expressions
.insert
(
var
.clone
(),
expression
.clone
());
}
}
Def
::
Load
{
var
,
address
:
expression
,
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expression
.substitute_input_var
(
input_var
,
input_expr
);
}
// expressions dependent on the assigned variable are no longer insertable
insertable_expressions
.retain
(|
input_var
,
input_expr
|
{
input_var
!=
var
&&
!
input_expr
.input_vars
()
.into_iter
()
.any
(|
x
|
x
==
var
)
});
}
Def
::
Store
{
address
,
value
}
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
address
.substitute_input_var
(
input_var
,
input_expr
);
value
.substitute_input_var
(
input_var
,
input_expr
);
}
}
}
}
for
jump
in
self
.term.jmps
.iter_mut
()
{
match
&
mut
jump
.term
{
Jmp
::
Branch
(
_
)
|
Jmp
::
Call
{
..
}
|
Jmp
::
CallOther
{
..
}
=>
(),
Jmp
::
BranchInd
(
expr
)
|
Jmp
::
CBranch
{
condition
:
expr
,
..
}
|
Jmp
::
CallInd
{
target
:
expr
,
..
}
|
Jmp
::
Return
(
expr
)
=>
{
// insert known input expressions
for
(
input_var
,
input_expr
)
in
insertable_expressions
.iter
()
{
expr
.substitute_input_var
(
input_var
,
input_expr
);
}
}
}
}
}
/// Merge subsequent assignments to the same variable to a single assignment to that variable.
///
/// The value expressions of merged assignments can often be simplified later on
/// in the corresponding [`Project` normalization pass](Project::normalize).
pub
fn
merge_def_assignments_to_same_var
(
&
mut
self
)
{
let
mut
new_defs
=
Vec
::
new
();
let
mut
last_def_opt
=
None
;
for
def
in
self
.term.defs
.iter
()
{
if
let
Def
::
Assign
{
var
:
current_var
,
..
}
=
&
def
.term
{
if
let
Some
(
Term
{
term
:
Def
::
Assign
{
var
:
last_var
,
value
:
last_value
,
},
..
})
=
&
last_def_opt
{
if
current_var
==
last_var
{
let
mut
substituted_def
=
def
.clone
();
substituted_def
.substitute_input_var
(
last_var
,
last_value
);
last_def_opt
=
Some
(
substituted_def
);
}
else
{
new_defs
.push
(
last_def_opt
.unwrap
());
last_def_opt
=
Some
(
def
.clone
());
}
}
else
if
last_def_opt
.is_some
()
{
panic!
();
// Only assign-defs should be saved in last_def.
}
else
{
last_def_opt
=
Some
(
def
.clone
());
}
}
else
{
if
let
Some
(
last_def
)
=
last_def_opt
{
new_defs
.push
(
last_def
);
}
new_defs
.push
(
def
.clone
());
last_def_opt
=
None
;
}
}
if
let
Some
(
last_def
)
=
last_def_opt
{
new_defs
.push
(
last_def
);
}
self
.term.defs
=
new_defs
;
}
}
impl
fmt
::
Display
for
Blk
{
...
...
@@ -208,101 +80,3 @@ impl fmt::Display for Blk {
Ok
(())
}
}
#[cfg(test)]
mod
tests
{
use
super
::
*
;
use
crate
::
intermediate_representation
::{
Def
,
Expression
,
Variable
};
impl
Blk
{
/// Creates empty block with tid "block".
pub
fn
mock
()
->
Term
<
Blk
>
{
Term
{
tid
:
Tid
::
new
(
"block"
),
term
:
Blk
{
defs
:
Vec
::
new
(),
jmps
:
Vec
::
new
(),
indirect_jmp_targets
:
Vec
::
new
(),
},
}
}
pub
fn
mock_with_tid
(
tid
:
&
str
)
->
Term
<
Blk
>
{
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Blk
{
defs
:
Vec
::
new
(),
jmps
:
Vec
::
new
(),
indirect_jmp_targets
:
Vec
::
new
(),
},
}
}
}
#[test]
fn
expression_propagation
()
{
use
crate
::
intermediate_representation
::
UnOpType
;
let
defs
=
vec!
[
Def
::
assign
(
"tid_1"
,
Variable
::
mock
(
"X"
,
8
),
Expression
::
var
(
"Y"
,
8
)
.un_op
(
UnOpType
::
IntNegate
),
),
Def
::
assign
(
"tid_2"
,
Variable
::
mock
(
"Y"
,
8
),
Expression
::
var
(
"X"
,
8
)
.plus
(
Expression
::
var
(
"Y"
,
8
)),
),
Def
::
assign
(
"tid_3"
,
Variable
::
mock
(
"X"
,
8
),
Expression
::
var
(
"X"
,
8
)
.un_op
(
UnOpType
::
IntNegate
),
),
Def
::
assign
(
"tid_4"
,
Variable
::
mock
(
"Y"
,
8
),
Expression
::
var
(
"Y"
,
8
)
.un_op
(
UnOpType
::
IntNegate
),
),
Def
::
assign
(
"tid_5"
,
Variable
::
mock
(
"Y"
,
8
),
Expression
::
var
(
"X"
,
8
)
.plus
(
Expression
::
var
(
"Y"
,
8
)),
),
];
let
mut
block
=
Term
{
tid
:
Tid
::
new
(
"block"
),
term
:
Blk
{
defs
,
jmps
:
Vec
::
new
(),
indirect_jmp_targets
:
Vec
::
new
(),
},
};
block
.merge_def_assignments_to_same_var
();
block
.propagate_input_expressions
(
None
);
let
result_defs
=
vec!
[
Def
::
assign
(
"tid_1"
,
Variable
::
mock
(
"X"
,
8
),
Expression
::
var
(
"Y"
,
8
)
.un_op
(
UnOpType
::
IntNegate
),
),
Def
::
assign
(
"tid_2"
,
Variable
::
mock
(
"Y"
,
8
),
Expression
::
var
(
"Y"
,
8
)
.un_op
(
UnOpType
::
IntNegate
)
.plus
(
Expression
::
var
(
"Y"
,
8
)),
),
Def
::
assign
(
"tid_3"
,
Variable
::
mock
(
"X"
,
8
),
Expression
::
var
(
"X"
,
8
)
.un_op
(
UnOpType
::
IntNegate
),
),
Def
::
assign
(
"tid_5"
,
Variable
::
mock
(
"Y"
,
8
),
Expression
::
var
(
"X"
,
8
)
.plus
(
Expression
::
var
(
"Y"
,
8
)
.un_op
(
UnOpType
::
IntNegate
)),
),
];
assert_eq!
(
block
.term.defs
,
result_defs
);
}
}
src/cwe_checker_lib/src/intermediate_representation/def.rs
View file @
decc1254
...
...
@@ -101,41 +101,18 @@ impl fmt::Display for Def {
#[cfg(test)]
mod
tests
{
use
super
::
*
;
use
crate
::
intermediate_representation
::
BinOpType
;
use
crate
::
{
expr
,
intermediate_representation
::
*
,
variable
}
;
#[test]
fn
zero_extension_check
()
{
let
eax_variable
=
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
"EAX"
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
false
,
});
let
int_sub_expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntSub
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
"EAX"
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
false
,
})),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
"ECX"
),
size
:
ByteSize
::
new
(
4
),
is_temp
:
false
,
})),
};
let
zero_extend_def
=
Term
{
tid
:
Tid
::
new
(
"zero_tid"
),
term
:
Def
::
Assign
{
var
:
Variable
{
name
:
String
::
from
(
"RAX"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
},
var
:
variable!
(
"RAX:8"
),
value
:
Expression
::
Cast
{
op
:
CastOpType
::
IntZExt
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
e
ax_variable
.clone
(
)),
arg
:
Box
::
new
(
e
xpr!
(
"EAX:8"
)),
},
},
};
...
...
@@ -143,15 +120,11 @@ mod tests {
let
zero_extend_but_no_var_def
=
Term
{
tid
:
Tid
::
new
(
"zero_tid"
),
term
:
Def
::
Assign
{
var
:
Variable
{
name
:
String
::
from
(
"RAX"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
},
var
:
variable!
(
"RAX:8"
),
value
:
Expression
::
Cast
{
op
:
CastOpType
::
IntZExt
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
int_sub_expr
.clone
(
)),
arg
:
Box
::
new
(
expr!
(
"EAX:8 - ECX:8"
)),
},
},
};
...
...
@@ -159,15 +132,11 @@ mod tests {
let
non_zero_extend_def
=
Term
{
tid
:
Tid
::
new
(
"zero_tid"
),
term
:
Def
::
Assign
{
var
:
Variable
{
name
:
String
::
from
(
"RAX"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
},
var
:
variable!
(
"RAX:8"
),
value
:
Expression
::
Cast
{
op
:
CastOpType
::
IntSExt
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
e
ax_variable
.clone
(
)),
arg
:
Box
::
new
(
e
xpr!
(
"EAX:8"
)),
},
},
};
...
...
src/cwe_checker_lib/src/intermediate_representation/expression/builder.rs
View file @
decc1254
#
[
cfg
(
test
)]
use
apint
::
ApInt
;
#[cfg(test)]
use
super
::{
CastOpType
,
Variable
};
use
super
::
*
;
/// ## Helper functions for building expressions
impl
Expression
{
/// Shortcut for creating a constant expression from an i64 value
#[cfg(test)]
pub
fn
const_from_i64
(
value
:
i64
)
->
Expression
{
Expression
::
Const
(
Bitvector
::
from_i64
(
value
))
}
/// Shortcut for creating a constant expression from an i32 value
#[cfg(test)]
pub
fn
const_from_i32
(
value
:
i32
)
->
Expression
{
Expression
::
Const
(
Bitvector
::
from_i32
(
value
))
}
/// Shortcut for creating a constant expression from an apint value (e.g. copy of global address)
#[cfg(test)]
pub
fn
const_from_apint
(
value
:
ApInt
)
->
Expression
{
Expression
::
Const
(
value
)
}
/// Shortcut for creating a variable expression
#[cfg(test)]
pub
fn
var
(
name
:
impl
ToString
,
size_in_bytes
:
impl
Into
<
ByteSize
>
)
->
Expression
{
Expression
::
Var
(
Variable
{
name
:
name
.to_string
(),
size
:
size_in_bytes
.into
(),
is_temp
:
false
,
})
}
/// Shortcut for creating a cast expression
#[cfg(test)]
pub
fn
cast
(
self
,
op
:
CastOpType
)
->
Expression
{
Expression
::
Cast
{
op
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
self
),
}
}
/// Shortcut for creating a subpiece expression
#[cfg(test)]
pub
fn
subpiece
(
self
,
low_byte
:
ByteSize
,
size
:
ByteSize
)
->
Expression
{
Expression
::
Subpiece
{
low_byte
,
size
,
arg
:
Box
::
new
(
self
),
}
}
/// Shortcut for creating unary operation expressions.
#[cfg(test)]
pub
fn
un_op
(
self
,
op
:
UnOpType
)
->
Expression
{
Expression
::
UnOp
{
op
,
arg
:
Box
::
new
(
self
),
}
}
/// Shortcut for creating an `IntAdd`-expression
pub
fn
plus
(
self
,
rhs
:
Expression
)
->
Expression
{
Expression
::
BinOp
{
...
...
@@ -74,16 +11,6 @@ impl Expression {
}
}
/// Shortcut for creating an `IntSub`-expression
#[cfg(test)]
pub
fn
minus
(
self
,
rhs
:
Expression
)
->
Expression
{
Expression
::
BinOp
{
lhs
:
Box
::
new
(
self
),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
rhs
),
}
}
/// Construct an expression that adds a constant value to the given expression.
///
/// The bytesize of the value is automatically adjusted to the bytesize of the given expression.
...
...
@@ -100,19 +27,4 @@ impl Expression {
}
self
.plus
(
Expression
::
Const
(
value
))
}
/// Construct an expression that subtracts a constant value from the given expression.
///
/// The bytesize of the value is automatically adjusted to the bytesize of the given expression.
#[cfg(test)]
pub
fn
minus_const
(
self
,
value
:
i64
)
->
Expression
{
let
bytesize
=
self
.bytesize
();
let
mut
value
=
Bitvector
::
from_i64
(
value
);
match
u64
::
from
(
bytesize
)
{
size
if
size
>
8
=>
value
.sign_extend
(
bytesize
)
.unwrap
(),
size
if
size
<
8
=>
value
.truncate
(
bytesize
)
.unwrap
(),
_
=>
(),
}
self
.minus
(
Expression
::
Const
(
value
))
}
}
src/cwe_checker_lib/src/intermediate_representation/expression/tests.rs
View file @
decc1254
use
super
::
*
;
use
crate
::{
expr
,
intermediate_representation
::
*
};
#[test]
fn
trivial_expression_substitution
()
{
let
rax_variable
=
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
);
let
rcx_variable
=
Expression
::
Var
(
Variable
::
mock
(
"RCX"
,
8
)
);
let
rax_variable
=
expr!
(
"RAX:8"
);
let
rcx_variable
=
expr!
(
"RCX:8"
);
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntXOr
,
lhs
:
Box
::
new
(
rax_variable
.clone
()),
rhs
:
Box
::
new
(
rax_variable
.clone
()),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
8
)
.into
()))
);
assert_eq!
(
expr
,
expr!
(
"0:8"
));
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntOr
,
lhs
:
Box
::
new
(
rax_variable
.clone
()),
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
8
)
.into
())
)),
rhs
:
Box
::
new
(
expr!
(
"0:8"
)),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
rax_variable
);
let
sub_expr
=
Expression
::
BinOp
{
lhs
:
Box
::
new
(
rax_variable
.clone
()),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
rcx_variable
.clone
()),
};
let
sub_expr
=
expr!
(
"RAX:8 - RCX:8"
);
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntEqual
,
lhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
1
)
.into
())
)),
lhs
:
Box
::
new
(
expr!
(
"0:8"
)),
rhs
:
Box
::
new
(
sub_expr
.clone
()),
};
expr
.substitute_trivial_operations
();
...
...
@@ -44,7 +38,7 @@ fn trivial_expression_substitution() {
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntNotEqual
,
lhs
:
Box
::
new
(
sub_expr
.clone
()),
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
1
)
.into
())
)),
rhs
:
Box
::
new
(
expr!
(
"0:8"
)),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
...
...
@@ -108,29 +102,29 @@ fn trivial_expression_substitution() {
arg
:
Box
::
new
(
Expression
::
Cast
{
op
:
CastOpType
::
IntSExt
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
)),
arg
:
Box
::
new
(
expr!
(
"EAX:4"
)),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
));
assert_eq!
(
expr
,
expr!
(
"EAX:4"
));
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
4
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
BinOp
{
op
:
BinOpType
::
Piece
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
)),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EBX"
,
4
)
)),
lhs
:
Box
::
new
(
expr!
(
"EAX:4"
)),
rhs
:
Box
::
new
(
expr!
(
"EBX:4"
)),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
));
assert_eq!
(
expr
,
expr!
(
"EAX:4"
));
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
2
),
size
:
ByteSize
::
new
(
6
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
arg
:
Box
::
new
(
expr!
(
"RAX:8"
)),
}),
};
expr
.substitute_trivial_operations
();
...
...
@@ -139,7 +133,7 @@ fn trivial_expression_substitution() {
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
2
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
arg
:
Box
::
new
(
expr!
(
"RAX:8"
)),
}
);
...
...
@@ -165,10 +159,10 @@ fn trivial_expression_substitution() {
lhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
rax_variable
.clone
()),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_i64
(
3
)
)),
rhs
:
Box
::
new
(
expr!
(
"3:8"
)),
}),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_i64
(
4
)
)),
rhs
:
Box
::
new
(
expr!
(
"4:8"
)),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
...
...
@@ -176,7 +170,7 @@ fn trivial_expression_substitution() {
Expression
::
BinOp
{
lhs
:
Box
::
new
(
rax_variable
.clone
()),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_i64
(
7
)
))
rhs
:
Box
::
new
(
expr!
(
"7:8"
))
}
);
}
...
...
@@ -187,17 +181,13 @@ fn test_complicated_a_less_than_b_substitution() {
use
Expression
::
*
;
let
sborrow_expr
=
BinOp
{
op
:
IntSBorrow
,
lhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
rhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RBX"
,
8
)
)),
lhs
:
Box
::
new
(
expr!
(
"RAX:8"
)),
rhs
:
Box
::
new
(
expr!
(
"RBX:8"
)),
};
let
a_minus_b_less_zero_expr
=
BinOp
{
op
:
IntSLess
,
lhs
:
Box
::
new
(
BinOp
{
op
:
IntSub
,
lhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RAX"
,
8
))),
rhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RBX"
,
8
))),
}),
rhs
:
Box
::
new
(
Const
(
Bitvector
::
from_u64
(
0
))),
lhs
:
Box
::
new
(
expr!
(
"RAX:8 - RBX:8"
)),
rhs
:
Box
::
new
(
expr!
(
"0:8"
)),
};
let
mut
expr
=
BinOp
{
op
:
IntNotEqual
,
...
...
@@ -207,19 +197,19 @@ fn test_complicated_a_less_than_b_substitution() {
expr
.substitute_trivial_operations
();
let
expected_expr
=
BinOp
{
op
:
IntSLess
,
lhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
rhs
:
Box
::
new
(
Var
(
Variable
::
mock
(
"RBX"
,
8
)
)),
lhs
:
Box
::
new
(
expr!
(
"RAX:8"
)),
rhs
:
Box
::
new
(
expr!
(
"RBX:8"
)),
};
assert_eq!
(
expr
,
expected_expr
);
}
#[test]
fn
display
()
{
let
expr
=
Expression
::
const_from_i32
(
2
);
let
expr
=
expr!
(
"2:4"
);
let
mul
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntMult
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RBP"
,
8
)
)),
lhs
:
Box
::
new
(
expr!
(
"RAX:8"
)),
rhs
:
Box
::
new
(
expr!
(
"RBP:8"
)),
};
let
expr
=
expr
.plus
(
mul
);
let
expr
=
Expression
::
UnOp
{
...
...
src/cwe_checker_lib/src/intermediate_representation/jmp.rs
View file @
decc1254
...
...
@@ -92,23 +92,3 @@ impl fmt::Display for Jmp {
}
}
}
#[cfg(test)]
pub
mod
tests
{
use
super
::
*
;
impl
Jmp
{
/// Create a mock call to a TID with the given `target` and `return_`
/// as the names of the target and return TIDs.
pub
fn
mock_call
(
target
:
&
str
,
return_
:
Option
<&
str
>
)
->
Term
<
Jmp
>
{
let
call
=
Jmp
::
Call
{
target
:
Tid
::
new
(
target
.to_string
()),
return_
:
return_
.map
(|
tid_name
|
Tid
::
new
(
tid_name
)),
};
Term
{
tid
:
Tid
::
new
(
format!
(
"call_{}"
,
target
.to_string
())),
term
:
call
,
}
}
}
}
src/cwe_checker_lib/src/intermediate_representation/macros/mod.rs
View file @
decc1254
...
...
@@ -189,7 +189,7 @@ pub mod parsing {
#[allow(dead_code)]
pub
fn
parse_expr
<
S
:
AsRef
<
str
>>
(
str
:
S
)
->
Expression
{
let
set
=
RegexSet
::
new
([
r
"^[[:alnum:]&&[^0-9]]{1}[[:alnum:]&&[^x]]?[[:alnum:]]*:[0-9]{1,2}$"
,
// Variable
r
"^[[:alnum:]&&[^0-9]]{1}[[:alnum:]&&[^x]]?[[:alnum:]
_
]*:[0-9]{1,2}$"
,
// Variable
r
"^((0x(-)?[[:alnum:]]+)|^(-)?([0-9])+)+:[0-9]+$"
,
// Constant
r
"^[^
\
+]*
\
+{1}[^
\
+]*$"
,
// BinOp (IntAdd)
r
"^[[:ascii:]]+
\
-{1} [[:ascii:]]+$"
,
// BinOp (IntSub)
...
...
src/cwe_checker_lib/src/intermediate_representation/mod.rs
View file @
decc1254
...
...
@@ -194,50 +194,6 @@ mod tests {
use
super
::
*
;
use
apint
::
BitWidth
;
impl
DatatypeProperties
{
pub
fn
mock
()
->
DatatypeProperties
{
DatatypeProperties
{
char_size
:
ByteSize
::
new
(
1
),
double_size
:
ByteSize
::
new
(
8
),
float_size
:
ByteSize
::
new
(
4
),
integer_size
:
ByteSize
::
new
(
4
),
long_double_size
:
ByteSize
::
new
(
8
),
long_long_size
:
ByteSize
::
new
(
8
),
long_size
:
ByteSize
::
new
(
4
),
pointer_size
:
ByteSize
::
new
(
8
),
short_size
:
ByteSize
::
new
(
2
),
}
}
/// Datatype sizes according to System V ABI
pub
fn
mock_x64
()
->
DatatypeProperties
{
DatatypeProperties
{
char_size
:
ByteSize
::
new
(
1
),
double_size
:
ByteSize
::
new
(
8
),
float_size
:
ByteSize
::
new
(
4
),
integer_size
:
ByteSize
::
new
(
4
),
long_double_size
:
ByteSize
::
new
(
16
),
long_long_size
:
ByteSize
::
new
(
8
),
long_size
:
ByteSize
::
new
(
8
),
pointer_size
:
ByteSize
::
new
(
8
),
short_size
:
ByteSize
::
new
(
2
),
}
}
pub
fn
mock_arm32
()
->
DatatypeProperties
{
DatatypeProperties
{
char_size
:
ByteSize
::
new
(
1
),
double_size
:
ByteSize
::
new
(
8
),
float_size
:
ByteSize
::
new
(
4
),
integer_size
:
ByteSize
::
new
(
4
),
long_double_size
:
ByteSize
::
new
(
8
),
long_long_size
:
ByteSize
::
new
(
8
),
long_size
:
ByteSize
::
new
(
4
),
pointer_size
:
ByteSize
::
new
(
4
),
short_size
:
ByteSize
::
new
(
2
),
}
}
}
#[test]
fn
check_bit_to_byte_conversion
()
{
let
bits
:
BitWidth
=
BitWidth
::
new
(
8
)
.unwrap
();
...
...
src/cwe_checker_lib/src/intermediate_representation/program.rs
View file @
decc1254
...
...
@@ -49,75 +49,3 @@ impl Program {
None
}
}
#[cfg(test)]
mod
tests
{
use
crate
::
intermediate_representation
::{
CallingConvention
,
Datatype
};
use
super
::
*
;
impl
Program
{
fn
add_extern_symbols_to_program
(
a
:
Vec
<
(
Tid
,
ExternSymbol
)
>
)
->
Program
{
Program
{
subs
:
BTreeMap
::
new
(),
extern_symbols
:
BTreeMap
::
from_iter
(
a
),
entry_points
:
BTreeSet
::
new
(),
address_base_offset
:
0x1000u64
,
}
}
/// Returns Program with malloc, free and other_function
pub
fn
mock_x64
()
->
Program
{
let
malloc
=
ExternSymbol
::
create_extern_symbol
(
"malloc"
,
CallingConvention
::
mock_x64
(),
Some
(
Datatype
::
Integer
),
Some
(
Datatype
::
Pointer
),
);
let
free
=
ExternSymbol
::
create_extern_symbol
(
"free"
,
CallingConvention
::
mock_x64
(),
Some
(
Datatype
::
Pointer
),
None
,
);
let
other_function
=
ExternSymbol
::
create_extern_symbol
(
"other_function"
,
CallingConvention
::
mock_x64
(),
None
,
None
,
);
Program
::
add_extern_symbols_to_program
(
vec!
[
(
malloc
.tid
.clone
(),
malloc
),
(
free
.tid
.clone
(),
free
),
(
other_function
.tid
.clone
(),
other_function
),
])
}
/// Returns Program with malloc, free and other_function
pub
fn
mock_arm32
()
->
Program
{
let
malloc
=
ExternSymbol
::
create_extern_symbol
(
"malloc"
,
CallingConvention
::
mock_arm32
(),
Some
(
Datatype
::
Integer
),
Some
(
Datatype
::
Pointer
),
);
let
free
=
ExternSymbol
::
create_extern_symbol
(
"free"
,
CallingConvention
::
mock_arm32
(),
Some
(
Datatype
::
Pointer
),
None
,
);
let
other_function
=
ExternSymbol
::
create_extern_symbol
(
"other_function"
,
CallingConvention
::
mock_arm32
(),
None
,
None
,
);
Program
::
add_extern_symbols_to_program
(
vec!
[
(
malloc
.tid
.clone
(),
malloc
),
(
free
.tid
.clone
(),
free
),
(
other_function
.tid
.clone
(),
other_function
),
])
}
}
}
src/cwe_checker_lib/src/intermediate_representation/project.rs
View file @
decc1254
...
...
@@ -291,75 +291,6 @@ impl Term<Jmp> {
mod
tests
{
use
super
::
*
;
impl
Project
{
/// Returns project with x64 calling convention and mocked program.
pub
fn
mock_x64
()
->
Project
{
let
mut
none_cconv_register
:
Vec
<
Variable
>
=
vec!
[
"RAX"
,
"RBX"
,
"RSP"
,
"RBP"
,
"R10"
,
"R11"
,
"R12"
,
"R13"
,
"R14"
,
"R15"
,
]
.into_iter
()
.map
(|
name
|
Variable
::
mock
(
name
,
ByteSize
::
new
(
8
)))
.collect
();
let
mut
integer_register
=
CallingConvention
::
mock_x64
()
.integer_parameter_register
;
integer_register
.append
(
&
mut
none_cconv_register
);
let
calling_conventions
:
BTreeMap
<
String
,
CallingConvention
>
=
BTreeMap
::
from
([(
"__stdcall"
.to_string
(),
CallingConvention
::
mock_x64
())]);
Project
{
program
:
Term
{
tid
:
Tid
::
new
(
"program_tid"
),
term
:
Program
::
mock_x64
(),
},
cpu_architecture
:
"x86_64"
.to_string
(),
stack_pointer_register
:
Variable
::
mock
(
"RSP"
,
8u64
),
calling_conventions
,
register_set
:
integer_register
.iter
()
.cloned
()
.collect
(),
datatype_properties
:
DatatypeProperties
::
mock_x64
(),
runtime_memory_image
:
RuntimeMemoryImage
::
mock
(),
}
}
pub
fn
mock_arm32
()
->
Project
{
let
none_cconv_4byte_register
:
Vec
<
Variable
>
=
vec!
[
"r12"
,
"r14"
,
"r15"
]
.into_iter
()
.map
(|
name
|
Variable
::
mock
(
name
,
ByteSize
::
new
(
4
)))
.collect
();
let
none_cconv_16byte_register
:
Vec
<
Variable
>
=
vec!
[
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
]
.into_iter
()
.map
(|
name
|
Variable
::
mock
(
name
,
ByteSize
::
new
(
16
)))
.collect
();
let
callee_saved_register
=
CallingConvention
::
mock_arm32
()
.callee_saved_register
;
let
integer_register
=
CallingConvention
::
mock_arm32
()
.integer_parameter_register
.into_iter
()
.chain
(
none_cconv_4byte_register
)
.chain
(
none_cconv_16byte_register
)
.chain
(
callee_saved_register
);
Project
{
program
:
Term
{
tid
:
Tid
::
new
(
"program_tid"
),
term
:
Program
::
mock_arm32
(),
},
cpu_architecture
:
"arm32"
.to_string
(),
stack_pointer_register
:
Variable
::
mock
(
"sp"
,
4u64
),
calling_conventions
:
BTreeMap
::
from
([(
"__stdcall"
.to_string
(),
CallingConvention
::
mock_arm32
(),
)]),
register_set
:
integer_register
.collect
(),
datatype_properties
:
DatatypeProperties
::
mock_arm32
(),
runtime_memory_image
:
RuntimeMemoryImage
::
mock
(),
}
}
}
#[test]
fn
retarget_nonexisting_jumps
()
{
let
mut
jmp_term
=
Term
{
...
...
src/cwe_checker_lib/src/intermediate_representation/project/propagate_control_flow.rs
View file @
decc1254
...
...
@@ -245,12 +245,13 @@ fn negate_condition(expr: Expression) -> Expression {
#[cfg(test)]
pub
mod
tests
{
use
super
::
*
;
use
crate
::{
def
,
expr
};
use
std
::
collections
::
BTreeMap
;
fn
mock_condition_block
(
name
:
&
str
,
if_target
:
&
str
,
else_target
:
&
str
)
->
Term
<
Blk
>
{
let
if_jmp
=
Jmp
::
CBranch
{
target
:
Tid
::
new
(
if_target
),
condition
:
Expression
::
Var
(
Variable
::
mock
(
"zero_flag"
,
ByteSize
::
new
(
1
))
),
condition
:
expr!
(
"zero_flag:1"
),
};
let
if_jmp
=
Term
{
tid
:
Tid
::
new
(
name
.to_string
()
+
"_jmp_if"
),
...
...
@@ -273,14 +274,8 @@ pub mod tests {
}
fn
mock_block_with_defs
(
name
:
&
str
,
return_target
:
&
str
)
->
Term
<
Blk
>
{
let
def
=
Def
::
Assign
{
var
:
Variable
::
mock
(
"r0"
,
ByteSize
::
new
(
4
)),
value
:
Expression
::
Var
(
Variable
::
mock
(
"r1"
,
ByteSize
::
new
(
4
))),
};
let
def
=
Term
{
tid
:
Tid
::
new
(
name
.to_string
()
+
"_def"
),
term
:
def
,
};
let
def
=
def!
[
format!
(
"{name}_def: r0:4 = r1:4"
)];
let
jmp
=
Jmp
::
Branch
(
Tid
::
new
(
return_target
));
let
jmp
=
Term
{
tid
:
Tid
::
new
(
name
.to_string
()
+
"_jmp"
),
...
...
src/cwe_checker_lib/src/intermediate_representation/runtime_memory_image.rs
View file @
decc1254
...
...
@@ -5,8 +5,10 @@ use goblin::{elf, Object};
/// A representation of the runtime image of a binary after being loaded into memory by the loader.
#[derive(Serialize,
Deserialize,
Debug,
PartialEq,
Eq,
Hash,
Clone)]
pub
struct
RuntimeMemoryImage
{
memory_segments
:
Vec
<
MemorySegment
>
,
is_little_endian
:
bool
,
/// Sequence of memory segments.
pub
memory_segments
:
Vec
<
MemorySegment
>
,
/// Endianness
pub
is_little_endian
:
bool
,
}
impl
RuntimeMemoryImage
{
...
...
@@ -276,108 +278,29 @@ impl RuntimeMemoryImage {
}
}
impl
RuntimeMemoryImage
{
/// Creates a mock runtime memory image with: byte series, strings and format strings.
pub
fn
mock
()
->
RuntimeMemoryImage
{
RuntimeMemoryImage
{
memory_segments
:
vec!
[
MemorySegment
{
bytes
:
[
0xb0u8
,
0xb1
,
0xb2
,
0xb3
,
0xb4
]
.to_vec
(),
base_address
:
0x1000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
MemorySegment
{
bytes
:
[
0u8
;
8
]
.to_vec
(),
base_address
:
0x2000
,
read_flag
:
true
,
write_flag
:
true
,
execute_flag
:
false
,
},
// Contains the Hello World string at byte 3002.
MemorySegment
{
bytes
:
[
0x01
,
0x02
,
0x48
,
0x65
,
0x6c
,
0x6c
,
0x6f
,
0x20
,
0x57
,
0x6f
,
0x72
,
0x6c
,
0x64
,
0x00
,
]
.to_vec
(),
base_address
:
0x3000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
MemorySegment
{
bytes
:
[
0x02
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
]
.to_vec
(),
base_address
:
0x4000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains strings: '/dev/sd%c%d' and 'cat %s'
MemorySegment
{
bytes
:
[
0x2f
,
0x64
,
0x65
,
0x76
,
0x2f
,
0x73
,
0x64
,
0x25
,
0x63
,
0x25
,
0x64
,
0x00
,
0x63
,
0x61
,
0x74
,
0x20
,
0x25
,
0x73
,
0x00
,
]
.to_vec
(),
base_address
:
0x5000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains string: 'cat %s %s %s %s' starting at the first byte.
MemorySegment
{
bytes
:
[
0x63
,
0x61
,
0x74
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x00
,
]
.to_vec
(),
base_address
:
0x6000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains string: 'str1 str2 str3 str4'
MemorySegment
{
bytes
:
[
0x73
,
0x74
,
0x72
,
0x31
,
0x20
,
0x73
,
0x74
,
0x72
,
0x32
,
0x20
,
0x73
,
0x74
,
0x72
,
0x33
,
0x20
,
0x73
,
0x74
,
0x72
,
0x34
,
0x00
,
]
.to_vec
(),
base_address
:
0x7000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
],
is_little_endian
:
true
,
}
}
}
#[cfg(test)]
mod
tests
{
use
crate
::
intermediate_representation
::{
Bitvector
,
ByteSize
,
RuntimeMemoryImage
};
use
crate
::
{
bitvec
,
intermediate_representation
::
*
};
#[test]
fn
read_endianness
()
{
let
mut
mem_image
=
RuntimeMemoryImage
::
mock
();
let
address
=
Bitvector
::
from_u32
(
0x1001
);
let
address
=
bitvec!
(
"0x1001:4"
);
assert_eq!
(
mem_image
.read
(
&
address
,
ByteSize
::
new
(
4
))
.unwrap
(),
Bitvector
::
from_u32
(
0xb4b3b2b1
)
.into
()
bitvec!
(
"0xb4b3b2b1:4"
)
.into
()
);
mem_image
.is_little_endian
=
false
;
assert_eq!
(
mem_image
.read
(
&
address
,
ByteSize
::
new
(
4
))
.unwrap
(),
Bitvector
::
from_u32
(
0xb1b2b3b4
)
.into
()
bitvec!
(
"0xb1b2b3b4:4"
)
.into
()
);
}
#[test]
fn
ro_data_pointer
()
{
let
mem_image
=
RuntimeMemoryImage
::
mock
();
let
address
=
Bitvector
::
from_u32
(
0x1002
);
let
address
=
bitvec!
(
"0x1002:4"
);
let
(
slice
,
index
)
=
mem_image
.get_ro_data_pointer_at_address
(
&
address
)
.unwrap
();
assert_eq!
(
index
,
2
);
assert_eq!
(
&
slice
[
index
..
],
&
[
0xb2u8
,
0xb3
,
0xb4
]);
...
...
@@ -389,7 +312,7 @@ mod tests {
// the byte array contains "Hello World".
let
expected_string
:
&
str
=
std
::
str
::
from_utf8
(
b
"
\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64
"
)
.unwrap
();
let
address
=
Bitvector
::
from_u32
(
0x3002
);
let
address
=
bitvec!
(
"0x3002:4"
);
assert_eq!
(
expected_string
,
mem_image
...
...
src/cwe_checker_lib/src/intermediate_representation/sub.rs
View file @
decc1254
...
...
@@ -195,232 +195,3 @@ impl CallingConvention {
register_list
}
}
#[cfg(test)]
mod
tests
{
use
super
::
*
;
impl
Sub
{
pub
fn
mock
(
name
:
impl
ToString
)
->
Term
<
Sub
>
{
Term
{
tid
:
Tid
::
new
(
name
.to_string
()),
term
:
Sub
{
name
:
name
.to_string
(),
blocks
:
Vec
::
new
(),
calling_convention
:
None
,
},
}
}
}
/// Wrapper for subpiece to model float register for argument passing
fn
create_float_register_subpiece
(
name
:
&
str
,
reg_size
:
u64
,
low_byte
:
u64
,
size
:
u64
,
)
->
Expression
{
Expression
::
subpiece
(
Expression
::
Var
(
Variable
::
mock
(
name
,
reg_size
)),
ByteSize
::
new
(
low_byte
),
ByteSize
::
new
(
size
),
)
}
impl
CallingConvention
{
/// Creates System V Calling Convention with Advanced Vector Extensions 512
pub
fn
mock_x64
()
->
CallingConvention
{
CallingConvention
{
name
:
"__stdcall"
.to_string
(),
// so that the mock is useable as standard calling convention in tests
integer_parameter_register
:
vec!
[
Variable
::
mock
(
"RDI"
,
8
),
Variable
::
mock
(
"RSI"
,
8
),
Variable
::
mock
(
"RDX"
,
8
),
Variable
::
mock
(
"RCX"
,
8
),
Variable
::
mock
(
"R8"
,
8
),
Variable
::
mock
(
"R9"
,
8
),
],
// ABI: first 8 Bytes of ZMM0-ZMM7 for float parameter
// Ghidra: first 8 Bytes of YMM0-YMM7 for float parameter
float_parameter_register
:
vec!
[
create_float_register_subpiece
(
"ZMM0"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM1"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM2"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM3"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM4"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM5"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM6"
,
64
,
0
,
8
),
create_float_register_subpiece
(
"ZMM7"
,
64
,
0
,
8
),
],
integer_return_register
:
vec!
[
Variable
::
mock
(
"RAX"
,
8
),
Variable
::
mock
(
"RDX"
,
8
)],
// ABI: XMM0-XMM1 float return register
// Ghidra: uses XMM0 only
float_return_register
:
vec!
[
create_float_register_subpiece
(
"ZMM0"
,
64
,
0
,
8
)],
callee_saved_register
:
vec!
[
Variable
::
mock
(
"RBP"
,
8
),
Variable
::
mock
(
"RBX"
,
8
),
Variable
::
mock
(
"RSP"
,
8
),
Variable
::
mock
(
"R12"
,
8
),
Variable
::
mock
(
"R13"
,
8
),
Variable
::
mock
(
"R14"
,
8
),
Variable
::
mock
(
"R15"
,
8
),
],
}
}
/// Following ARM32 ABI with MVE Extention
pub
fn
mock_arm32
()
->
CallingConvention
{
CallingConvention
{
name
:
"__stdcall"
.to_string
(),
// so that the mock is useable as standard calling convention in tests
integer_parameter_register
:
vec!
[
Variable
::
mock
(
"r0"
,
4
),
Variable
::
mock
(
"r1"
,
4
),
Variable
::
mock
(
"r2"
,
4
),
Variable
::
mock
(
"r3"
,
4
),
],
// ABI: q0-q3 used for argument passing
// Ghidra: uses q0-q1 only
float_parameter_register
:
vec!
[
create_float_register_subpiece
(
"q0"
,
16
,
0
,
4
),
create_float_register_subpiece
(
"q0"
,
16
,
4
,
4
),
create_float_register_subpiece
(
"q0"
,
16
,
8
,
4
),
create_float_register_subpiece
(
"q0"
,
16
,
12
,
4
),
create_float_register_subpiece
(
"q1"
,
16
,
0
,
4
),
create_float_register_subpiece
(
"q1"
,
16
,
4
,
4
),
create_float_register_subpiece
(
"q1"
,
16
,
8
,
4
),
create_float_register_subpiece
(
"q1"
,
16
,
12
,
4
),
],
// ABI: r0-r1 used as integer return register
// Ghidra uses r0 only
integer_return_register
:
vec!
[
Variable
::
mock
(
"r0"
,
4
),
Variable
::
mock
(
"r1"
,
4
),
Variable
::
mock
(
"r2"
,
4
),
Variable
::
mock
(
"r3"
,
4
),
],
// ABI: whole q0 used as float return
// Ghidra: uses first 8 Bytes of q0 only
float_return_register
:
vec!
[
create_float_register_subpiece
(
"q0"
,
16
,
0
,
4
)],
callee_saved_register
:
vec!
[
Variable
::
mock
(
"r4"
,
4
),
Variable
::
mock
(
"r5"
,
4
),
Variable
::
mock
(
"r6"
,
4
),
Variable
::
mock
(
"r7"
,
4
),
Variable
::
mock
(
"r8"
,
4
),
Variable
::
mock
(
"r9"
,
4
),
Variable
::
mock
(
"r10"
,
4
),
Variable
::
mock
(
"r11"
,
4
),
Variable
::
mock
(
"r13"
,
4
),
Variable
::
mock
(
"q4"
,
16
),
Variable
::
mock
(
"q5"
,
16
),
Variable
::
mock
(
"q6"
,
16
),
Variable
::
mock
(
"q7"
,
16
),
],
}
}
}
impl
Arg
{
pub
fn
mock_register
(
name
:
impl
ToString
,
size_in_bytes
:
impl
Into
<
ByteSize
>
)
->
Arg
{
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
name
.to_string
(),
size_in_bytes
)),
data_type
:
None
,
}
}
pub
fn
mock_register_with_data_type
(
name
:
impl
ToString
,
size_in_bytes
:
impl
Into
<
ByteSize
>
,
data_type
:
Option
<
Datatype
>
,
)
->
Arg
{
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
name
.to_string
(),
size_in_bytes
)),
data_type
,
}
}
pub
fn
mock_pointer_register
(
name
:
impl
ToString
,
size_in_bytes
:
impl
Into
<
ByteSize
>
,
)
->
Arg
{
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
name
.to_string
(),
size_in_bytes
)),
data_type
:
Some
(
Datatype
::
Pointer
),
}
}
}
impl
ExternSymbol
{
pub
fn
mock_x64
(
name
:
impl
ToString
)
->
ExternSymbol
{
ExternSymbol
{
tid
:
Tid
::
new
(
name
.to_string
()),
addresses
:
vec!
[
"UNKNOWN"
.to_string
()],
name
:
name
.to_string
(),
calling_convention
:
Some
(
"__stdcall"
.to_string
()),
parameters
:
vec!
[
Arg
::
mock_register
(
"RDI"
,
8
)],
return_values
:
vec!
[
Arg
::
mock_register
(
"RAX"
,
8
)],
no_return
:
false
,
has_var_args
:
false
,
}
}
pub
fn
mock_arm32
(
name
:
impl
ToString
)
->
ExternSymbol
{
ExternSymbol
{
tid
:
Tid
::
new
(
name
.to_string
()),
addresses
:
vec!
[
"UNKNOWN"
.to_string
()],
name
:
name
.to_string
(),
calling_convention
:
Some
(
"__stdcall"
.to_string
()),
parameters
:
vec!
[
Arg
::
mock_register
(
"r0"
,
4
)],
return_values
:
vec!
[
Arg
::
mock_register
(
"r0"
,
4
)],
no_return
:
false
,
has_var_args
:
false
,
}
}
pub
fn
mock_sprintf_x64
()
->
Self
{
ExternSymbol
{
tid
:
Tid
::
new
(
"sprintf"
),
addresses
:
vec!
[
"UNKNOWN"
.to_string
()],
name
:
"sprintf"
.to_string
(),
calling_convention
:
Some
(
"__stdcall"
.to_string
()),
parameters
:
vec!
[
Arg
::
mock_register
(
"RDI"
,
8
),
Arg
::
mock_register
(
"RSI"
,
8
)],
return_values
:
vec!
[
Arg
::
mock_register
(
"RAX"
,
8
)],
no_return
:
false
,
has_var_args
:
true
,
}
}
/// Returns extern symbol with argument/return register according to calling convention
pub
fn
create_extern_symbol
(
name
:
&
str
,
cconv
:
CallingConvention
,
arg_type
:
Option
<
Datatype
>
,
return_type
:
Option
<
Datatype
>
,
)
->
ExternSymbol
{
ExternSymbol
{
tid
:
Tid
::
new
(
name
),
addresses
:
vec!
[],
name
:
name
.to_string
(),
calling_convention
:
Some
(
cconv
.name
),
parameters
:
match
arg_type
{
Some
(
data_type
)
=>
{
vec!
[
Arg
::
from_var
(
cconv
.integer_parameter_register
[
0
]
.clone
(),
Some
(
data_type
),
)]
}
None
=>
vec!
[],
},
return_values
:
match
return_type
{
Some
(
data_type
)
=>
{
vec!
[
Arg
::
from_var
(
cconv
.integer_return_register
[
0
]
.clone
(),
Some
(
data_type
),
)]
}
None
=>
vec!
[],
},
no_return
:
false
,
has_var_args
:
false
,
}
}
}
}
src/cwe_checker_lib/src/intermediate_representation/term.rs
View file @
decc1254
use
crate
::
prelude
::
*
;
mod
builder
;
mod
builder_high_lvl
;
mod
builder_low_lvl
;
/// A term identifier consisting of an ID string (which is required to be unique)
/// and an address to indicate where the term is located.
...
...
src/cwe_checker_lib/src/intermediate_representation/term/builder.rs
deleted
100644 → 0
View file @
dcbdac1e
//! This module contains the implementations of various builder functions
//! for different terms.
#[cfg(test)]
use
crate
::
intermediate_representation
::{
Def
,
Expression
,
Jmp
,
Variable
};
#[cfg(test)]
use
super
::{
Term
,
Tid
};
/// ## Helper functions for building defs
#[cfg(test)]
impl
Def
{
/// Shortcut for creating a assign def
pub
fn
assign
(
tid
:
&
str
,
var
:
Variable
,
value
:
Expression
)
->
Term
<
Def
>
{
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Def
::
Assign
{
var
,
value
},
}
}
/// Shortcut for creating a load def
pub
fn
load
(
tid
:
&
str
,
var
:
Variable
,
address
:
Expression
)
->
Term
<
Def
>
{
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Def
::
Load
{
var
,
address
},
}
}
/// Shortcut for creating a store def
pub
fn
store
(
tid
:
&
str
,
address
:
Expression
,
value
:
Expression
)
->
Term
<
Def
>
{
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Def
::
Store
{
address
,
value
},
}
}
}
/// ## Helper functions for building jmps
#[cfg(test)]
impl
Jmp
{
/// Shortcut for creating a call
pub
fn
call
(
tid
:
&
str
,
target_tid
:
&
str
,
return_tid
:
Option
<&
str
>
)
->
Term
<
Jmp
>
{
let
return_tid
=
return_tid
.map
(|
tid_name
|
Tid
::
new
(
tid_name
));
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Jmp
::
Call
{
target
:
Tid
::
new
(
target_tid
),
return_
:
return_tid
,
},
}
}
/// Shortcut for creating a branch
pub
fn
branch
(
tid
:
&
str
,
target_tid
:
&
str
)
->
Term
<
Jmp
>
{
Term
{
tid
:
Tid
::
new
(
tid
),
term
:
Jmp
::
Branch
(
Tid
::
new
(
target_tid
)),
}
}
}
src/cwe_checker_lib/src/intermediate_representation/term/builder_high_lvl.rs
0 → 100644
View file @
decc1254
//! This module contains the implementations of various builder functions for
//! the higher intermediate representation [Project](crate::intermediate_representation::Expression),
//! [Program](crate::intermediate_representation::Expression)
//! and [RuntimeMemoryImage](crate::intermediate_representation::Expression).
#[cfg(test)]
use
crate
::
utils
::
binary
::
MemorySegment
;
#[cfg(test)]
use
crate
::{
intermediate_representation
::
*
,
variable
};
#[cfg(test)]
use
std
::
collections
::{
BTreeMap
,
BTreeSet
};
#[cfg(test)]
impl
RuntimeMemoryImage
{
/// Creates a mock runtime memory image with: byte series, strings and format strings.
pub
fn
mock
()
->
RuntimeMemoryImage
{
RuntimeMemoryImage
{
memory_segments
:
vec!
[
MemorySegment
{
bytes
:
[
0xb0u8
,
0xb1
,
0xb2
,
0xb3
,
0xb4
]
.to_vec
(),
base_address
:
0x1000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
MemorySegment
{
bytes
:
[
0u8
;
8
]
.to_vec
(),
base_address
:
0x2000
,
read_flag
:
true
,
write_flag
:
true
,
execute_flag
:
false
,
},
// Contains the Hello World string at byte 3002.
MemorySegment
{
bytes
:
[
0x01
,
0x02
,
0x48
,
0x65
,
0x6c
,
0x6c
,
0x6f
,
0x20
,
0x57
,
0x6f
,
0x72
,
0x6c
,
0x64
,
0x00
,
]
.to_vec
(),
base_address
:
0x3000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
MemorySegment
{
bytes
:
[
0x02
,
0x30
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
]
.to_vec
(),
base_address
:
0x4000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains strings: '/dev/sd%c%d' and 'cat %s'
MemorySegment
{
bytes
:
[
0x2f
,
0x64
,
0x65
,
0x76
,
0x2f
,
0x73
,
0x64
,
0x25
,
0x63
,
0x25
,
0x64
,
0x00
,
0x63
,
0x61
,
0x74
,
0x20
,
0x25
,
0x73
,
0x00
,
]
.to_vec
(),
base_address
:
0x5000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains string: 'cat %s %s %s %s' starting at the first byte.
MemorySegment
{
bytes
:
[
0x63
,
0x61
,
0x74
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x20
,
0x25
,
0x73
,
0x00
,
]
.to_vec
(),
base_address
:
0x6000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
// Contains string: 'str1 str2 str3 str4'
MemorySegment
{
bytes
:
[
0x73
,
0x74
,
0x72
,
0x31
,
0x20
,
0x73
,
0x74
,
0x72
,
0x32
,
0x20
,
0x73
,
0x74
,
0x72
,
0x33
,
0x20
,
0x73
,
0x74
,
0x72
,
0x34
,
0x00
,
]
.to_vec
(),
base_address
:
0x7000
,
read_flag
:
true
,
write_flag
:
false
,
execute_flag
:
false
,
},
],
is_little_endian
:
true
,
}
}
}
#[cfg(test)]
impl
Program
{
fn
add_extern_symbols_to_program
(
a
:
Vec
<
(
Tid
,
ExternSymbol
)
>
)
->
Program
{
Program
{
subs
:
BTreeMap
::
new
(),
extern_symbols
:
BTreeMap
::
from_iter
(
a
),
entry_points
:
BTreeSet
::
new
(),
address_base_offset
:
0x1000u64
,
}
}
/// Returns Program with malloc, free and other_function
pub
fn
mock_x64
()
->
Program
{
let
malloc
=
ExternSymbol
::
create_extern_symbol
(
"malloc"
,
CallingConvention
::
mock_x64
(),
Some
(
Datatype
::
Integer
),
Some
(
Datatype
::
Pointer
),
);
let
free
=
ExternSymbol
::
create_extern_symbol
(
"free"
,
CallingConvention
::
mock_x64
(),
Some
(
Datatype
::
Pointer
),
None
,
);
let
other_function
=
ExternSymbol
::
create_extern_symbol
(
"other_function"
,
CallingConvention
::
mock_x64
(),
None
,
None
,
);
Program
::
add_extern_symbols_to_program
(
vec!
[
(
malloc
.tid
.clone
(),
malloc
),
(
free
.tid
.clone
(),
free
),
(
other_function
.tid
.clone
(),
other_function
),
])
}
/// Returns Program with malloc, free and other_function
pub
fn
mock_arm32
()
->
Program
{
let
malloc
=
ExternSymbol
::
create_extern_symbol
(
"malloc"
,
CallingConvention
::
mock_arm32
(),
Some
(
Datatype
::
Integer
),
Some
(
Datatype
::
Pointer
),
);
let
free
=
ExternSymbol
::
create_extern_symbol
(
"free"
,
CallingConvention
::
mock_arm32
(),
Some
(
Datatype
::
Pointer
),
None
,
);
let
other_function
=
ExternSymbol
::
create_extern_symbol
(
"other_function"
,
CallingConvention
::
mock_arm32
(),
None
,
None
,
);
Program
::
add_extern_symbols_to_program
(
vec!
[
(
malloc
.tid
.clone
(),
malloc
),
(
free
.tid
.clone
(),
free
),
(
other_function
.tid
.clone
(),
other_function
),
])
}
}
#[cfg(test)]
impl
Project
{
/// Returns project with x64 calling convention and mocked program.
pub
fn
mock_x64
()
->
Project
{
let
mut
none_cconv_register
:
Vec
<
Variable
>
=
vec!
[
"RAX"
,
"RBX"
,
"RSP"
,
"RBP"
,
"R10"
,
"R11"
,
"R12"
,
"R13"
,
"R14"
,
"R15"
,
]
.into_iter
()
.map
(|
name
|
variable!
(
format!
(
"{name}:8"
)))
.collect
();
let
mut
integer_register
=
CallingConvention
::
mock_x64
()
.integer_parameter_register
;
integer_register
.append
(
&
mut
none_cconv_register
);
let
calling_conventions
:
BTreeMap
<
String
,
CallingConvention
>
=
BTreeMap
::
from
([(
"__stdcall"
.to_string
(),
CallingConvention
::
mock_x64
())]);
Project
{
program
:
Term
{
tid
:
Tid
::
new
(
"program_tid"
),
term
:
Program
::
mock_x64
(),
},
cpu_architecture
:
"x86_64"
.to_string
(),
stack_pointer_register
:
variable!
(
"RSP:8"
),
calling_conventions
,
register_set
:
integer_register
.iter
()
.cloned
()
.collect
(),
datatype_properties
:
DatatypeProperties
::
mock_x64
(),
runtime_memory_image
:
RuntimeMemoryImage
::
mock
(),
}
}
pub
fn
mock_arm32
()
->
Project
{
let
none_cconv_4byte_register
:
Vec
<
Variable
>
=
vec!
[
"r12"
,
"r14"
,
"r15"
]
.into_iter
()
.map
(|
name
|
variable!
(
format!
(
"{name}:4"
)))
.collect
();
let
none_cconv_16byte_register
:
Vec
<
Variable
>
=
vec!
[
"q0"
,
"q1"
,
"q2"
,
"q3"
,
"q8"
,
"q9"
,
"q10"
,
"q11"
,
"q12"
,
"q13"
,
"q14"
,
"q15"
,
]
.into_iter
()
.map
(|
name
|
variable!
(
format!
(
"{name}:16"
)))
.collect
();
let
callee_saved_register
=
CallingConvention
::
mock_arm32
()
.callee_saved_register
;
let
integer_register
=
CallingConvention
::
mock_arm32
()
.integer_parameter_register
.into_iter
()
.chain
(
none_cconv_4byte_register
)
.chain
(
none_cconv_16byte_register
)
.chain
(
callee_saved_register
);
Project
{
program
:
Term
{
tid
:
Tid
::
new
(
"program_tid"
),
term
:
Program
::
mock_arm32
(),
},
cpu_architecture
:
"arm32"
.to_string
(),
stack_pointer_register
:
variable!
(
"sp:4"
),
calling_conventions
:
BTreeMap
::
from
([(
"__stdcall"
.to_string
(),
CallingConvention
::
mock_arm32
(),
)]),
register_set
:
integer_register
.collect
(),
datatype_properties
:
DatatypeProperties
::
mock_arm32
(),
runtime_memory_image
:
RuntimeMemoryImage
::
mock
(),
}
}
}
src/cwe_checker_lib/src/intermediate_representation/term/builder_low_lvl.rs
0 → 100644
View file @
decc1254
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/intermediate_representation/variable.rs
View file @
decc1254
...
...
@@ -29,18 +29,3 @@ impl Display for Variable {
Ok
(())
}
}
#[cfg(test)]
mod
tests
{
use
super
::
*
;
impl
Variable
{
pub
fn
mock
(
name
:
impl
ToString
,
size_in_bytes
:
impl
Into
<
ByteSize
>
)
->
Variable
{
Variable
{
name
:
name
.to_string
(),
size
:
size_in_bytes
.into
(),
is_temp
:
false
,
}
}
}
}
src/cwe_checker_lib/src/pcode/subregister_substitution/tests.rs
View file @
decc1254
use
crate
::
intermediate_representation
::
CastOpType
;
use
super
::
*
;
use
crate
::{
def
,
expr
,
intermediate_representation
::
*
,
variable
};
struct
Setup
<
'a
>
{
register_map
:
HashMap
<&
'a
String
,
&
'a
RegisterProperties
>
,
...
...
@@ -61,24 +60,24 @@ impl<'a> Setup<'a> {
},
int_sub_expr
:
Expression
::
BinOp
{
op
:
BinOpType
::
IntSub
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
)),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"ECX"
,
4
)
)),
lhs
:
Box
::
new
(
expr!
(
"EAX:4"
)),
rhs
:
Box
::
new
(
expr!
(
"ECX:4"
)),
},
int_sub_subpiece_expr
:
Expression
::
BinOp
{
op
:
BinOpType
::
IntSub
,
lhs
:
Box
::
new
(
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
)),
arg
:
Box
::
new
(
expr!
(
"RAX:8"
)),
}),
rhs
:
Box
::
new
(
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RCX"
,
8
)
)),
arg
:
Box
::
new
(
expr!
(
"RCX:8"
)),
}),
},
eax_variable
:
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)
),
rax_variable
:
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
)
),
eax_variable
:
expr!
(
"EAX:4"
),
rax_variable
:
expr!
(
"RAX:8"
),
}
}
}
...
...
@@ -244,58 +243,34 @@ fn piecing_or_zero_extending() {
register_map
.insert
(
&
setup
.rcx_name
,
&
setup
.rcx_register
);
register_map
.insert
(
&
setup
.ah_name
,
&
setup
.ah_register
);
let
eax_assign
=
Term
{
tid
:
Tid
::
new
(
"eax_assign"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"EAX"
,
4
),
value
:
Expression
::
const_from_i32
(
0
),
},
};
let
load_to_eax
=
Term
{
tid
:
Tid
::
new
(
"load_to_eax"
),
term
:
Def
::
Load
{
var
:
Variable
::
mock
(
"EAX"
,
4
),
address
:
Expression
::
const_from_i64
(
0
),
},
};
let
ah_assign
=
Term
{
tid
:
Tid
::
new
(
"ah_assign"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"AH"
,
1
),
value
:
Expression
::
Const
(
Bitvector
::
from_i8
(
0
)),
},
};
let
eax_assign
=
def!
[
"eax_assign: EAX:4 = 0:4"
];
let
load_to_eax
=
def!
[
"load_to_eax: EAX:4 := Load from 0:8"
];
let
ah_assign
=
def!
[
"ah_assign: AH:1 = 0:1"
];
let
zext_eax_to_rax
=
Term
{
tid
:
Tid
::
new
(
"zext_eax_to_rax"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"RAX"
,
8
),
var
:
variable!
(
"RAX:8"
),
value
:
Expression
::
cast
(
setup
.eax_variable
.clone
(),
CastOpType
::
IntZExt
),
},
};
let
zext_ah_to_eax
=
Term
{
tid
:
Tid
::
new
(
"zext_ah_to_eax"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"EAX"
,
4
),
value
:
Expression
::
cast
(
Expression
::
Var
(
Variable
::
mock
(
"AH"
,
1
)),
CastOpType
::
IntZExt
,
),
var
:
variable!
(
"EAX:4"
),
value
:
Expression
::
cast
(
expr!
(
"AH:1"
),
CastOpType
::
IntZExt
),
},
};
let
zext_ah_to_rax
=
Term
{
tid
:
Tid
::
new
(
"zext_ah_to_rax"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"RAX"
,
8
),
value
:
Expression
::
cast
(
Expression
::
Var
(
Variable
::
mock
(
"AH"
,
1
)),
CastOpType
::
IntZExt
,
),
var
:
variable!
(
"RAX:8"
),
value
:
Expression
::
cast
(
expr!
(
"AH:1"
),
CastOpType
::
IntZExt
),
},
};
let
zext_eax_to_rcx
=
Term
{
tid
:
Tid
::
new
(
"zext_eax_to_rcx"
),
term
:
Def
::
Assign
{
var
:
Variable
::
mock
(
"RCX"
,
8
),
var
:
variable!
(
"RCX:8"
),
value
:
Expression
::
cast
(
setup
.eax_variable
.clone
(),
CastOpType
::
IntZExt
),
},
};
...
...
src/cwe_checker_lib/src/utils/arguments/tests.rs
View file @
decc1254
use
std
::
collections
::
BTreeSet
;
use
crate
::{
abstract_domain
::
IntervalDomain
,
intermediate_representation
::{
Bitvector
,
Tid
},
};
use
crate
::{
abstract_domain
::
IntervalDomain
,
expr
,
intermediate_representation
::
*
,
variable
};
use
super
::
*
;
fn
mock_pi_state
()
->
PointerInferenceState
{
PointerInferenceState
::
new
(
&
Variable
::
mock
(
"RSP"
,
8
as
u64
),
Tid
::
new
(
"func"
),
BTreeSet
::
new
(),
)
PointerInferenceState
::
new
(
&
variable!
(
"RSP:8"
),
Tid
::
new
(
"func"
),
BTreeSet
::
new
())
}
#[test]
...
...
@@ -24,20 +17,14 @@ fn test_get_variable_parameters() {
format_string_index_map
.insert
(
"sprintf"
.to_string
(),
1
);
let
global_address
=
Bitvector
::
from_str_radix
(
16
,
"5000"
)
.unwrap
();
pi_state
.set_register
(
&
Variable
::
mock
(
"RSI"
,
8
as
u64
),
&
variable!
(
"RSI:8"
),
IntervalDomain
::
new
(
global_address
.clone
(),
global_address
)
.into
(),
);
let
project
=
Project
::
mock_x64
();
let
mut
output
:
Vec
<
Arg
>
=
Vec
::
new
();
output
.push
(
Arg
::
from_var
(
Variable
::
mock
(
"RDX"
,
8
),
Some
(
Datatype
::
Char
),
));
output
.push
(
Arg
::
from_var
(
Variable
::
mock
(
"RCX"
,
8
),
Some
(
Datatype
::
Integer
),
));
output
.push
(
Arg
::
from_var
(
variable!
(
"RDX:8"
),
Some
(
Datatype
::
Char
)));
output
.push
(
Arg
::
from_var
(
variable!
(
"RCX:8"
),
Some
(
Datatype
::
Integer
)));
assert_eq!
(
output
,
...
...
@@ -50,14 +37,11 @@ fn test_get_variable_parameters() {
.unwrap
()
);
output
=
vec!
[
Arg
::
from_var
(
Variable
::
mock
(
"RDX"
,
8
),
Some
(
Datatype
::
Pointer
),
)];
output
=
vec!
[
Arg
::
from_var
(
variable!
(
"RDX:8"
),
Some
(
Datatype
::
Pointer
))];
let
global_address
=
Bitvector
::
from_str_radix
(
16
,
"500c"
)
.unwrap
();
pi_state
.set_register
(
&
Variable
::
mock
(
"RSI"
,
8
as
u64
),
&
variable!
(
"RSI:8"
),
IntervalDomain
::
new
(
global_address
.clone
(),
global_address
)
.into
(),
);
...
...
@@ -81,7 +65,7 @@ fn test_get_input_format_string() {
let
global_address
=
Bitvector
::
from_str_radix
(
16
,
"3002"
)
.unwrap
();
pi_state
.set_register
(
&
Variable
::
mock
(
"RSI"
,
8
as
u64
),
&
variable!
(
"RSI:8"
),
IntervalDomain
::
new
(
global_address
.clone
(),
global_address
)
.into
(),
);
...
...
@@ -199,19 +183,15 @@ fn test_calculate_parameter_locations() {
let
mut
expected_args
=
vec!
[
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"RDX"
,
ByteSize
::
new
(
8
))
),
expr
:
expr!
(
"RDX:8"
),
data_type
:
Some
(
Datatype
::
Integer
),
},
Arg
::
Register
{
expr
:
Expression
::
subpiece
(
Expression
::
Var
(
Variable
::
mock
(
"ZMM0"
,
64
)),
ByteSize
::
new
(
0
),
ByteSize
::
new
(
8
),
),
expr
:
Expression
::
subpiece
(
expr!
(
"ZMM0:64"
),
ByteSize
::
new
(
0
),
ByteSize
::
new
(
8
)),
data_type
:
Some
(
Datatype
::
Double
),
},
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"RCX"
,
ByteSize
::
new
(
8
))
),
expr
:
expr!
(
"RCX:8"
),
data_type
:
Some
(
Datatype
::
Pointer
),
},
];
...
...
@@ -227,15 +207,15 @@ fn test_calculate_parameter_locations() {
parameters
.push
((
"s"
.to_string
()
.into
(),
ByteSize
::
new
(
8
)));
expected_args
.push
(
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"R8"
,
ByteSize
::
new
(
8
))
),
expr
:
expr!
(
"R8:8"
),
data_type
:
Some
(
Datatype
::
Pointer
),
});
expected_args
.push
(
Arg
::
Register
{
expr
:
Expression
::
Var
(
Variable
::
mock
(
"R9"
,
ByteSize
::
new
(
8
))
),
expr
:
expr!
(
"R9:8"
),
data_type
:
Some
(
Datatype
::
Pointer
),
});
expected_args
.push
(
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"RSP"
,
8
))
.plus_const
(
8
),
address
:
expr!
(
"RSP:8 + 8:8"
),
size
:
ByteSize
::
new
(
8
),
data_type
:
Some
(
Datatype
::
Pointer
),
});
...
...
@@ -251,15 +231,10 @@ fn test_calculate_parameter_locations() {
fn
test_create_stack_arg
()
{
assert_eq!
(
Arg
::
Stack
{
address
:
Expression
::
Var
(
Variable
::
mock
(
"RSP"
,
8
))
.plus_const
(
8
),
address
:
expr!
(
"RSP:8 + 8:8"
),
size
:
ByteSize
::
new
(
8
),
data_type
:
Some
(
Datatype
::
Pointer
),
},
create_stack_arg
(
ByteSize
::
new
(
8
),
8
,
Datatype
::
Pointer
,
&
Variable
::
mock
(
"RSP"
,
8
)
),
create_stack_arg
(
ByteSize
::
new
(
8
),
8
,
Datatype
::
Pointer
,
&
variable!
(
"RSP:8"
)),
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment