Skip to content

Commit c674ce7

Browse files
author
Daniel Kroening
authored
Merge pull request #1007 from thk123/bugfix/irrelevant-const-removal
Fix irrelevant loss of const throwing off the const analysis
2 parents 5f7ff99 + fcd4e42 commit c674ce7

File tree

9 files changed

+1092
-28
lines changed

9 files changed

+1092
-28
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#include <stdio.h>
2+
3+
void f1 (void) { printf("%i\n", 1); }
4+
void f2 (void) { printf("%i\n", 2); }
5+
void f3 (void) { printf("%i\n", 3); }
6+
void f4 (void) { printf("%i\n", 4); }
7+
void f5 (void) { printf("%i\n", 5); }
8+
void f6 (void) { printf("%i\n", 6); }
9+
void f7 (void) { printf("%i\n", 7); }
10+
void f8 (void) { printf("%i\n", 8); }
11+
void f9 (void) { printf("%i\n", 9); }
12+
13+
typedef void(*void_fp)(void);
14+
15+
// There is a basic check that excludes all functions that aren't used anywhere
16+
// This ensures that check can't work in this example
17+
const void_fp fp_all[] = {f1, f2 ,f3, f4, f5 ,f6, f7, f8, f9};
18+
19+
const int const_number=4;
20+
21+
void func()
22+
{
23+
// Here we 'lose' const-ness except it is a copy so we shouldn't care
24+
int non_const_number=const_number;
25+
const void_fp fp = f2;
26+
27+
28+
// Here also we lose const-ness except it is a copy of pointer so we
29+
// shouldn't care
30+
const void_fp * const p2fp = &f2;
31+
const void_fp * p2fp_non_const = &p2fp;
32+
33+
fp();
34+
}
35+
36+
int main()
37+
{
38+
func();
39+
40+
return 0;
41+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
CORE
2+
main.c
3+
--show-goto-functions --verbosity 10 --pointer-check
4+
^Removing function pointers and virtual functions$
5+
^\s*f2\(\);
6+
--
7+
^warning: ignoring
8+
^\s*\d+:\s*f1\(\);
9+
^\s*\d+:\s*f3\(\);
10+
^\s*\d+:\s*f4\(\);
11+
^\s*\d+:\s*f5\(\);
12+
^\s*\d+:\s*f6\(\);
13+
^\s*\d+:\s*f7\(\);
14+
^\s*\d+:\s*f8\(\);
15+
^\s*\d+:\s*f9\(\);
16+
--
17+
Though this example program appears to lose const-ness, since it is a primitive
18+
it is a copy so it is irrelevant.

src/analyses/does_remove_const.cpp

Lines changed: 68 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ bool does_remove_constt::operator()() const
4747

4848
// Compare the types recursively for a point where the rhs is more
4949
// const that the lhs
50-
if(!is_type_at_least_as_const_as(&lhs_type, &rhs_type))
50+
if(!does_type_preserve_const_correctness(&lhs_type, &rhs_type))
5151
{
5252
return true;
5353
}
@@ -78,7 +78,7 @@ bool does_remove_constt::does_expr_lose_const(const exprt &expr) const
7878
if(base_type_eq(op_type, root_type, ns))
7979
{
8080
// Is this child more const-qualified than the root
81-
if(!is_type_at_least_as_const_as(&root_type, &op_type))
81+
if(!does_type_preserve_const_correctness(&root_type, &op_type))
8282
{
8383
return true;
8484
}
@@ -93,37 +93,78 @@ bool does_remove_constt::does_expr_lose_const(const exprt &expr) const
9393
return false;
9494
}
9595

96-
/// A recursive check to check the type_more_const is at least as const as type
97-
/// compare.
96+
/// A recursive check that handles when assigning a source value to a target, is
97+
/// the assignment a loss of const-correctness.
9898
///
99-
/// type_more_const | type_compare || result
100-
/// ----------------------------------------
101-
/// const int * | const int * -> true
102-
/// int * | const int * -> false
103-
/// const int * | int * -> true
104-
/// int * | int * const -> false
99+
/// For primitive types, it always returns true since these are copied
100+
///
101+
/// For pointers we requires that if in the source it's value couldn't
102+
/// be modified, then it still can't be modified in the target
103+
///
104+
/// target_type | source_type || result
105+
/// ----------------------------------------
106+
/// const int | int -> true
107+
/// int | const int -> true
108+
/// const int | const int -> true
109+
/// int | int -> true
110+
///
111+
/// int * | int * const -> true
112+
/// int * | const int * -> false
113+
/// const int * | int * -> true
114+
/// const int * | const int * -> true
115+
/// int * const | int * -> true
116+
///
117+
/// See unit/analyses/does_type_preserve_const_correcness for
118+
/// comprehensive list
119+
/// \param target_type: the resulting type
120+
/// \param source_type: the starting type
121+
/// \return Returns true if a value of type source_type could be assigned into a
122+
/// a value of target_type without losing const-correctness
123+
bool does_remove_constt::does_type_preserve_const_correctness(
124+
const typet *target_type, const typet *source_type) const
125+
{
126+
while(target_type->id()==ID_pointer)
127+
{
128+
bool direct_subtypes_at_least_as_const=
129+
is_type_at_least_as_const_as(
130+
target_type->subtype(), source_type->subtype());
131+
// We have a pointer to something, but the thing it is pointing to can't be
132+
// modified normally, but can through this pointer
133+
if(!direct_subtypes_at_least_as_const)
134+
return false;
135+
// Check the subtypes if they are pointers
136+
target_type=&target_type->subtype();
137+
source_type=&source_type->subtype();
138+
}
139+
return true;
140+
}
141+
142+
/// A simple check to check the type_more_const is at least as const as type
143+
/// compare. This only checks the exact type, use
144+
/// `is_pointer_at_least_as_constant_as` for dealing with nested types
145+
///
146+
/// type_more_const | type_compare || result
147+
/// ----------------------------------------
148+
/// const int | int -> true
149+
/// int | const int -> false
150+
/// const int | const int -> true
151+
/// int | int -> true
152+
/// int * | int * const -> false
153+
/// int * | const int * -> true
154+
/// const int * | int * -> true
155+
/// int * const | int * -> true
156+
///
157+
/// See unit/analyses/is_type_as_least_as_const_as for comprehensive list
105158
/// \param type_more_const: the type we are expecting to be at least as const
106159
/// qualified
107160
/// \param type_compare: the type we are comparing against which may be less
108161
/// const qualified
109162
/// \return Returns true if type_more_const is at least as const as type_compare
110163
bool does_remove_constt::is_type_at_least_as_const_as(
111-
const typet *type_more_const, const typet *type_compare) const
164+
const typet &type_more_const, const typet &type_compare) const
112165
{
113-
while(type_compare->id()!=ID_nil && type_more_const->id()!=ID_nil)
114-
{
115-
const c_qualifierst rhs_qualifiers(*type_compare);
116-
const c_qualifierst lhs_qualifiers(*type_more_const);
117-
if(rhs_qualifiers.is_constant && !lhs_qualifiers.is_constant)
118-
{
119-
return false;
120-
}
121-
122-
type_compare=&type_compare->subtype();
123-
type_more_const=&type_more_const->subtype();
124-
}
125-
126-
// Both the types should have the same number of subtypes
127-
assert(type_compare->id()==ID_nil && type_more_const->id()==ID_nil);
128-
return true;
166+
const c_qualifierst type_compare_qualifiers(type_compare);
167+
const c_qualifierst more_constant_qualifiers(type_more_const);
168+
return !type_compare_qualifiers.is_constant ||
169+
more_constant_qualifiers.is_constant;
129170
}

