Skip to content

Commit a8069ba

Browse files
committed
uninitialized check
Uninitialized local or dynamically allocated variables have an indeterminate initial value. Reading an indeterminate value _may_ be undefined behavior, or may yield an unspecific value. This adds a check for uninitialized local variables. The check is not added as a standard check.
1 parent f9a7807 commit a8069ba

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

src/ansi-c/goto-conversion/goto_check_c.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ class goto_check_ct
5353
{
5454
enable_bounds_check = _options.get_bool_option("bounds-check");
5555
enable_pointer_check = _options.get_bool_option("pointer-check");
56+
enable_uninitialized_check =
57+
_options.get_bool_option("uninitialized-check");
5658
enable_memory_leak_check = _options.get_bool_option("memory-leak-check");
5759
enable_memory_cleanup_check =
5860
_options.get_bool_option("memory-cleanup-check");
@@ -189,6 +191,8 @@ class goto_check_ct
189191
void undefined_shift_check(const shift_exprt &, const guardt &);
190192
void pointer_rel_check(const binary_exprt &, const guardt &);
191193
void pointer_overflow_check(const exprt &, const guardt &);
194+
void
195+
uninitialized_check(const symbol_exprt &, const guardt &, bool is_assigned);
192196
void memory_leak_check(const irep_idt &function_id);
193197

194198
/// Generates VCCs for the validity of the given dereferencing operation.
@@ -265,6 +269,7 @@ class goto_check_ct
265269

266270
bool enable_bounds_check;
267271
bool enable_pointer_check;
272+
bool enable_uninitialized_check;
268273
bool enable_memory_leak_check;
269274
bool enable_memory_cleanup_check;
270275
bool enable_div_by_zero_check;
@@ -286,6 +291,7 @@ class goto_check_ct
286291
std::map<irep_idt, bool *> name_to_flag{
287292
{"bounds-check", &enable_bounds_check},
288293
{"pointer-check", &enable_pointer_check},
294+
{"uninitialized-check", &enable_uninitialized_check},
289295
{"memory-leak-check", &enable_memory_leak_check},
290296
{"memory-cleanup-check", &enable_memory_cleanup_check},
291297
{"div-by-zero-check", &enable_div_by_zero_check},
@@ -1339,6 +1345,45 @@ void goto_check_ct::nan_check(const exprt &expr, const guardt &guard)
13391345
guard);
13401346
}
13411347

1348+
void goto_check_ct::uninitialized_check(
1349+
const symbol_exprt &expr,
1350+
const guardt &guard,
1351+
bool is_assigned)
1352+
{
1353+
if(!enable_uninitialized_check)
1354+
return;
1355+
1356+
// Ignore C function symbols.
1357+
if(expr.type().id() == ID_code)
1358+
return;
1359+
1360+
// Don't check the LHS of an assignment -- these do not
1361+
// have to be initialized
1362+
if(is_assigned)
1363+
return;
1364+
1365+
// Look up the symbol
1366+
auto &symbol = ns.lookup(expr);
1367+
1368+
// Anything with static lifetime is initialized by the runtime,
1369+
// and is hence never uninitialized.
1370+
if(symbol.is_static_lifetime)
1371+
return;
1372+
1373+
// Query our abstract domain whether this might be uninitialized use.
1374+
if(!local_bitvector_analysis->get(current_target, expr).is_uninitialized())
1375+
return; // not uninitialized
1376+
1377+
add_guarded_property(
1378+
false_exprt{},
1379+
"reading uninitialized local",
1380+
"uninitialized",
1381+
true, // not fatal
1382+
expr.find_source_location(),
1383+
expr,
1384+
guard);
1385+
}
1386+
13421387
void goto_check_ct::pointer_rel_check(
13431388
const binary_exprt &expr,
13441389
const guardt &guard)
@@ -2059,6 +2104,10 @@ void goto_check_ct::check_rec(
20592104
{
20602105
pointer_validity_check(to_dereference_expr(expr), expr, guard);
20612106
}
2107+
else if(expr.id() == ID_symbol)
2108+
{
2109+
uninitialized_check(to_symbol_expr(expr), guard, is_assigned);
2110+
}
20622111
else if(requires_pointer_primitive_check(expr))
20632112
{
20642113
pointer_primitive_check(expr, guard);

src/ansi-c/goto-conversion/goto_check_c.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ void goto_check_c(
3939

4040
#define OPT_GOTO_CHECK \
4141
"(bounds-check)(pointer-check)(memory-leak-check)(memory-cleanup-check)" \
42+
"(uninitialized-check)" \
4243
"(div-by-zero-check)(float-div-by-zero-check)" \
4344
"(enum-range-check)" \
4445
"(signed-overflow-check)(unsigned-overflow-check)" \
@@ -51,6 +52,7 @@ void goto_check_c(
5152
"(assert-to-assume)" \
5253
"(no-bounds-check)(no-pointer-check)(no-signed-overflow-check)" \
5354
"(no-pointer-primitive-check)(no-undefined-shift-check)" \
55+
"(no-uninitialized-check)" \
5456
"(no-div-by-zero-check)"
5557

5658
// clang-format off
@@ -59,6 +61,8 @@ void goto_check_c(
5961
" {y--bounds-check} \t enable array bounds checks (default on)\n" \
6062
" {y--no-bounds-check} \t disable array bounds checks\n" \
6163
" {y--pointer-check} \t enable pointer checks (default on)\n" \
64+
" {y--uninitialized-check} \t enable checks for uninitialized data (default off)\n" \
65+
" {y--no-uninitialized-check} \t disable checks for uninitialized data\n" \
6266
" {y--no-pointer-check} \t disable pointer checks\n" \
6367
" {y--memory-leak-check} \t enable memory leak checks\n" \
6468
" {y--memory-cleanup-check} \t enable memory cleanup checks\n" \
@@ -126,6 +130,7 @@ void goto_check_c(
126130
options.set_option("error-label", cmdline.get_values("error-label")); \
127131
PARSE_OPTION_OVERRIDE(cmdline, options, "bounds-check"); \
128132
PARSE_OPTION_OVERRIDE(cmdline, options, "pointer-check"); \
133+
PARSE_OPTION_OVERRIDE(cmdline, options, "uninitialized-check"); \
129134
PARSE_OPTION_OVERRIDE(cmdline, options, "div-by-zero-check"); \
130135
PARSE_OPTION_OVERRIDE(cmdline, options, "float-div-by-zero-check"); \
131136
PARSE_OPTION_OVERRIDE(cmdline, options, "signed-overflow-check"); \

0 commit comments

Comments
 (0)