@@ -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+
13421387void 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);
0 commit comments