Skip to content

Commit 26fd6ce

Browse files
Merge pull request #808 from goblint/limit_string_pointers
Limit address sets to include at most one string pointer
2 parents 948ea64 + e54e9bb commit 26fd6ce

File tree

5 files changed

+123
-9
lines changed

5 files changed

+123
-9
lines changed

conf/examples/very-precise.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
},
5656
"structs" : {
5757
"domain" : "combined-sk"
58-
}
58+
},
59+
"limit-string-addresses": false
5960
}
6061
},
6162
"exp": {

src/cdomains/lval.ml

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -178,12 +178,22 @@ struct
178178
type field = fieldinfo
179179
type idx = Idx.t
180180
module Offs = OffsetPrintable (Idx)
181+
181182
type t =
182183
| Addr of CilType.Varinfo.t * Offs.t (** Pointer to offset of a variable. *)
183184
| NullPtr (** NULL pointer. *)
184185
| UnknownPtr (** Unknown pointer. Could point to globals, heap and escaped variables. *)
185-
| StrPtr of string (** String literal pointer. *)
186+
| StrPtr of string option (** String literal pointer. [StrPtr None] abstracts any string pointer *)
186187
[@@deriving eq, ord, hash] (* TODO: StrPtr equal problematic if the same literal appears more than once *)
188+
189+
let hash x = match x with
190+
| StrPtr _ ->
191+
if GobConfig.get_bool "ana.base.limit-string-addresses" then
192+
13859
193+
else
194+
hash x
195+
| _ -> hash x
196+
187197
include Printable.Std
188198
let name () = "Normal Lvals"
189199

@@ -210,9 +220,9 @@ struct
210220
| _ -> None
211221

212222
(* strings *)
213-
let from_string x = StrPtr x
223+
let from_string x = StrPtr (Some x)
214224
let to_string = function
215-
| StrPtr x -> Some x
225+
| StrPtr (Some x) -> Some x
216226
| _ -> None
217227

218228
let rec short_offs = function
@@ -228,7 +238,8 @@ struct
228238

229239
let show = function
230240
| Addr (x, o)-> short_addr (x, o)
231-
| StrPtr x -> "\"" ^ x ^ "\""
241+
| StrPtr (Some x) -> "\"" ^ x ^ "\""
242+
| StrPtr None -> "(unknown string)"
232243
| UnknownPtr -> "?"
233244
| NullPtr -> "NULL"
234245

@@ -277,7 +288,8 @@ struct
277288
in
278289
match x with
279290
| Addr (v,o) -> AddrOf (Var v, to_cil o)
280-
| StrPtr x -> mkString x
291+
| StrPtr (Some x) -> mkString x
292+
| StrPtr None -> raise (Lattice.Unsupported "Cannot express unknown string pointer as expression.")
281293
| NullPtr -> integer 0
282294
| UnknownPtr -> raise Lattice.TopValue
283295
let rec add_offsets x y = match x with
@@ -303,24 +315,46 @@ struct
303315
module Offs = Offset (Idx)
304316

305317
let is_definite = function
306-
| NullPtr | StrPtr _ -> true
318+
| NullPtr -> true
307319
| Addr (v,o) when Offs.is_definite o -> true
308320
| _ -> false
309321

310322
let leq x y = match x, y with
311-
| StrPtr a , StrPtr b -> a = b
323+
| StrPtr _, StrPtr None -> true
324+
| StrPtr a, StrPtr b -> a = b
312325
| Addr (x,o), Addr (y,u) -> CilType.Varinfo.equal x y && Offs.leq o u
313326
| _ -> x = y
314327

315328
let drop_ints = function
316329
| Addr (x, o) -> Addr (x, Offs.drop_ints o)
317330
| x -> x
318331

332+
let join_string_ptr x y = match x, y with
333+
| None, _
334+
| _, None -> None
335+
| Some a, Some b when a = b -> Some a
336+
| Some a, Some b (* when a <> b *) ->
337+
if GobConfig.get_bool "ana.base.limit-string-addresses" then
338+
None
339+
else
340+
raise Lattice.Uncomparable
341+
342+
let meet_string_ptr x y = match x, y with
343+
| None, a
344+
| a, None -> a
345+
| Some a, Some b when a = b -> Some a
346+
| Some a, Some b (* when a <> b *) -> raise Lattice.Uncomparable
347+
319348
let merge cop x y =
320349
match x, y with
321350
| UnknownPtr, UnknownPtr -> UnknownPtr
322351
| NullPtr , NullPtr -> NullPtr
323-
| StrPtr a , StrPtr b when a=b -> StrPtr a
352+
| StrPtr a, StrPtr b ->
353+
StrPtr
354+
begin match cop with
355+
|`Join | `Widen -> join_string_ptr a b
356+
|`Meet | `Narrow -> meet_string_ptr a b
357+
end
324358
| Addr (x,o), Addr (y,u) when CilType.Varinfo.equal x y -> Addr (x, Offs.merge cop o u)
325359
| _ -> raise Lattice.Uncomparable
326360

src/util/options.schema.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,12 @@
606606
},
607607
"additionalProperties": false
608608
},
609+
"limit-string-addresses": {
610+
"title": "ana.base.limit-string-addresses",
611+
"description": "Limit abstract address sets to keep at most one distinct string pointer.",
612+
"type": "boolean",
613+
"default": true
614+
},
609615
"partition-arrays": {
610616
"title": "ana.base.partition-arrays",
611617
"type": "object",
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//PARAM: --enable ana.base.limit-string-addresses
2+
#include <stdlib.h>
3+
4+
char *unknown_function();
5+
6+
int main(){
7+
char* str = "Hello";
8+
char* str2 = "Hello";
9+
char* str3 = "hi";
10+
char* str4 = "other string";
11+
12+
// Unknown since the there may be multiple copies of the same string
13+
__goblint_check(str != str2); // UNKNOWN!
14+
15+
__goblint_check(str == str);
16+
__goblint_check(str != str3);
17+
18+
char *ptr = NULL;
19+
int top = rand();
20+
21+
if(top){
22+
ptr = str2;
23+
} else {
24+
ptr = str3;
25+
}
26+
__goblint_check(ptr == str); //UNKNOWN!
27+
28+
// This is unknown due to only keeping one string pointer in abstract address sets
29+
__goblint_check(ptr != str4); //UNKNOWN
30+
31+
char *ptr2 = unknown_function();
32+
33+
__goblint_check(ptr2 == str); //UNKNOWN!
34+
__goblint_check(ptr2 == ptr); //UNKNOWN!
35+
36+
return 0;
37+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//PARAM: --disable ana.base.limit-string-addresses
2+
#include <stdlib.h>
3+
4+
char *unknown_function();
5+
6+
int main(){
7+
char* str = "Hello";
8+
char* str2 = "Hello";
9+
char* str3 = "hi";
10+
char* str4 = "other string";
11+
12+
// Unknown since the there may be multiple copies of the same string
13+
__goblint_check(str != str2); // UNKNOWN!
14+
15+
__goblint_check(str == str);
16+
__goblint_check(str != str3);
17+
18+
char *ptr = NULL;
19+
int top = rand();
20+
21+
if(top){
22+
ptr = str2;
23+
} else {
24+
ptr = str3;
25+
}
26+
__goblint_check(ptr == str); //UNKNOWN!
27+
28+
__goblint_check(ptr != str4);
29+
30+
char *ptr2 = unknown_function();
31+
32+
__goblint_check(ptr2 == str); //UNKNOWN!
33+
__goblint_check(ptr2 == ptr); //UNKNOWN!
34+
35+
return 0;
36+
}

0 commit comments

Comments
 (0)