@@ -53,6 +53,8 @@ class goto_check_ct
53
53
{
54
54
enable_bounds_check = _options.get_bool_option (" bounds-check" );
55
55
enable_pointer_check = _options.get_bool_option (" pointer-check" );
56
+ enable_uninitialized_check =
57
+ _options.get_bool_option (" uninitialized-check" );
56
58
enable_memory_leak_check = _options.get_bool_option (" memory-leak-check" );
57
59
enable_memory_cleanup_check =
58
60
_options.get_bool_option (" memory-cleanup-check" );
@@ -157,11 +159,13 @@ class goto_check_ct
157
159
// / guard.
158
160
// / \param expr: the expression to be checked
159
161
// / \param guard: the condition for when the check should be made
160
- void check_rec (const exprt &expr, const guardt &guard);
162
+ // / \param is_lhs: the expression is the LHS of an assignment
163
+ void check_rec (const exprt &, const guardt &, bool is_lhs);
161
164
162
165
// / Initiate the recursively analysis of \p expr with its `guard' set to TRUE.
163
166
// / \param expr: the expression to be checked
164
- void check (const exprt &expr);
167
+ // / \param is_lhs: the expression is the LHS of an assignment
168
+ void check (const exprt &expr, bool is_lhs);
165
169
166
170
struct conditiont
167
171
{
@@ -187,6 +191,7 @@ class goto_check_ct
187
191
void undefined_shift_check (const shift_exprt &, const guardt &);
188
192
void pointer_rel_check (const binary_exprt &, const guardt &);
189
193
void pointer_overflow_check (const exprt &, const guardt &);
194
+ void uninitialized_check (const symbol_exprt &, const guardt &);
190
195
void memory_leak_check (const irep_idt &function_id);
191
196
192
197
// / Generates VCCs for the validity of the given dereferencing operation.
@@ -263,6 +268,7 @@ class goto_check_ct
263
268
264
269
bool enable_bounds_check;
265
270
bool enable_pointer_check;
271
+ bool enable_uninitialized_check;
266
272
bool enable_memory_leak_check;
267
273
bool enable_memory_cleanup_check;
268
274
bool enable_div_by_zero_check;
@@ -284,6 +290,7 @@ class goto_check_ct
284
290
std::map<irep_idt, bool *> name_to_flag{
285
291
{" bounds-check" , &enable_bounds_check},
286
292
{" pointer-check" , &enable_pointer_check},
293
+ {" uninitialized-check" , &enable_uninitialized_check},
287
294
{" memory-leak-check" , &enable_memory_leak_check},
288
295
{" memory-cleanup-check" , &enable_memory_cleanup_check},
289
296
{" div-by-zero-check" , &enable_div_by_zero_check},
@@ -1331,6 +1338,23 @@ void goto_check_ct::nan_check(const exprt &expr, const guardt &guard)
1331
1338
guard);
1332
1339
}
1333
1340
1341
+ void goto_check_ct::uninitialized_check (
1342
+ const symbol_exprt &expr,
1343
+ const guardt &guard)
1344
+ {
1345
+ if (!enable_uninitialized_check)
1346
+ return ;
1347
+
1348
+ add_guarded_property (
1349
+ false_exprt{},
1350
+ " reading uninitialized local" ,
1351
+ " uninitialized" ,
1352
+ true , // not fatal
1353
+ expr.find_source_location (),
1354
+ expr,
1355
+ guard);
1356
+ }
1357
+
1334
1358
void goto_check_ct::pointer_rel_check (
1335
1359
const binary_exprt &expr,
1336
1360
const guardt &guard)
@@ -1807,13 +1831,13 @@ void goto_check_ct::check_rec_address(const exprt &expr, const guardt &guard)
1807
1831
1808
1832
if (expr.id () == ID_dereference)
1809
1833
{
1810
- check_rec (to_dereference_expr (expr).pointer (), guard);
1834
+ check_rec (to_dereference_expr (expr).pointer (), guard, false );
1811
1835
}
1812
1836
else if (expr.id () == ID_index)
1813
1837
{
1814
1838
const index_exprt &index_expr = to_index_expr (expr);
1815
1839
check_rec_address (index_expr.array (), guard);
1816
- check_rec (index_expr.index (), guard);
1840
+ check_rec (index_expr.index (), guard, false );
1817
1841
}
1818
1842
else
1819
1843
{
@@ -1843,7 +1867,7 @@ void goto_check_ct::check_rec_logical_op(const exprt &expr, const guardt &guard)
1843
1867
return guard (implication (conjunction (constraints), expr));
1844
1868
};
1845
1869
1846
- check_rec (op, new_guard);
1870
+ check_rec (op, new_guard, false );
1847
1871
1848
1872
constraints.push_back (expr.id () == ID_or ? boolean_negate (op) : op);
1849
1873
}
@@ -1855,20 +1879,20 @@ void goto_check_ct::check_rec_if(const if_exprt &if_expr, const guardt &guard)
1855
1879
if_expr.cond ().is_boolean (),
1856
1880
" first argument of if must be boolean, but got " + if_expr.cond ().pretty ());
1857
1881
1858
- check_rec (if_expr.cond (), guard);
1882
+ check_rec (if_expr.cond (), guard, false );
1859
1883
1860
1884
{
1861
1885
auto new_guard = [&guard, &if_expr](exprt expr) {
1862
1886
return guard (implication (if_expr.cond (), std::move (expr)));
1863
1887
};
1864
- check_rec (if_expr.true_case (), new_guard);
1888
+ check_rec (if_expr.true_case (), new_guard, false );
1865
1889
}
1866
1890
1867
1891
{
1868
1892
auto new_guard = [&guard, &if_expr](exprt expr) {
1869
1893
return guard (implication (not_exprt (if_expr.cond ()), std::move (expr)));
1870
1894
};
1871
- check_rec (if_expr.false_case (), new_guard);
1895
+ check_rec (if_expr.false_case (), new_guard, false );
1872
1896
}
1873
1897
}
1874
1898
@@ -1878,7 +1902,7 @@ bool goto_check_ct::check_rec_member(
1878
1902
{
1879
1903
const dereference_exprt &deref = to_dereference_expr (member.struct_op ());
1880
1904
1881
- check_rec (deref.pointer (), guard);
1905
+ check_rec (deref.pointer (), guard, false );
1882
1906
1883
1907
// avoid building the following expressions when pointer_validity_check
1884
1908
// would return immediately anyway
@@ -1969,7 +1993,7 @@ void goto_check_ct::check_rec_arithmetic_op(
1969
1993
}
1970
1994
}
1971
1995
1972
- void goto_check_ct::check_rec (const exprt &expr, const guardt &guard)
1996
+ void goto_check_ct::check_rec (const exprt &expr, const guardt &guard, bool is_lhs )
1973
1997
{
1974
1998
if (expr.id () == ID_exists || expr.id () == ID_forall)
1975
1999
{
@@ -1980,7 +2004,7 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
1980
2004
return guard (forall_exprt (quantifier_expr.symbol (), expr));
1981
2005
};
1982
2006
1983
- check_rec (quantifier_expr.where (), new_guard);
2007
+ check_rec (quantifier_expr.where (), new_guard, false );
1984
2008
return ;
1985
2009
}
1986
2010
else if (expr.id () == ID_address_of)
@@ -2007,7 +2031,7 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
2007
2031
}
2008
2032
2009
2033
for (const auto &op : expr.operands ())
2010
- check_rec (op, guard);
2034
+ check_rec (op, guard, false );
2011
2035
2012
2036
if (expr.type ().id () == ID_c_enum_tag)
2013
2037
enum_range_check (expr, guard);
@@ -2048,6 +2072,10 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
2048
2072
{
2049
2073
pointer_validity_check (to_dereference_expr (expr), expr, guard);
2050
2074
}
2075
+ else if (expr.id () == ID_symbol)
2076
+ {
2077
+ uninitialized_check (to_symbol_expr (expr), guard);
2078
+ }
2051
2079
else if (requires_pointer_primitive_check (expr))
2052
2080
{
2053
2081
pointer_primitive_check (expr, guard);
@@ -2059,9 +2087,9 @@ void goto_check_ct::check_rec(const exprt &expr, const guardt &guard)
2059
2087
}
2060
2088
}
2061
2089
2062
- void goto_check_ct::check (const exprt &expr)
2090
+ void goto_check_ct::check (const exprt &expr, bool is_lhs )
2063
2091
{
2064
- check_rec (expr, identity);
2092
+ check_rec (expr, identity, is_lhs );
2065
2093
}
2066
2094
2067
2095
void goto_check_ct::memory_leak_check (const irep_idt &function_id)
@@ -2151,7 +2179,7 @@ void goto_check_ct::goto_check(
2151
2179
2152
2180
if (i.has_condition ())
2153
2181
{
2154
- check (i.condition ());
2182
+ check (i.condition (), false );
2155
2183
}
2156
2184
2157
2185
// magic ERROR label?
@@ -2184,12 +2212,12 @@ void goto_check_ct::goto_check(
2184
2212
2185
2213
if (statement == ID_expression)
2186
2214
{
2187
- check (code);
2215
+ check (code, false );
2188
2216
}
2189
2217
else if (statement == ID_printf)
2190
2218
{
2191
2219
for (const auto &op : code.operands ())
2192
- check (op);
2220
+ check (op, false );
2193
2221
}
2194
2222
}
2195
2223
else if (i.is_assign ())
@@ -2202,10 +2230,10 @@ void goto_check_ct::goto_check(
2202
2230
{
2203
2231
flag_overridet resetter (i.source_location ());
2204
2232
resetter.disable_flag (enable_enum_range_check, " enum_range_check" );
2205
- check (assign_lhs);
2233
+ check (assign_lhs, true );
2206
2234
}
2207
2235
2208
- check (assign_rhs);
2236
+ check (assign_rhs, false );
2209
2237
2210
2238
// the LHS might invalidate any assertion
2211
2239
invalidate (assign_lhs);
@@ -2217,12 +2245,13 @@ void goto_check_ct::goto_check(
2217
2245
{
2218
2246
flag_overridet resetter (i.source_location ());
2219
2247
resetter.disable_flag (enable_enum_range_check, " enum_range_check" );
2220
- check (i.call_lhs ());
2248
+ check (i.call_lhs (), true );
2221
2249
}
2222
- check (i.call_function ());
2250
+
2251
+ check (i.call_function (), false );
2223
2252
2224
2253
for (const auto &arg : i.call_arguments ())
2225
- check (arg);
2254
+ check (arg, false );
2226
2255
2227
2256
check_shadow_memory_api_calls (i);
2228
2257
@@ -2231,7 +2260,7 @@ void goto_check_ct::goto_check(
2231
2260
}
2232
2261
else if (i.is_set_return_value ())
2233
2262
{
2234
- check (i.return_value ());
2263
+ check (i.return_value (), false );
2235
2264
// the return value invalidate any assertion
2236
2265
invalidate (i.return_value ());
2237
2266
}
@@ -2342,7 +2371,7 @@ void goto_check_ct::check_shadow_memory_api_calls(
2342
2371
{
2343
2372
const exprt &expr = i.call_arguments ()[0 ];
2344
2373
PRECONDITION (expr.type ().id () == ID_pointer);
2345
- check (dereference_exprt (expr));
2374
+ check (dereference_exprt (expr), false );
2346
2375
}
2347
2376
}
2348
2377
0 commit comments