method vstmt_aux s =
let preaction s = match s.skind with
| If(e,tbl,fbl,_loc) ->
begin match destruct_string_test e with _,None -> ()
| test_to_null,Some(neg,v,off) ->
if hasAttribute name_of_string_declspec (typeAttrs v.vtype)
then
(* A string should be tested within its bounds, and
depending on the result, the offset is either before
or equal to the length of the string *)
let off =
!Db.Properties.Interp.force_exp_to_term locUnknown off
in
let rel1 = within_bounds ~strict:true v off in
let supst = mkStmt(Instr(Skip(CurrentLoc.get()))) in
Annotations.add_alarm
supst ~before:true Alarms.Other_alarm rel1;
let rel2 = reach_upper_bound ~loose:false v off in
let eqst = mkStmt(Instr(Skip(CurrentLoc.get()))) in
Annotations.add_alarm
eqst ~before:true Alarms.Other_alarm rel2;
(* Rather add skip statement as blocks may be empty *)
if neg then
begin
fbl.bstmts <- supst :: fbl.bstmts;
if test_to_null then tbl.bstmts <- eqst :: tbl.bstmts
end
else
begin
tbl.bstmts <- supst :: tbl.bstmts;
if test_to_null then fbl.bstmts <- eqst :: fbl.bstmts
end
end; s
| Instr(Set(lv,e,_loc)) when is_null_expr e ->
if Jessie_options.HintLevel.get () > 1 then
match lval_destruct_string_access ~through_tmp:true lv with
| None -> ()
| Some(v,off) ->
let off =
!Db.Properties.Interp.force_exp_to_term locUnknown off
in
(* Help ATP with proving the bound on [strlen(v)] by
asserting the obvious equality *)
let lv' = !Db.Properties.Interp.force_lval_to_term_lval
locUnknown lv
in
let e' = !Db.Properties.Interp.force_exp_to_term
locUnknown e
in
let lvt = mkterm (TLval lv') strlen_type locUnknown in
let rel =
Logic_const.new_predicate (Logic_const.prel (Req,lvt,e'))
in
let prel = Logic_const.pred_of_id_pred
{ rel with ip_name = [ name_of_hint_assertion ] }
in
Annotations.add_alarm
s ~before:false Alarms.Other_alarm prel;
(* Further help ATP by asserting that index should be
positive *)
(* let rel = *)
(* Logic_const.new_predicate *)
(* (Logic_const.prel (Rle,lzero(),off)) *)
(* in *)
(* let prel = Logic_const.pred_of_id_pred *)
(* { rel with ip_name = [ name_of_hint_assertion ] } *)
(* in *)
(* Annotations.add_alarm *)
(* s ~before:false Alarms.Other_alarm prel; *)
(* If setting a character to zero in a buffer, this should
be the new length of a string *)
let rel = reach_upper_bound ~loose:true v off in
Annotations.add_alarm
s ~before:false Alarms.Other_alarm rel
else ();
s
| Instr(Set((Var v1,NoOffset),e,_loc)) ->
begin match
destruct_string_access ~through_tmp:true ~through_cast:true e
with
| None -> ()
| Some(v2,off) -> VarinfoHashtbl.add temps v1 (v2,off)
end; s
| _ -> s
in
ChangeDoChildrenPost(preaction s,fun x -> x)