src/analyses/does_remove_const.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define CPROVER_ANALYSES_DOES_REMOVE_CONST_H
1313

1414
#include <util/type.h>
15+
#include <util/namespace.h>
1516

1617
class goto_programt;
1718
class namespacet;
@@ -27,10 +28,15 @@ class does_remove_constt
2728
bool does_expr_lose_const(const exprt &expr) const;
2829

2930
bool is_type_at_least_as_const_as(
30-
const typet *type_more_const, const typet *type_compare) const;
31+
const typet &type_more_const, const typet &type_compare) const;
32+
33+
bool does_type_preserve_const_correctness(
34+
const typet *target_type, const typet *source_type) const;
3135

3236
const goto_programt &goto_program;
3337
const namespacet &ns;
38+
39+
friend class does_remove_const_testt;
3440
};
3541

3642
#endif // CPROVER_ANALYSES_DOES_REMOVE_CONST_H

unit/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
.PHONY: all cprover.dir test
22

33
SRC = unit_tests.cpp \
4+
analyses/does_remove_const/does_expr_lose_const.cpp \
5+
analyses/does_remove_const/does_type_preserve_const_correctness.cpp \
6+
analyses/does_remove_const/is_type_at_least_as_const_as.cpp \
47
catch_example.cpp \
58
# Empty last line
69

0 commit comments

Comments
 (0)