Skip to content

Commit 5b0937f

Browse files
committed
analyzer: new warning: -Wanalyzer-div-by-zero (PR analyzer/124217)
gcc/analyzer/ChangeLog: PR analyzer/124217 * analyzer.opt (Wanalyzer-div-by-zero): New. * analyzer.opt.urls: Regenerate. * region-model.cc (class div_by_zero_diagnostic): New. (region_model::get_gassign_result): Add warning for division by zero if ctxt is non-null. Bail out on such cases even if ctxt is null. * svalue.cc (type_can_have_value_range_p): Also handle frange. gcc/ChangeLog: PR analyzer/124217 * doc/invoke.texi: Add -Wanalyzer-div-by-zero. gcc/testsuite/ChangeLog: PR analyzer/124217 * c-c++-common/analyzer/divide-by-zero-1.c: Update to expect -Wanalyzer-div-by-zero. * c-c++-common/analyzer/divide-by-zero-pr124195-2.c: Likewise. * gcc.dg/analyzer/data-model-1.c (test_21): Split out division by zero cases into... (test_21_division_by_zero): ...this, and... (test_21_modulus_by_zero): ...this, updating these to expect -Wanalyzer-div-by-zero warnings. * gcc.dg/analyzer/divide-by-zero-float.c: New test. * gcc.dg/analyzer/divide-by-zero-ice-pr124433.c: Update to expect -Wanalyzer-div-by-zero. * gcc.dg/analyzer/divide-by-zero-pr124195-1.c: Likewise. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
1 parent eb67d98 commit 5b0937f

11 files changed

Lines changed: 132 additions & 26 deletions

File tree

gcc/analyzer/analyzer.opt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ Wanalyzer-deref-before-check
7878
Common Var(warn_analyzer_deref_before_check) Init(1) Warning
7979
Warn about code paths in which a pointer is checked for NULL after it has already been dereferenced.
8080

81+
Wanalyzer-div-by-zero
82+
Common Var(warn_analyzer_div_by_zero) Init(1) Warning
83+
Warn about code paths which attempt integer division by zero.
84+
8185
Wanalyzer-double-fclose
8286
Common Var(warn_analyzer_double_fclose) Init(1) Warning
8387
Warn about code paths in which a stdio FILE can be closed more than once.

gcc/analyzer/analyzer.opt.urls

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-allocation-size)
66
Wanalyzer-deref-before-check
77
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-deref-before-check)
88

9+
Wanalyzer-div-by-zero
10+
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-div-by-zero)
11+
912
Wanalyzer-double-fclose
1013
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-fclose)
1114

gcc/analyzer/region-model.cc

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,46 @@ class undefined_ptrdiff_diagnostic
855855
const region *m_base_reg_b;
856856
};
857857

858+
class div_by_zero_diagnostic
859+
: public pending_diagnostic_subclass<div_by_zero_diagnostic>
860+
{
861+
public:
862+
div_by_zero_diagnostic (const gassign *assign)
863+
: m_assign (assign)
864+
{}
865+
866+
const char *get_kind () const final override
867+
{
868+
return "div_by_zero_diagnostic";
869+
}
870+
871+
bool operator== (const div_by_zero_diagnostic &other) const
872+
{
873+
return m_assign == other.m_assign;
874+
}
875+
876+
int get_controlling_option () const final override
877+
{
878+
return OPT_Wanalyzer_div_by_zero;
879+
}
880+
881+
bool emit (diagnostic_emission_context &ctxt) final override
882+
{
883+
return ctxt.warn ("division by zero");
884+
}
885+
886+
bool
887+
describe_final_event (pretty_printer &pp,
888+
const evdesc::final_event &) final override
889+
{
890+
pp_printf (&pp, "division by zero");
891+
return true;
892+
}
893+
894+
private:
895+
const gassign *m_assign;
896+
};
897+
858898
/* Check the pointer subtraction SVAL_A - SVAL_B at ASSIGN and add
859899
a warning to CTXT if they're not within the same base region. */
860900

@@ -1073,24 +1113,27 @@ region_model::get_gassign_result (const gassign *assign,
10731113
}
10741114
}
10751115

1076-
if (ctxt
1077-
&& (op == TRUNC_DIV_EXPR
1078-
|| op == CEIL_DIV_EXPR
1079-
|| op == FLOOR_DIV_EXPR
1080-
|| op == ROUND_DIV_EXPR
1081-
|| op == TRUNC_MOD_EXPR
1082-
|| op == CEIL_MOD_EXPR
1083-
|| op == FLOOR_MOD_EXPR
1084-
|| op == ROUND_MOD_EXPR
1085-
|| op == RDIV_EXPR
1086-
|| op == EXACT_DIV_EXPR))
1116+
if (op == TRUNC_DIV_EXPR
1117+
|| op == CEIL_DIV_EXPR
1118+
|| op == FLOOR_DIV_EXPR
1119+
|| op == ROUND_DIV_EXPR
1120+
|| op == TRUNC_MOD_EXPR
1121+
|| op == CEIL_MOD_EXPR
1122+
|| op == FLOOR_MOD_EXPR
1123+
|| op == ROUND_MOD_EXPR
1124+
|| op == RDIV_EXPR
1125+
|| op == EXACT_DIV_EXPR)
10871126
{
10881127
value_range rhs_vr;
10891128
if (rhs2_sval->maybe_get_value_range (rhs_vr))
10901129
if (rhs_vr.zero_p ())
10911130
{
1092-
/* Ideally we should issue a warning here;
1093-
see PR analyzer/124217. */
1131+
if (ctxt)
1132+
{
1133+
ctxt->warn
1134+
(std::make_unique<div_by_zero_diagnostic> (assign));
1135+
ctxt->terminate_path ();
1136+
}
10941137
return nullptr;
10951138
}
10961139
}

