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
809b7ca8
Unverified
Commit
809b7ca8
authored
Jan 08, 2021
by
Melvin Klimke
Committed by
GitHub
Jan 08, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Backward analysis trait (#123)
parent
95566833
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
536 additions
and
141 deletions
+536
-141
mock_context.rs
...nalysis/backward_interprocedural_fixpoint/mock_context.rs
+126
-0
mod.rs
..._rs/src/analysis/backward_interprocedural_fixpoint/mod.rs
+0
-0
tests.rs
...s/src/analysis/backward_interprocedural_fixpoint/tests.rs
+303
-0
forward_interprocedural_fixpoint.rs
...ecker_rs/src/analysis/forward_interprocedural_fixpoint.rs
+38
-121
interprocedural_fixpoint_generic.rs
...ecker_rs/src/analysis/interprocedural_fixpoint_generic.rs
+44
-0
mod.rs
cwe_checker_rs/src/analysis/mod.rs
+3
-1
tests.rs
...hecker_rs/src/analysis/pointer_inference/context/tests.rs
+2
-2
trait_impls.rs
..._rs/src/analysis/pointer_inference/context/trait_impls.rs
+1
-1
mod.rs
cwe_checker_rs/src/analysis/pointer_inference/mod.rs
+12
-9
cwe_476.rs
cwe_checker_rs/src/checkers/cwe_476.rs
+4
-4
context.rs
cwe_checker_rs/src/checkers/cwe_476/context.rs
+3
-3
No files found.
cwe_checker_rs/src/analysis/backward_interprocedural_fixpoint/mock_context.rs
0 → 100644
View file @
809b7ca8
use
super
::
*
;
use
crate
::
analysis
::
graph
::
Graph
;
use
petgraph
::
graph
::
NodeIndex
;
use
std
::
collections
::{
HashMap
,
HashSet
};
/// Identifier for BlkStart and BlkEnd nodes
#[derive(Clone,
PartialEq,
Eq,
Hash)]
pub
enum
StartEnd
{
Start
,
End
,
}
/// A simple mock context, only containing the program cfg
#[derive(Clone)]
pub
struct
Context
<
'a
>
{
pub
graph
:
Graph
<
'a
>
,
pub
tid_to_node_index
:
HashMap
<
(
Tid
,
Tid
,
StartEnd
),
NodeIndex
>
,
}
impl
<
'a
>
Context
<
'a
>
{
pub
fn
new
(
project
:
&
'a
Project
)
->
Self
{
let
mut
graph
=
crate
::
analysis
::
graph
::
get_program_cfg
(
&
project
.program
,
HashSet
::
new
());
graph
.reverse
();
let
mut
tid_to_node_index
:
HashMap
<
(
Tid
,
Tid
,
StartEnd
),
NodeIndex
>
=
HashMap
::
new
();
for
node
in
graph
.node_indices
()
{
let
node_value
=
graph
.node_weight
(
node
)
.unwrap
();
match
node_value
{
Node
::
BlkStart
{
0
:
block
,
1
:
subroutine
,
}
=>
{
tid_to_node_index
.insert
(
(
subroutine
.tid
.clone
(),
block
.tid
.clone
(),
StartEnd
::
Start
),
node
,
);
}
Node
::
BlkEnd
{
0
:
block
,
1
:
subroutine
,
}
=>
{
tid_to_node_index
.insert
(
(
subroutine
.tid
.clone
(),
block
.tid
.clone
(),
StartEnd
::
End
),
node
,
);
}
_
=>
(),
}
}
Context
{
graph
,
tid_to_node_index
,
}
}
}
impl
<
'a
>
crate
::
analysis
::
backward_interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
type
Value
=
u64
;
fn
get_graph
(
&
self
)
->
&
Graph
<
'a
>
{
&
self
.graph
}
/// Take the minimum of two values when merging
fn
merge
(
&
self
,
val1
:
&
u64
,
val2
:
&
u64
)
->
u64
{
std
::
cmp
::
min
(
*
val1
,
*
val2
)
}
/// Increase the Def count when parsing one
fn
update_def
(
&
self
,
val
:
&
u64
,
_def
:
&
Term
<
Def
>
)
->
Option
<
u64
>
{
let
updated_value
=
*
val
+
1
;
Some
(
updated_value
)
}
/// Simply copy the value at the jumpsite
fn
update_jumpsite
(
&
self
,
value_after_jump
:
&
u64
,
_jump
:
&
Term
<
Jmp
>
,
_untaken_conditional
:
Option
<&
Term
<
Jmp
>>
,
_jumpsite
:
&
Term
<
Blk
>
,
)
->
Option
<
u64
>
{
Some
(
*
value_after_jump
)
}
/// Merge two values at the callsite if both exist
/// If there is only one, simply copy it
fn
update_callsite
(
&
self
,
target_value
:
Option
<&
u64
>
,
return_value
:
Option
<&
u64
>
,
_call
:
&
Term
<
Jmp
>
,
_return_
:
&
Term
<
Jmp
>
,
)
->
Option
<
u64
>
{
match
(
target_value
,
return_value
)
{
(
Some
(
call
),
Some
(
fall
))
=>
Some
(
self
.merge
(
call
,
fall
)),
(
Some
(
call
),
_
)
=>
Some
(
*
call
),
(
_
,
Some
(
fall
))
=>
Some
(
*
fall
),
_
=>
panic!
(
"No values to merge at callsite!"
),
}
}
/// Simply copy the value
fn
split_call_stub
(
&
self
,
combined_value
:
&
u64
)
->
Option
<
u64
>
{
Some
(
*
combined_value
)
}
/// Simply copy the value
fn
split_return_stub
(
&
self
,
combined_value
:
&
u64
)
->
Option
<
u64
>
{
Some
(
*
combined_value
)
}
/// Simply copy the value
fn
update_call_stub
(
&
self
,
value_after_call
:
&
u64
,
_call
:
&
Term
<
Jmp
>
)
->
Option
<
u64
>
{
Some
(
*
value_after_call
)
}
/// Simply copy the value
fn
specialize_conditional
(
&
self
,
value_after_jump
:
&
u64
,
_condition
:
&
Expression
,
_is_true
:
bool
,
)
->
Option
<
u64
>
{
Some
(
*
value_after_jump
)
}
}
cwe_checker_rs/src/analysis/backward_interprocedural_fixpoint/mod.rs
0 → 100644
View file @
809b7ca8
This diff is collapsed.
Click to expand it.
cwe_checker_rs/src/analysis/backward_interprocedural_fixpoint/tests.rs
0 → 100644
View file @
809b7ca8
use
crate
::{
bil
::
Bitvector
,
intermediate_representation
::
*
};
use
super
::{
create_computation
,
mock_context
,
NodeValue
};
use
mock_context
::
Context
;
use
mock_context
::
StartEnd
;
fn
mock_program
()
->
Term
<
Program
>
{
let
var
=
Variable
{
name
:
String
::
from
(
"RAX"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
};
let
value
=
Expression
::
UnOp
{
op
:
UnOpType
::
IntNegate
,
arg
:
Box
::
new
(
Expression
::
Var
(
var
.clone
())),
};
let
def_term1
=
Term
{
tid
:
Tid
::
new
(
"def1"
.to_string
()),
term
:
Def
::
Assign
{
var
:
var
.clone
(),
value
:
value
.clone
(),
},
};
let
def_term2
=
Term
{
tid
:
Tid
::
new
(
"def2"
.to_string
()),
term
:
Def
::
Assign
{
var
:
var
.clone
(),
value
:
value
.clone
(),
},
};
let
def_term3
=
Term
{
tid
:
Tid
::
new
(
"def3"
.to_string
()),
term
:
Def
::
Assign
{
var
:
var
.clone
(),
value
:
value
.clone
(),
},
};
let
def_term4
=
Term
{
tid
:
Tid
::
new
(
"def4"
.to_string
()),
term
:
Def
::
Assign
{
var
:
var
.clone
(),
value
:
value
.clone
(),
},
};
let
def_term5
=
Term
{
tid
:
Tid
::
new
(
"def5"
.to_string
()),
term
:
Def
::
Assign
{
var
:
var
.clone
(),
value
:
value
.clone
(),
},
};
let
call_term
=
Term
{
tid
:
Tid
::
new
(
"call"
.to_string
()),
term
:
Jmp
::
Call
{
target
:
Tid
::
new
(
"sub2"
),
return_
:
Some
(
Tid
::
new
(
"sub1_blk2"
)),
},
};
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
};
let
jmp
=
Jmp
::
Branch
(
Tid
::
new
(
"sub1_blk1"
));
let
jmp_term
=
Term
{
tid
:
Tid
::
new
(
"jump"
),
term
:
jmp
,
};
let
sub1_blk1
=
Term
{
tid
:
Tid
::
new
(
"sub1_blk1"
),
term
:
Blk
{
defs
:
vec!
[
def_term1
],
jmps
:
vec!
[
call_term
],
},
};
let
sub1_blk2
=
Term
{
tid
:
Tid
::
new
(
"sub1_blk2"
),
term
:
Blk
{
defs
:
vec!
[
def_term5
],
jmps
:
vec!
[
jmp_term
],
},
};
let
sub1
=
Term
{
tid
:
Tid
::
new
(
"sub1"
),
term
:
Sub
{
name
:
"sub1"
.to_string
(),
blocks
:
vec!
[
sub1_blk1
,
sub1_blk2
],
},
};
let
cond_jump
=
Jmp
::
CBranch
{
target
:
Tid
::
new
(
"sub1_blk1"
),
condition
:
Expression
::
Const
(
Bitvector
::
from_u8
(
0
)),
};
let
cond_jump_term
=
Term
{
tid
:
Tid
::
new
(
"cond_jump"
),
term
:
cond_jump
,
};
let
jump_term_2
=
Term
{
tid
:
Tid
::
new
(
"jump2"
),
term
:
Jmp
::
Branch
(
Tid
::
new
(
"sub2_blk2"
)),
};
let
sub2_blk1
=
Term
{
tid
:
Tid
::
new
(
"sub2_blk1"
),
term
:
Blk
{
defs
:
vec!
[
def_term2
,
def_term3
],
jmps
:
vec!
[
cond_jump_term
,
jump_term_2
],
},
};
let
sub2_blk2
=
Term
{
tid
:
Tid
::
new
(
"sub2_blk2"
),
term
:
Blk
{
defs
:
vec!
[
def_term4
],
jmps
:
vec!
[
return_term
],
},
};
let
sub2
=
Term
{
tid
:
Tid
::
new
(
"sub2"
),
term
:
Sub
{
name
:
"sub2"
.to_string
(),
blocks
:
vec!
[
sub2_blk1
,
sub2_blk2
],
},
};
let
program
=
Term
{
tid
:
Tid
::
new
(
"program"
),
term
:
Program
{
subs
:
vec!
[
sub1
,
sub2
],
extern_symbols
:
Vec
::
new
(),
entry_points
:
Vec
::
new
(),
},
};
program
}
#[test]
fn
backward_fixpoint
()
{
let
project
=
Project
{
program
:
mock_program
(),
cpu_architecture
:
String
::
from
(
"x86"
),
stack_pointer_register
:
Variable
{
name
:
String
::
from
(
"RSP"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
},
calling_conventions
:
Vec
::
new
(),
};
let
mock_con
=
Context
::
new
(
&
project
);
let
mut
computation
=
create_computation
(
mock_con
.clone
(),
None
);
computation
.set_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub1"
),
Tid
::
new
(
"sub1_blk1"
),
StartEnd
::
Start
))
.unwrap
(),
NodeValue
::
Value
(
0
),
);
computation
.compute_with_max_steps
(
100
);
// The fixpoint values of all 12 BlockStart/BlockEnd nodes are compared with their expected value
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub1"
),
Tid
::
new
(
"sub1_blk1"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
0
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub1"
),
Tid
::
new
(
"sub1_blk1"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
1
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub1"
),
Tid
::
new
(
"sub1_blk2"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
1
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub1"
),
Tid
::
new
(
"sub1_blk2"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
0
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub2_blk1"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
4
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub2_blk1"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
2
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub2_blk2"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
2
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub2_blk2"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
1
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub1_blk1"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
5
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub1_blk1"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
4
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub1_blk2"
),
StartEnd
::
Start
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
6
as
u64
);
assert_eq!
(
*
computation
.get_node_value
(
*
mock_con
.tid_to_node_index
.get
(
&
(
Tid
::
new
(
"sub2"
),
Tid
::
new
(
"sub1_blk2"
),
StartEnd
::
End
))
.unwrap
()
)
.unwrap
()
.unwrap_value
(),
5
as
u64
);
}
cwe_checker_rs/src/analysis/interprocedural_fixpoint.rs
→
cwe_checker_rs/src/analysis/
forward_
interprocedural_fixpoint.rs
View file @
809b7ca8
//! Creating and computing interprocedural fixpoint problems.
//! Creating and computing
forward
interprocedural fixpoint problems.
//!
//! # General notes
//!
//! This module supports computation of fixpoint problems on the control flow graphs generated by the `graph` module.
//! As of this writing, only forward analyses are possible,
//! backward analyses are not yet implemented.
//!
//! To compute a generalized fixpoint problem,
//! first construct a context object implementing the `Context`trait.
...
...
@@ -13,27 +11,11 @@
use
super
::
fixpoint
::
Context
as
GeneralFPContext
;
use
super
::
graph
::
*
;
use
super
::
interprocedural_fixpoint_generic
::
*
;
use
crate
::
intermediate_representation
::
*
;
use
crate
::
prelude
::
*
;
use
fnv
::
FnvHashMap
;
use
petgraph
::
graph
::{
EdgeIndex
,
NodeIndex
};
use
petgraph
::
graph
::
EdgeIndex
;
use
std
::
marker
::
PhantomData
;
#[derive(PartialEq,
Eq,
Serialize,
Deserialize)]
pub
enum
NodeValue
<
T
:
PartialEq
+
Eq
>
{
Value
(
T
),
CallReturnCombinator
{
call
:
Option
<
T
>
,
return_
:
Option
<
T
>
},
}
impl
<
T
:
PartialEq
+
Eq
>
NodeValue
<
T
>
{
pub
fn
unwrap_value
(
&
self
)
->
&
T
{
match
self
{
NodeValue
::
Value
(
value
)
=>
value
,
_
=>
panic!
(
"Unexpected node value type"
),
}
}
}
/// The context for an interprocedural fixpoint computation.
///
/// Basically, a `Context` object needs to contain a reference to the actual graph,
...
...
@@ -101,7 +83,7 @@ pub trait Context<'a> {
}
/// This struct is a wrapper to create a general fixpoint context out of an interprocedural fixpoint context.
struct
GeneralizedContext
<
'a
,
T
:
Context
<
'a
>>
{
pub
struct
GeneralizedContext
<
'a
,
T
:
Context
<
'a
>>
{
context
:
T
,
_phantom_graph_reference
:
PhantomData
<
Graph
<
'a
>>
,
}
...
...
@@ -114,6 +96,10 @@ impl<'a, T: Context<'a>> GeneralizedContext<'a, T> {
_phantom_graph_reference
:
PhantomData
,
}
}
pub
fn
get_context
(
&
self
)
->
&
T
{
&
self
.context
}
}
impl
<
'a
,
T
:
Context
<
'a
>>
GeneralFPContext
for
GeneralizedContext
<
'a
,
T
>
{
...
...
@@ -132,17 +118,19 @@ impl<'a, T: Context<'a>> GeneralFPContext for GeneralizedContext<'a, T> {
match
(
val1
,
val2
)
{
(
Value
(
value1
),
Value
(
value2
))
=>
Value
(
self
.context
.merge
(
value1
,
value2
)),
(
Call
Return
Combinator
{
call
:
call1
,
return_
:
return1
,
Call
Flow
Combinator
{
call
_stub
:
call1
,
interprocedural_flow
:
return1
,
},
Call
Return
Combinator
{
call
:
call2
,
return_
:
return2
,
Call
Flow
Combinator
{
call
_stub
:
call2
,
interprocedural_flow
:
return2
,
},
)
=>
CallReturnCombinator
{
call
:
merge_option
(
call1
,
call2
,
|
v1
,
v2
|
self
.context
.merge
(
v1
,
v2
)),
return_
:
merge_option
(
return1
,
return2
,
|
v1
,
v2
|
self
.context
.merge
(
v1
,
v2
)),
)
=>
CallFlowCombinator
{
call_stub
:
merge_option
(
call1
,
call2
,
|
v1
,
v2
|
self
.context
.merge
(
v1
,
v2
)),
interprocedural_flow
:
merge_option
(
return1
,
return2
,
|
v1
,
v2
|
{
self
.context
.merge
(
v1
,
v2
)
}),
},
_
=>
panic!
(
"Malformed CFG in fixpoint computation"
),
}
...
...
@@ -174,17 +162,20 @@ impl<'a, T: Context<'a>> GeneralFPContext for GeneralizedContext<'a, T> {
.context
.update_call
(
node_value
.unwrap_value
(),
call
,
&
graph
[
end_node
])
.map
(
NodeValue
::
Value
),
Edge
::
CRCallStub
=>
Some
(
NodeValue
::
Call
Return
Combinator
{
call
:
Some
(
node_value
.unwrap_value
()
.clone
()),
return_
:
None
,
Edge
::
CRCallStub
=>
Some
(
NodeValue
::
Call
Flow
Combinator
{
call
_stub
:
Some
(
node_value
.unwrap_value
()
.clone
()),
interprocedural_flow
:
None
,
}),
Edge
::
CRReturnStub
=>
Some
(
NodeValue
::
Call
Return
Combinator
{
call
:
None
,
return_
:
Some
(
node_value
.unwrap_value
()
.clone
()),
Edge
::
CRReturnStub
=>
Some
(
NodeValue
::
Call
Flow
Combinator
{
call
_stub
:
None
,
interprocedural_flow
:
Some
(
node_value
.unwrap_value
()
.clone
()),
}),
Edge
::
ReturnCombine
(
call_term
)
=>
match
node_value
{
NodeValue
::
Value
(
_
)
=>
panic!
(
"Unexpected interprocedural fixpoint graph state"
),
NodeValue
::
CallReturnCombinator
{
call
,
return_
}
=>
{
NodeValue
::
CallFlowCombinator
{
call_stub
,
interprocedural_flow
,
}
=>
{
let
return_from_block
=
match
graph
.node_weight
(
start_node
)
{
Some
(
Node
::
CallReturn
{
call
:
_
,
...
...
@@ -194,8 +185,8 @@ impl<'a, T: Context<'a>> GeneralFPContext for GeneralizedContext<'a, T> {
};
let
return_from_jmp
=
&
return_from_block
.term.jmps
[
0
];
match
self
.context
.update_return
(
return_
.as_ref
(),
call
.as_ref
(),
interprocedural_flow
.as_ref
(),
call
_stub
.as_ref
(),
call_term
,
return_from_jmp
,
)
{
...
...
@@ -221,85 +212,11 @@ impl<'a, T: Context<'a>> GeneralFPContext for GeneralizedContext<'a, T> {
}
}
/// An intermediate result of an interprocedural fixpoint computation.
///
/// The usage instructions are identical to the usage of the general fixpoint computation object,
/// except that you need to provide an interprocedural context object instead of a general one.
pub
struct
Computation
<
'a
,
T
:
Context
<
'a
>>
{
generalized_computation
:
super
::
fixpoint
::
Computation
<
GeneralizedContext
<
'a
,
T
>>
,
}
impl
<
'a
,
T
:
Context
<
'a
>>
Computation
<
'a
,
T
>
{
/// Generate a new computation from the corresponding context and an optional default value for nodes.
pub
fn
new
(
problem
:
T
,
default_value
:
Option
<
T
::
Value
>
)
->
Self
{
let
generalized_problem
=
GeneralizedContext
::
new
(
problem
);
let
computation
=
super
::
fixpoint
::
Computation
::
new
(
generalized_problem
,
default_value
.map
(
NodeValue
::
Value
),
);
Computation
{
generalized_computation
:
computation
,
}
}
/// Compute the fixpoint.
/// Note that this function does not terminate if the fixpoint algorithm does not stabilize.
pub
fn
compute
(
&
mut
self
)
{
self
.generalized_computation
.compute
()
}
/// Compute the fixpoint while updating each node at most max_steps times.
/// Note that the result may not be a stabilized fixpoint, but only an intermediate result of a fixpoint computation.
pub
fn
compute_with_max_steps
(
&
mut
self
,
max_steps
:
u64
)
{
self
.generalized_computation
.compute_with_max_steps
(
max_steps
)
}
/// Get the value of a node.
pub
fn
get_node_value
(
&
self
,
node
:
NodeIndex
)
->
Option
<&
NodeValue
<
T
::
Value
>>
{
self
.generalized_computation
.get_node_value
(
node
)
}
/// Set the value of a node and mark the node as not yet stabilized
pub
fn
set_node_value
(
&
mut
self
,
node
:
NodeIndex
,
value
:
NodeValue
<
T
::
Value
>
)
{
self
.generalized_computation
.set_node_value
(
node
,
value
)
}
/// Get a reference to the internal map where one can look up the current values of all nodes
pub
fn
node_values
(
&
self
)
->
&
FnvHashMap
<
NodeIndex
,
NodeValue
<
T
::
Value
>>
{
self
.generalized_computation
.node_values
()
}
/// Get a reference to the underlying graph
pub
fn
get_graph
(
&
self
)
->
&
Graph
{
self
.generalized_computation
.get_graph
()
}
/// Get a reference to the underlying context object
pub
fn
get_context
(
&
self
)
->
&
T
{
&
self
.generalized_computation
.get_context
()
.context
}
/// Returns `True` if the computation has stabilized, i.e. the internal worklist is empty.
pub
fn
has_stabilized
(
&
self
)
->
bool
{
self
.generalized_computation
.has_stabilized
()
}
/// Return a list of all nodes which are marked as not-stabilized
pub
fn
get_worklist
(
&
self
)
->
Vec
<
NodeIndex
>
{
self
.generalized_computation
.get_worklist
()
}
}
/// Helper function to merge to values wrapped in `Option<..>`.
/// Merges `(Some(x), None)` to `Some(x)`.
fn
merge_option
<
T
:
Clone
,
F
>
(
opt1
:
&
Option
<
T
>
,
opt2
:
&
Option
<
T
>
,
merge
:
F
)
->
Option
<
T
>
where
F
:
Fn
(
&
T
,
&
T
)
->
T
,
{
match
(
opt1
,
opt2
)
{
(
Some
(
value1
),
Some
(
value2
))
=>
Some
(
merge
(
value1
,
value2
)),
(
Some
(
value
),
None
)
|
(
None
,
Some
(
value
))
=>
Some
(
value
.clone
()),
(
None
,
None
)
=>
None
,
}
/// Generate a new computation from the corresponding context and an optional default value for nodes.
pub
fn
create_computation
<
'a
,
T
:
Context
<
'a
>>
(
problem
:
T
,
default_value
:
Option
<
T
::
Value
>
,
)
->
super
::
fixpoint
::
Computation
<
GeneralizedContext
<
'a
,
T
>>
{
let
generalized_problem
=
GeneralizedContext
::
new
(
problem
);
super
::
fixpoint
::
Computation
::
new
(
generalized_problem
,
default_value
.map
(
NodeValue
::
Value
))
}
cwe_checker_rs/src/analysis/interprocedural_fixpoint_generic.rs
0 → 100644
View file @
809b7ca8
use
crate
::
prelude
::
*
;
/// NodeValue that can either be a single abstract value or a
/// composition of the abstract value computed following an interprocedural
/// call in the graph and of the abstract value when the call is not taken.
/// The CallFlowCombinator then allows for a merge of the values computed
/// over both paths.
///
/// The call_stub value will either be transferred from the callsite to the return site
/// in a forward analysis or the other way around in a backward analysis.
///
/// The interprocedural_flow value will either be transferred from the end of the called subroutine
/// to the return site in case of a forward analysis or from the beginning of the called subroutine
/// to the callsite in a backward analysis.
#[derive(PartialEq,
Eq,
Serialize,
Deserialize)]
pub
enum
NodeValue
<
T
:
PartialEq
+
Eq
>
{
Value
(
T
),
CallFlowCombinator
{
call_stub
:
Option
<
T
>
,
interprocedural_flow
:
Option
<
T
>
,
},
}
impl
<
T
:
PartialEq
+
Eq
>
NodeValue
<
T
>
{
pub
fn
unwrap_value
(
&
self
)
->
&
T
{
match
self
{
NodeValue
::
Value
(
value
)
=>
value
,
_
=>
panic!
(
"Unexpected node value type"
),
}
}
}
/// Helper function to merge to values wrapped in `Option<..>`.
/// Merges `(Some(x), None)` to `Some(x)`.
pub
fn
merge_option
<
T
:
Clone
,
F
>
(
opt1
:
&
Option
<
T
>
,
opt2
:
&
Option
<
T
>
,
merge
:
F
)
->
Option
<
T
>
where
F
:
Fn
(
&
T
,
&
T
)
->
T
,
{
match
(
opt1
,
opt2
)
{
(
Some
(
value1
),
Some
(
value2
))
=>
Some
(
merge
(
value1
,
value2
)),
(
Some
(
value
),
None
)
|
(
None
,
Some
(
value
))
=>
Some
(
value
.clone
()),
(
None
,
None
)
=>
None
,
}
}
cwe_checker_rs/src/analysis/mod.rs
View file @
809b7ca8
pub
mod
backward_interprocedural_fixpoint
;
pub
mod
fixpoint
;
pub
mod
forward_interprocedural_fixpoint
;
pub
mod
graph
;
pub
mod
interprocedural_fixpoint
;
pub
mod
interprocedural_fixpoint
_generic
;
pub
mod
pointer_inference
;
cwe_checker_rs/src/analysis/pointer_inference/context/tests.rs
View file @
809b7ca8
...
...
@@ -103,7 +103,7 @@ fn mock_project() -> (Project, Config) {
#[test]
fn
context_problem_implementation
()
{
use
crate
::
analysis
::
interprocedural_fixpoint
::
Context
as
IpFpContext
;
use
crate
::
analysis
::
forward_
interprocedural_fixpoint
::
Context
as
IpFpContext
;
use
crate
::
analysis
::
pointer_inference
::
Data
;
use
Expression
::
*
;
...
...
@@ -266,7 +266,7 @@ fn context_problem_implementation() {
#[test]
fn
update_return
()
{
use
crate
::
analysis
::
interprocedural_fixpoint
::
Context
as
IpFpContext
;
use
crate
::
analysis
::
forward_
interprocedural_fixpoint
::
Context
as
IpFpContext
;
use
crate
::
analysis
::
pointer_inference
::
object
::
ObjectType
;
use
crate
::
analysis
::
pointer_inference
::
Data
;
let
(
project
,
config
)
=
mock_project
();
...
...
cwe_checker_rs/src/analysis/pointer_inference/context/trait_impls.rs
View file @
809b7ca8
use
super
::
*
;
impl
<
'a
>
crate
::
analysis
::
interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
impl
<
'a
>
crate
::
analysis
::
forward_
interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
type
Value
=
State
;
/// Get the underlying graph on which the analysis operates.
...
...
cwe_checker_rs/src/analysis/pointer_inference/mod.rs
View file @
809b7ca8
...
...
@@ -13,7 +13,9 @@
//!
//! See the `Config` struct for configurable analysis parameters.
use
super
::
interprocedural_fixpoint
::{
Computation
,
NodeValue
};
use
super
::
fixpoint
::
Computation
;
use
super
::
forward_interprocedural_fixpoint
::
GeneralizedContext
;
use
super
::
interprocedural_fixpoint_generic
::
NodeValue
;
use
crate
::
abstract_domain
::{
BitvectorDomain
,
DataDomain
};
use
crate
::
analysis
::
graph
::{
Graph
,
Node
};
use
crate
::
intermediate_representation
::
*
;
...
...
@@ -59,7 +61,7 @@ pub struct Config {
/// A wrapper struct for the pointer inference computation object.
pub
struct
PointerInference
<
'a
>
{
computation
:
Computation
<
'a
,
Context
<
'a
>>
,
computation
:
Computation
<
GeneralizedContext
<
'a
,
Context
<
'a
>
>>
,
log_collector
:
crossbeam_channel
::
Sender
<
LogThreadMsg
>
,
pub
collected_logs
:
(
Vec
<
LogMessage
>
,
Vec
<
CweWarning
>
),
}
...
...
@@ -107,7 +109,7 @@ impl<'a> PointerInference<'a> {
})
.collect
();
let
mut
fixpoint_computation
=
super
::
interprocedural_fixpoint
::
Computation
::
new
(
context
,
None
);
super
::
forward_interprocedural_fixpoint
::
create_computation
(
context
,
None
);
let
_
=
log_sender
.send
(
LogThreadMsg
::
Log
(
LogMessage
::
new_debug
(
format!
(
"Pointer Inference: Adding {} entry points"
,
entry_sub_to_entry_node_map
.len
()
...
...
@@ -115,7 +117,7 @@ impl<'a> PointerInference<'a> {
for
(
sub_tid
,
start_node_index
)
in
entry_sub_to_entry_node_map
.into_iter
()
{
fixpoint_computation
.set_node_value
(
start_node_index
,
super
::
interprocedural_fixpoint
::
NodeValue
::
Value
(
State
::
new
(
super
::
interprocedural_fixpoint
_generic
::
NodeValue
::
Value
(
State
::
new
(
&
project
.stack_pointer_register
,
sub_tid
,
)),
...
...
@@ -175,7 +177,7 @@ impl<'a> PointerInference<'a> {
}
pub
fn
get_context
(
&
self
)
->
&
Context
{
self
.computation
.get_context
()
self
.computation
.get_context
()
.get_context
()
}
pub
fn
get_node_value
(
&
self
,
node_id
:
NodeIndex
)
->
Option
<&
NodeValue
<
State
>>
{
...
...
@@ -235,7 +237,7 @@ impl<'a> PointerInference<'a> {
.clone
();
self
.computation
.set_node_value
(
entry
,
super
::
interprocedural_fixpoint
::
NodeValue
::
Value
(
State
::
new
(
super
::
interprocedural_fixpoint
_generic
::
NodeValue
::
Value
(
State
::
new
(
&
project
.stack_pointer_register
,
sub_tid
,
)),
...
...
@@ -363,9 +365,10 @@ impl<'a> PointerInference<'a> {
}
Node
::
CallReturn
{
call
,
return_
}
=>
{
let
(
call_state
,
return_state
)
=
match
node_value
{
NodeValue
::
CallReturnCombinator
{
call
,
return_
}
=>
{
(
call
.is_some
(),
return_
.is_some
())
}
NodeValue
::
CallFlowCombinator
{
call_stub
,
interprocedural_flow
,
}
=>
(
call_stub
.is_some
(),
interprocedural_flow
.is_some
()),
_
=>
panic!
(),
};
println!
(
...
...
cwe_checker_rs/src/checkers/cwe_476.rs
View file @
809b7ca8
...
...
@@ -36,10 +36,10 @@
//! - For functions with more than one return value we do not distinguish between
//! the return values.
use
crate
::
analysis
::
forward_interprocedural_fixpoint
::
create_computation
;
use
crate
::
analysis
::
forward_interprocedural_fixpoint
::
Context
as
_
;
use
crate
::
analysis
::
graph
::{
Edge
,
Node
};
use
crate
::
analysis
::
interprocedural_fixpoint
::
Computation
;
use
crate
::
analysis
::
interprocedural_fixpoint
::
Context
as
_
;
use
crate
::
analysis
::
interprocedural_fixpoint
::
NodeValue
;
use
crate
::
analysis
::
interprocedural_fixpoint_generic
::
NodeValue
;
use
crate
::
intermediate_representation
::
*
;
use
crate
::
prelude
::
*
;
use
crate
::
utils
::
log
::{
CweWarning
,
LogMessage
};
...
...
@@ -102,7 +102,7 @@ pub fn check_cwe(
Some
(
NodeValue
::
Value
(
val
))
=>
Some
(
val
.clone
()),
_
=>
None
,
};
let
mut
computation
=
Computation
::
new
(
context
,
None
);
let
mut
computation
=
create_computation
(
context
,
None
);
computation
.set_node_value
(
node
,
NodeValue
::
Value
(
State
::
new
(
...
...
cwe_checker_rs/src/checkers/cwe_476/context.rs
View file @
809b7ca8
...
...
@@ -2,9 +2,9 @@ use super::State;
use
super
::
Taint
;
use
super
::
CWE_MODULE
;
use
crate
::
abstract_domain
::
AbstractDomain
;
use
crate
::
analysis
::
forward_interprocedural_fixpoint
::
Context
as
_
;
use
crate
::
analysis
::
graph
::{
Graph
,
Node
};
use
crate
::
analysis
::
interprocedural_fixpoint
::
Context
as
_
;
use
crate
::
analysis
::
interprocedural_fixpoint
::
NodeValue
;
use
crate
::
analysis
::
interprocedural_fixpoint_generic
::
NodeValue
;
use
crate
::
analysis
::
pointer_inference
::
PointerInference
as
PointerInferenceComputation
;
use
crate
::
analysis
::
pointer_inference
::
State
as
PointerInferenceState
;
use
crate
::
intermediate_representation
::
*
;
...
...
@@ -251,7 +251,7 @@ impl<'a> Context<'a> {
}
}
impl
<
'a
>
crate
::
analysis
::
interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
impl
<
'a
>
crate
::
analysis
::
forward_
interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
type
Value
=
State
;
/// Get the underlying graph of the fixpoint computation
...
...
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