@@ -58,6 +58,8 @@ class goto_check_ct
58
58
enable_memory_cleanup_check =
59
59
_options.get_bool_option (" memory-cleanup-check" );
60
60
enable_div_by_zero_check = _options.get_bool_option (" div-by-zero-check" );
61
+ enable_float_div_by_zero_check =
62
+ _options.get_bool_option (" float-div-by-zero-check" );
61
63
enable_enum_range_check = _options.get_bool_option (" enum-range-check" );
62
64
enable_signed_overflow_check =
63
65
_options.get_bool_option (" signed-overflow-check" );
@@ -179,6 +181,7 @@ class goto_check_ct
179
181
void bounds_check_index (const index_exprt &, const guardt &);
180
182
void bounds_check_bit_count (const unary_exprt &, const guardt &);
181
183
void div_by_zero_check (const div_exprt &, const guardt &);
184
+ void float_div_by_zero_check (const div_exprt &, const guardt &);
182
185
void mod_by_zero_check (const mod_exprt &, const guardt &);
183
186
void mod_overflow_check (const mod_exprt &, const guardt &);
184
187
void enum_range_check (const exprt &, const guardt &);
@@ -262,6 +265,7 @@ class goto_check_ct
262
265
bool enable_memory_leak_check;
263
266
bool enable_memory_cleanup_check;
264
267
bool enable_div_by_zero_check;
268
+ bool enable_float_div_by_zero_check;
265
269
bool enable_enum_range_check;
266
270
bool enable_signed_overflow_check;
267
271
bool enable_unsigned_overflow_check;
@@ -282,6 +286,7 @@ class goto_check_ct
282
286
{" memory-leak-check" , &enable_memory_leak_check},
283
287
{" memory-cleanup-check" , &enable_memory_cleanup_check},
284
288
{" div-by-zero-check" , &enable_div_by_zero_check},
289
+ {" float-div-by-zero-check" , &enable_float_div_by_zero_check},
285
290
{" enum-range-check" , &enable_enum_range_check},
286
291
{" signed-overflow-check" , &enable_signed_overflow_check},
287
292
{" unsigned-overflow-check" , &enable_unsigned_overflow_check},
@@ -508,6 +513,27 @@ void goto_check_ct::div_by_zero_check(
508
513
guard);
509
514
}
510
515
516
+ void goto_check_ct::float_div_by_zero_check (
517
+ const div_exprt &expr,
518
+ const guardt &guard)
519
+ {
520
+ if (!enable_float_div_by_zero_check)
521
+ return ;
522
+
523
+ // add divison by zero subgoal
524
+
525
+ exprt zero = from_integer (0 , expr.op1 ().type ());
526
+ const notequal_exprt inequality (expr.op1 (), std::move (zero));
527
+
528
+ add_guarded_property (
529
+ inequality,
530
+ " floating-point division by zero" ,
531
+ " float-division-by-zero" ,
532
+ expr.find_source_location (),
533
+ expr,
534
+ guard);
535
+ }
536
+
511
537
void goto_check_ct::enum_range_check (const exprt &expr, const guardt &guard)
512
538
{
513
539
if (!enable_enum_range_check)
@@ -1850,7 +1876,21 @@ void goto_check_ct::check_rec_div(
1850
1876
const div_exprt &div_expr,
1851
1877
const guardt &guard)
1852
1878
{
1853
- div_by_zero_check (to_div_expr (div_expr), guard);
1879
+ if (
1880
+ div_expr.type ().id () == ID_signedbv ||
1881
+ div_expr.type ().id () == ID_unsignedbv || div_expr.type ().id () == ID_c_bool)
1882
+ {
1883
+ // Division by zero is undefined behavior for all integer types.
1884
+ div_by_zero_check (to_div_expr (div_expr), guard);
1885
+ }
1886
+ else if (div_expr.type ().id () == ID_floatbv)
1887
+ {
1888
+ // Division by zero on floating-point numbers may be undefined behavior.
1889
+ // Annex F of the ISO C21 suggests that implementations that
1890
+ // define __STDC_IEC_559__ follow IEEE 754 semantics,
1891
+ // which defines the outcome of division by zero.
1892
+ float_div_by_zero_check (to_div_expr (div_expr), guard);
1893
+ }
1854
1894
1855
1895
if (div_expr.type ().id () == ID_signedbv)
1856
1896
integer_overflow_check (div_expr, guard);
0 commit comments