Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
F
frama-c
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
frama-c
Commits
3fc7c696
Commit
3fc7c696
authored
5 years ago
by
Allan Blanchard
Browse files
Options
Downloads
Patches
Plain Diff
[Builtin] Calloc with flexible array member OK
parent
26a07366
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/plugins/builtin/basic_blocks.ml
+42
-16
42 additions, 16 deletions
src/plugins/builtin/basic_blocks.ml
src/plugins/builtin/basic_blocks.mli
+5
-1
5 additions, 1 deletion
src/plugins/builtin/basic_blocks.mli
src/plugins/builtin/stdlib/calloc.ml
+48
-30
48 additions, 30 deletions
src/plugins/builtin/stdlib/calloc.ml
with
95 additions
and
47 deletions
src/plugins/builtin/basic_blocks.ml
+
42
−
16
View file @
3fc7c696
...
...
@@ -75,8 +75,8 @@ let rec string_of_typ_aux = function
and
string_of_typ
t
=
string_of_typ_aux
(
Cil
.
unrollType
t
)
and
string_of_exp
e
=
Format
.
asprintf
"%a"
Cil_printer
.
pp_exp
e
let
size_var
t
value
=
{
l_var_info
=
make_logic_var_local
"__fc_len"
t
;
let
size_var
?
(
name_ext
=
""
)
t
value
=
{
l_var_info
=
make_logic_var_local
(
"__fc_
"
^
name_ext
^
"
len"
)
t
;
l_type
=
Some
t
;
l_tparams
=
[]
;
l_labels
=
[]
;
...
...
@@ -154,19 +154,23 @@ let sizeofpointed = function
|
Ctype
(
TPtr
(
t
,
_
))
|
Ctype
(
TArray
(
t
,
_
,
_
,
_
))
->
Cil
.
bytesSizeOf
t
|
_
->
assert
false
let
sizeof
=
function
|
Ctype
t
->
Cil
.
bytesSizeOf
t
|
_
->
assert
false
let
unroll_logic_type
=
function
|
Ctype
t
->
Ctype
(
Cil
.
unrollType
t
)
|
t
->
t
(** Features related to predicates *)
let
plet_len_div_size
?
loc
t
bytes_len
pred
=
let
plet_len_div_size
?
loc
?
name_ext
t
bytes_len
pred
=
let
sizeof
=
sizeofpointed
t
in
if
sizeof
=
1
then
pred
bytes_len
else
let
len
=
tdivide
?
loc
bytes_len
(
tinteger
?
loc
sizeof
)
in
let
len_var
=
size_var
Linteger
len
in
let
len_var
=
size_var
?
name_ext
Linteger
len
in
plet
?
loc
len_var
(
pred
(
tvar
len_var
.
l_var_info
))
let
pgeneric_valid_buffer
?
loc
validity
lbl
ptr
len
=
...
...
@@ -217,23 +221,45 @@ and pall_elems_pred ?loc depth t1 len pred =
let
t1_acc
=
taccess
?
loc
t1
tind
in
let
eq
=
punfold_pred
?
loc
depth
t1_acc
pred
in
pforall
?
loc
([
ind
]
,
(
pimplies
?
loc
(
bounds
,
eq
)))
and
pall_fields_pred
?
loc
depth
t1
ci
pred
=
let
eq
fi
=
let
lval
=
match
t1
.
term_node
with
TLval
(
lv
)
->
lv
|
_
->
assert
false
in
let
nlval
=
addTermOffsetLval
(
TField
(
fi
,
TNoOffset
))
lval
in
let
term
=
term
?
loc
(
TLval
nlval
)
(
Ctype
fi
.
ftype
)
in
punfold_pred
?
loc
depth
term
pred
in
let
eqs
=
List
.
map
eq
ci
.
cfields
in
pands
eqs
and
punfold_pred
?
loc
depth
t1
pred
=
and
punfold_pred
?
loc
?
(
dyn_len
=
None
)
depth
t1
pred
=
match
unroll_logic_type
t1
.
term_type
with
|
Ctype
(
TArray
(
_
,
Some
len
,
_
,
_
))
->
let
len
=
Logic_utils
.
expr_to_term
~
cast
:
false
len
in
|
Ctype
(
TArray
(
_
,
opt_len
,
_
,
_
))
->
let
len
=
match
opt_len
,
dyn_len
with
|
Some
len
,
None
->
Logic_utils
.
expr_to_term
~
cast
:
false
len
|
_
,
Some
len
->
len
|
None
,
None
->
assert
false
in
pall_elems_pred
?
loc
(
depth
+
1
)
t1
len
pred
|
Ctype
(
TComp
(
ci
,
_
,
_
))
->
pall_fields_pred
?
loc
depth
t1
ci
pred
|
_
->
pred
?
loc
t1
and
pall_fields_pred
?
loc
?
(
flex_mem_len
=
None
)
depth
t1
ci
pred
=
let
eq
dyn_len
fi
=
let
lval
=
match
t1
.
term_node
with
TLval
(
lv
)
->
lv
|
_
->
assert
false
in
let
nlval
=
addTermOffsetLval
(
TField
(
fi
,
TNoOffset
))
lval
in
let
term
=
term
?
loc
(
TLval
nlval
)
(
Ctype
fi
.
ftype
)
in
punfold_pred
?
loc
~
dyn_len
depth
term
pred
in
let
rec
eqs_fields
=
function
|
[
x
]
->
[
eq
flex_mem_len
x
]
|
x
::
l
->
let
x'
=
eq
None
x
in
x'
::
(
eqs_fields
l
)
|
_
->
assert
false
in
pands
(
eqs_fields
ci
.
cfields
)
let
punfold_flexible_struct_pred
?
loc
the_struct
bytes_len
pred
=
let
struct_len
=
tinteger
?
loc
(
sizeof
the_struct
.
term_type
)
in
let
ci
=
match
the_struct
.
term_type
with
|
Ctype
(
TComp
(
ci
,
_
,
_
)
as
t
)
when
Cil
.
has_flexible_array_member
t
->
ci
|
_
->
assert
false
in
let
flex_type
=
Ctype
(
Extlib
.
last
ci
.
cfields
)
.
ftype
in
let
flex_len
=
tminus
bytes_len
struct_len
in
let
pall_fields_pred
len
=
pall_fields_pred
?
loc
~
flex_mem_len
:
(
Some
len
)
0
the_struct
ci
pred
in
plet_len_div_size
?
loc
~
name_ext
:
"flex"
flex_type
flex_len
pall_fields_pred
let
pseparated_memories
?
loc
p1
len1
p2
len2
=
let
b1
=
tbuffer_range
?
loc
p1
len1
in
...
...
This diff is collapsed.
Click to expand it.
src/plugins/builtin/basic_blocks.mli
+
5
−
1
View file @
3fc7c696
...
...
@@ -49,12 +49,16 @@ val punfold_all_elems_eq: ?loc:location -> term -> term -> term -> predicate
val
punfold_all_elems_pred
:
?
loc
:
location
->
term
->
term
->
(
?
loc
:
location
->
term
->
predicate
)
->
predicate
val
punfold_flexible_struct_pred
:
?
loc
:
location
->
term
->
term
->
(
?
loc
:
location
->
term
->
predicate
)
->
predicate
val
pseparated_memories
:
?
loc
:
location
->
term
->
term
->
term
->
term
->
predicate
val
plet_len_div_size
:
?
loc
:
location
->
logic_type
->
term
->
(
term
->
predicate
)
->
predicate
?
loc
:
location
->
?
name_ext
:
string
->
logic_type
->
term
->
(
term
->
predicate
)
->
predicate
val
make_behavior
:
?
name
:
string
->
...
...
This diff is collapsed.
Click to expand it.
src/plugins/builtin/stdlib/calloc.ml
+
48
−
30
View file @
3fc7c696
...
...
@@ -27,9 +27,8 @@ open Logic_const
let
function_name
=
"calloc"
let
pset_len_to_zero
?
loc
ptr_type
len
=
let
result
=
tresult
?
loc
ptr_type
in
let
eq_value
?
loc
t
=
let
pset_len_to_zero
?
loc
alloc_type
num
size
=
let
eq_simpl_value
?
loc
t
=
let
value
=
match
t
.
term_type
with
|
Ctype
(
TPtr
(
_
))
->
term
Tnull
t
.
term_type
|
Ctype
(
TFloat
(
_
))
->
treal
?
loc
0
.
...
...
@@ -38,72 +37,91 @@ let pset_len_to_zero ?loc ptr_type len =
in
prel
?
loc
(
Req
,
t
,
value
)
in
let
p
=
punfold_all_elems_pred
?
loc
result
len
eq_value
in
let
ptr_type
=
ptr_of
alloc_type
in
let
result
=
tresult
?
loc
ptr_type
in
let
p
=
if
Cil
.
has_flexible_array_member
alloc_type
then
let
access
=
Cil
.
mkTermMem
~
addr
:
result
~
off
:
TNoOffset
in
let
access
=
term
?
loc
(
TLval
access
)
(
Ctype
alloc_type
)
in
(* Note: calloc with flexible array member assumes num == 1 *)
punfold_flexible_struct_pred
?
loc
access
size
eq_simpl_value
else
punfold_all_elems_pred
?
loc
result
num
eq_simpl_value
in
new_predicate
{
p
with
pred_name
=
[
"zero_initialization"
]
}
let
generate_requires
?
loc
alloc_typ
num
size
=
let
only_one
=
if
Cil
.
has_flexible_array_member
alloc_typ
then
let
p
=
prel
?
loc
(
Req
,
num
,
Cil
.
lone
?
loc
()
)
in
Some
(
new_predicate
{
p
with
pred_name
=
[
"only_one"
]
})
else
None
let
generate_requires
?
loc
alloc_typ
e
num
size
=
let
only_one
=
if
Cil
.
has_flexible_array_member
alloc_typ
e
then
let
p
=
prel
?
loc
(
Req
,
num
,
Cil
.
lone
?
loc
()
)
in
Some
(
new_predicate
{
p
with
pred_name
=
[
"only_one"
]
})
else
None
in
[
valid_size
?
loc
alloc_typ
size
]
@
(
Extlib
.
list_of_opt
only_one
)
[
valid_size
?
loc
alloc_typ
e
size
]
@
(
Extlib
.
list_of_opt
only_one
)
let
pinitialized_len
?
loc
ptr
_type
len
=
let
result
=
tresult
?
loc
ptr_type
in
let
pinitialized_len
?
loc
alloc
_type
num
size
=
let
result
=
tresult
?
loc
(
ptr_
of
alloc_
type
)
in
let
initialized
?
loc
t
=
pinitialized
?
loc
(
here_label
,
t
)
in
let
p
=
punfold_all_elems_pred
?
loc
result
len
initialized
in
let
p
=
if
Cil
.
has_flexible_array_member
alloc_type
then
let
access
=
Cil
.
mkTermMem
~
addr
:
result
~
off
:
TNoOffset
in
let
access
=
term
?
loc
(
TLval
access
)
(
Ctype
alloc_type
)
in
(* Note: calloc with flexible array member assumes num == 1 *)
punfold_flexible_struct_pred
?
loc
access
size
initialized
else
punfold_all_elems_pred
?
loc
result
num
initialized
in
new_predicate
{
p
with
pred_name
=
[
"initialization"
]
}
let
generate_global_assigns
loc
ptr
_type
num
size
=
let
assigns_result
=
assigns_result
~
loc
ptr_type
[
num
;
size
]
in
let
generate_global_assigns
loc
alloc
_type
num
size
=
let
assigns_result
=
assigns_result
~
loc
(
ptr_
of
alloc_
type
)
[
num
;
size
]
in
let
assigns_heap
=
assigns_heap
[
num
;
size
]
in
Writes
[
assigns_result
;
assigns_heap
]
let
make_behavior_allocation
loc
ptr_type
num
size
=
let
make_behavior_allocation
loc
alloc_type
num
size
=
let
ptr_type
=
ptr_of
alloc_type
in
let
len
=
term
~
loc
(
TBinOp
(
Mult
,
num
,
size
))
Linteger
in
let
assumes
=
[
is_allocable
~
loc
len
]
in
let
assigns
=
generate_global_assigns
loc
ptr
_type
num
size
in
let
assigns
=
generate_global_assigns
loc
alloc
_type
num
size
in
let
alloc
=
allocates_result
~
loc
ptr_type
in
let
ensures
=
[
Normal
,
fresh_result
~
loc
ptr_type
len
;
Normal
,
pset_len_to_zero
~
loc
ptr
_type
num
;
Normal
,
pinitialized_len
~
loc
ptr
_type
num
Normal
,
pset_len_to_zero
~
loc
alloc
_type
num
size
;
Normal
,
pinitialized_len
~
loc
alloc
_type
num
size
]
in
make_behavior
~
name
:
"allocation"
~
assumes
~
assigns
~
alloc
~
ensures
()
let
make_behavior_no_allocation
loc
ptr
_type
num
size
=
let
make_behavior_no_allocation
loc
alloc
_type
num
size
=
let
len
=
term
~
loc
(
TBinOp
(
Mult
,
num
,
size
))
Linteger
in
let
ptr_type
=
ptr_of
alloc_type
in
let
assumes
=
[
isnt_allocable
~
loc
len
]
in
let
assigns
=
Writes
[
assigns_result
~
loc
ptr_type
[]
]
in
let
ensures
=
[
Normal
,
null_result
~
loc
ptr_type
]
in
let
alloc
=
allocates_nothing
()
in
make_behavior
~
name
:
"no_allocation"
~
assumes
~
assigns
~
ensures
~
alloc
()
let
generate_spec
alloc_typ
{
svar
=
vi
}
loc
=
let
generate_spec
alloc_typ
e
{
svar
=
vi
}
loc
=
let
(
cnum
,
csize
)
=
match
Cil
.
getFormalsDecl
vi
with
|
[
cnum
;
csize
]
->
cnum
,
csize
|
_
->
assert
false
in
let
num
=
tlogic_coerce
~
loc
(
cvar_to_tvar
cnum
)
Linteger
in
let
size
=
tlogic_coerce
~
loc
(
cvar_to_tvar
csize
)
Linteger
in
let
requires
=
generate_requires
~
loc
alloc_typ
num
size
in
let
assigns
=
generate_global_assigns
loc
(
ptr_of
alloc_typ
)
num
size
in
let
alloc
=
allocates_result
~
loc
(
ptr_of
alloc_typ
)
in
let
requires
=
generate_requires
~
loc
alloc_typ
e
num
size
in
let
assigns
=
generate_global_assigns
loc
alloc_typ
e
num
size
in
let
alloc
=
allocates_result
~
loc
(
ptr_of
alloc_typ
e
)
in
make_funspec
[
make_behavior
~
requires
~
assigns
~
alloc
()
;
make_behavior_allocation
loc
(
ptr_of
alloc_typ
)
num
size
;
make_behavior_no_allocation
loc
(
ptr_of
alloc_typ
)
num
size
make_behavior_allocation
loc
alloc_typ
e
num
size
;
make_behavior_no_allocation
loc
alloc_typ
e
num
size
]
()
let
generate_prototype
alloc_t
=
let
name
=
function_name
^
"_"
^
(
string_of_typ
alloc_t
)
in
let
generate_prototype
alloc_t
ype
=
let
name
=
function_name
^
"_"
^
(
string_of_typ
alloc_t
ype
)
in
let
params
=
[
(
"num"
,
size_t
()
,
[]
)
;
(
"size"
,
size_t
()
,
[]
)
]
in
name
,
(
TFun
((
ptr_of
alloc_t
)
,
Some
params
,
false
,
[]
))
name
,
(
TFun
((
ptr_of
alloc_t
ype
)
,
Some
params
,
false
,
[]
))
let
well_typed_call
ret
args
=
match
ret
,
args
with
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment