Skip to content

Commit 6ac8ebb

Browse files
Value sets: fix byte extracts from structs
Pointers may be contained in any member that's included in the byte range being extracted, not just the one right at the offset that the byte extract starts from. Co-Authored-By: Petr Bauch <[email protected]>
1 parent 8f30441 commit 6ac8ebb

File tree

3 files changed

+95
-15
lines changed

3 files changed

+95
-15
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include <assert.h>
2+
#include <stdlib.h>
3+
4+
#ifdef _MSC_VER
5+
# define _Static_assert(x, m) static_assert(x, m)
6+
#endif
7+
8+
struct list;
9+
10+
typedef struct list list_nodet;
11+
12+
list_nodet fill_node(signed int depth_tag_list);
13+
14+
struct list
15+
{
16+
int datum;
17+
struct list *next;
18+
};
19+
20+
int max_depth = 2;
21+
22+
list_nodet *build_node(int depth)
23+
{
24+
if(max_depth < depth)
25+
return ((list_nodet *)NULL);
26+
else
27+
{
28+
_Static_assert(sizeof(list_nodet) == 16, "");
29+
list_nodet *result = malloc(16);
30+
31+
if(result)
32+
{
33+
*result = fill_node(depth + 1);
34+
}
35+
return result;
36+
}
37+
}
38+
39+
list_nodet fill_node(int depth)
40+
{
41+
list_nodet result;
42+
result.datum = depth;
43+
result.next = build_node(depth);
44+
return result;
45+
}
46+
47+
int main()
48+
{
49+
list_nodet *node = build_node(0);
50+
int i = 0;
51+
list_nodet *list_walker = node;
52+
for(; list_walker; list_walker = list_walker->next)
53+
{
54+
i = i + 1;
55+
}
56+
assert(i == 3);
57+
return 0;
58+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--64 --unwind 4 --unwinding-assertions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring
9+
^CONVERSION ERROR$

src/pointer-analysis/value_set.cpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -891,34 +891,47 @@ void value_sett::get_value_set_rec(
891891

892892
bool found=false;
893893

894-
exprt op1 = byte_extract_expr.op1();
895-
if(eval_pointer_offset(op1, ns))
896-
simplify(op1, ns);
897-
898-
const auto op1_offset = numeric_cast<mp_integer>(op1);
899894
const typet &op_type = ns.follow(byte_extract_expr.op().type());
900-
if(op1_offset.has_value() && op_type.id() == ID_struct)
895+
if(op_type.id() == ID_struct)
901896
{
897+
exprt offset = byte_extract_expr.offset();
898+
if(eval_pointer_offset(offset, ns))
899+
simplify(offset, ns);
900+
901+
const auto offset_int = numeric_cast<mp_integer>(offset);
902+
const auto type_size = pointer_offset_size(expr.type(), ns);
903+
902904
const struct_typet &struct_type = to_struct_type(op_type);
903905

904906
for(const auto &c : struct_type.components())
905907
{
906908
const irep_idt &name = c.get_name();
907909

908-
auto comp_offset = member_offset(struct_type, name, ns);
909-
910-
if(!comp_offset.has_value())
911-
continue;
912-
else if(*comp_offset > *op1_offset)
913-
break;
914-
else if(*comp_offset != *op1_offset)
915-
continue;
910+
if(offset_int.has_value())
911+
{
912+
auto comp_offset = member_offset(struct_type, name, ns);
913+
if(comp_offset.has_value())
914+
{
915+
if(
916+
type_size.has_value() && *offset_int + *type_size <= *comp_offset)
917+
{
918+
break;
919+
}
920+
921+
auto member_size = pointer_offset_size(c.type(), ns);
922+
if(
923+
member_size.has_value() &&
924+
*offset_int >= *comp_offset + *member_size)
925+
{
926+
continue;
927+
}
928+
}
929+
}
916930

917931
found=true;
918932

919933
member_exprt member(byte_extract_expr.op(), c);
920934
get_value_set_rec(member, dest, suffix, original_type, ns);
921-
break;
922935
}
923936
}
924937

0 commit comments

Comments
 (0)