gcc/analyzer/svalue.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -891,9 +891,11 @@ type_can_have_value_range_p (tree type)
891891
{
892892
if (!type)
893893
return false;
894-
if (!irange::supports_p (type))
895-
return false;
896-
return true;
894+
if (irange::supports_p (type))
895+
return true;
896+
if (frange::supports_p (type))
897+
return true;
898+
return false;
897899
}
898900

899901
/* Base implementation of svalue::maybe_get_value_range_1 vfunc.

gcc/doc/invoke.texi

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11555,6 +11555,7 @@ Enabling this option effectively enables the following warnings:
1155511555
@gccoptlist{
1155611556
-Wanalyzer-allocation-size
1155711557
-Wanalyzer-deref-before-check
11558+
-Wanalyzer-div-by-zero
1155811559
-Wanalyzer-double-fclose
1155911560
-Wanalyzer-double-free
1156011561
-Wanalyzer-exposure-through-output-file
@@ -11646,6 +11647,18 @@ multiple of @code{sizeof (*pointer)}.
1164611647

1164711648
See @uref{https://cwe.mitre.org/data/definitions/131.html, CWE-131: Incorrect Calculation of Buffer Size}.
1164811649

11650+
@opindex Wanalyzer-div-by-zero
11651+
@opindex Wno-analyzer-div-by-zero
11652+
@item -Wno-analyzer-div-by-zero
11653+
This warning requires @option{-fanalyzer}, which enables it;
11654+
to disable it, use @option{-Wno-analyzer-div-by-zero}.
11655+
11656+
This diagnostic warns for paths through the code which attempt
11657+
integer division by zero. It is analogous to @option{-Wdiv-by-zero}, but
11658+
implemented in a different way.
11659+
11660+
See @uref{https://cwe.mitre.org/data/definitions/369.html, CWE-369: Divide By Zero}.
11661+
1164911662
@opindex Wanalyzer-deref-before-check
1165011663
@opindex Wno-analyzer-deref-before-check
1165111664
@item -Wno-analyzer-deref-before-check

gcc/testsuite/c-c++-common/analyzer/divide-by-zero-1.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ return_zero (void)
99
void
1010
test_div (int a)
1111
{
12-
__analyzer_eval (a / return_zero () == 0); /* { dg-warning "UNKNOWN" } */
12+
__analyzer_eval (a / return_zero () == 0); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
1313
}
1414

1515
void
1616
test_mod (int a)
1717
{
18-
__analyzer_eval (a % return_zero () == 0); /* { dg-warning "UNKNOWN" } */
18+
__analyzer_eval (a % return_zero () == 0); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
1919
}

gcc/testsuite/c-c++-common/analyzer/divide-by-zero-pr124195-2.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ short s;
33
int
44
foo()
55
{
6-
s %= 0; /* { dg-warning "division by zero" } */
6+
s %= 0; /* { dg-warning "division by zero \\\[-Wdiv-by-zero\\\]" } */
7+
/* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" "" { target *-*-* } .-1 } */
78
return s > 0;
89
}

gcc/testsuite/gcc.dg/analyzer/data-model-1.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -421,11 +421,6 @@ void test_21 (void)
421421
__analyzer_eval (i / j == 1); /* { dg-warning "TRUE" } */
422422
__analyzer_eval (i % j == 2); /* { dg-warning "TRUE" } */
423423

424-
/* Division by zero. */
425-
// TODO: should we warn for this?
426-
__analyzer_eval (i / zero); /* { dg-warning "UNKNOWN" } */
427-
__analyzer_eval (i % zero); /* { dg-warning "UNKNOWN" } */
428-
429424
__analyzer_eval ((i & 1) == (5 & 1)); /* { dg-warning "TRUE" } */
430425
__analyzer_eval ((i & j) == (5 & 3)); /* { dg-warning "TRUE" } */
431426
__analyzer_eval ((i | 1) == (5 | 1)); /* { dg-warning "TRUE" } */
@@ -449,6 +444,28 @@ void test_21 (void)
449444
__analyzer_eval (+i == +5); /* { dg-warning "TRUE" } */
450445
}
451446

447+
void test_21_division_by_zero (void)
448+
{
449+
int i, zero;
450+
int *pi = &i;
451+
int *pzero = &zero;
452+
*pi = 5;
453+
*pzero = 0;
454+
455+
__analyzer_eval (i / zero); /* { dg-warning "Wanalyzer-div-by-zero" } */
456+
}
457+
458+
void test_21_modulus_by_zero (void)
459+
{
460+
int i, zero;
461+
int *pi = &i;
462+
int *pzero = &zero;
463+
*pi = 5;
464+
*pzero = 0;
465+
466+
__analyzer_eval (i % zero); /* { dg-warning "Wanalyzer-div-by-zero" } */
467+
}
468+
452469
void test_22 (int i, int j)
453470
{
454471
__analyzer_eval (i + j == i + j); /* { dg-warning "TRUE" } */
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
float
2+
test_1 ()
3+
{
4+
return 42.f / 0.f; /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
5+
}
6+
7+
static float __attribute__((noinline))
8+
get_zero ()
9+
{
10+
return 0.f;
11+
}
12+
13+
float
14+
test_2 ()
15+
{
16+
return 42.f / get_zero (); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
17+
}
18+
19+
float
20+
test_3 (float x)
21+
{
22+
return x / get_zero (); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
23+
}

gcc/testsuite/gcc.dg/analyzer/divide-by-zero-ice-pr124433.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ int c;
44
void
55
foo()
66
{
7-
do c %= (5ull << 40) & m;
7+
do c %= (5ull << 40) & m; /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
88
while (c);
99
}

0 commit comments

Comments
 (0)