mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
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>
This commit is contained in:
@@ -78,6 +78,10 @@ Wanalyzer-deref-before-check
|
||||
Common Var(warn_analyzer_deref_before_check) Init(1) Warning
|
||||
Warn about code paths in which a pointer is checked for NULL after it has already been dereferenced.
|
||||
|
||||
Wanalyzer-div-by-zero
|
||||
Common Var(warn_analyzer_div_by_zero) Init(1) Warning
|
||||
Warn about code paths which attempt integer division by zero.
|
||||
|
||||
Wanalyzer-double-fclose
|
||||
Common Var(warn_analyzer_double_fclose) Init(1) Warning
|
||||
Warn about code paths in which a stdio FILE can be closed more than once.
|
||||
|
||||
@@ -6,6 +6,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-allocation-size)
|
||||
Wanalyzer-deref-before-check
|
||||
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-deref-before-check)
|
||||
|
||||
Wanalyzer-div-by-zero
|
||||
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-div-by-zero)
|
||||
|
||||
Wanalyzer-double-fclose
|
||||
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-double-fclose)
|
||||
|
||||
|
||||
@@ -855,6 +855,46 @@ private:
|
||||
const region *m_base_reg_b;
|
||||
};
|
||||
|
||||
class div_by_zero_diagnostic
|
||||
: public pending_diagnostic_subclass<div_by_zero_diagnostic>
|
||||
{
|
||||
public:
|
||||
div_by_zero_diagnostic (const gassign *assign)
|
||||
: m_assign (assign)
|
||||
{}
|
||||
|
||||
const char *get_kind () const final override
|
||||
{
|
||||
return "div_by_zero_diagnostic";
|
||||
}
|
||||
|
||||
bool operator== (const div_by_zero_diagnostic &other) const
|
||||
{
|
||||
return m_assign == other.m_assign;
|
||||
}
|
||||
|
||||
int get_controlling_option () const final override
|
||||
{
|
||||
return OPT_Wanalyzer_div_by_zero;
|
||||
}
|
||||
|
||||
bool emit (diagnostic_emission_context &ctxt) final override
|
||||
{
|
||||
return ctxt.warn ("division by zero");
|
||||
}
|
||||
|
||||
bool
|
||||
describe_final_event (pretty_printer &pp,
|
||||
const evdesc::final_event &) final override
|
||||
{
|
||||
pp_printf (&pp, "division by zero");
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
const gassign *m_assign;
|
||||
};
|
||||
|
||||
/* Check the pointer subtraction SVAL_A - SVAL_B at ASSIGN and add
|
||||
a warning to CTXT if they're not within the same base region. */
|
||||
|
||||
@@ -1073,24 +1113,27 @@ region_model::get_gassign_result (const gassign *assign,
|
||||
}
|
||||
}
|
||||
|
||||
if (ctxt
|
||||
&& (op == TRUNC_DIV_EXPR
|
||||
|| op == CEIL_DIV_EXPR
|
||||
|| op == FLOOR_DIV_EXPR
|
||||
|| op == ROUND_DIV_EXPR
|
||||
|| op == TRUNC_MOD_EXPR
|
||||
|| op == CEIL_MOD_EXPR
|
||||
|| op == FLOOR_MOD_EXPR
|
||||
|| op == ROUND_MOD_EXPR
|
||||
|| op == RDIV_EXPR
|
||||
|| op == EXACT_DIV_EXPR))
|
||||
if (op == TRUNC_DIV_EXPR
|
||||
|| op == CEIL_DIV_EXPR
|
||||
|| op == FLOOR_DIV_EXPR
|
||||
|| op == ROUND_DIV_EXPR
|
||||
|| op == TRUNC_MOD_EXPR
|
||||
|| op == CEIL_MOD_EXPR
|
||||
|| op == FLOOR_MOD_EXPR
|
||||
|| op == ROUND_MOD_EXPR
|
||||
|| op == RDIV_EXPR
|
||||
|| op == EXACT_DIV_EXPR)
|
||||
{
|
||||
value_range rhs_vr;
|
||||
if (rhs2_sval->maybe_get_value_range (rhs_vr))
|
||||
if (rhs_vr.zero_p ())
|
||||
{
|
||||
/* Ideally we should issue a warning here;
|
||||
see PR analyzer/124217. */
|
||||
if (ctxt)
|
||||
{
|
||||
ctxt->warn
|
||||
(std::make_unique<div_by_zero_diagnostic> (assign));
|
||||
ctxt->terminate_path ();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -891,9 +891,11 @@ type_can_have_value_range_p (tree type)
|
||||
{
|
||||
if (!type)
|
||||
return false;
|
||||
if (!irange::supports_p (type))
|
||||
return false;
|
||||
return true;
|
||||
if (irange::supports_p (type))
|
||||
return true;
|
||||
if (frange::supports_p (type))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Base implementation of svalue::maybe_get_value_range_1 vfunc.
|
||||
|
||||
@@ -11555,6 +11555,7 @@ Enabling this option effectively enables the following warnings:
|
||||
@gccoptlist{
|
||||
-Wanalyzer-allocation-size
|
||||
-Wanalyzer-deref-before-check
|
||||
-Wanalyzer-div-by-zero
|
||||
-Wanalyzer-double-fclose
|
||||
-Wanalyzer-double-free
|
||||
-Wanalyzer-exposure-through-output-file
|
||||
@@ -11646,6 +11647,18 @@ multiple of @code{sizeof (*pointer)}.
|
||||
|
||||
See @uref{https://cwe.mitre.org/data/definitions/131.html, CWE-131: Incorrect Calculation of Buffer Size}.
|
||||
|
||||
@opindex Wanalyzer-div-by-zero
|
||||
@opindex Wno-analyzer-div-by-zero
|
||||
@item -Wno-analyzer-div-by-zero
|
||||
This warning requires @option{-fanalyzer}, which enables it;
|
||||
to disable it, use @option{-Wno-analyzer-div-by-zero}.
|
||||
|
||||
This diagnostic warns for paths through the code which attempt
|
||||
integer division by zero. It is analogous to @option{-Wdiv-by-zero}, but
|
||||
implemented in a different way.
|
||||
|
||||
See @uref{https://cwe.mitre.org/data/definitions/369.html, CWE-369: Divide By Zero}.
|
||||
|
||||
@opindex Wanalyzer-deref-before-check
|
||||
@opindex Wno-analyzer-deref-before-check
|
||||
@item -Wno-analyzer-deref-before-check
|
||||
|
||||
@@ -9,11 +9,11 @@ return_zero (void)
|
||||
void
|
||||
test_div (int a)
|
||||
{
|
||||
__analyzer_eval (a / return_zero () == 0); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (a / return_zero () == 0); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
}
|
||||
|
||||
void
|
||||
test_mod (int a)
|
||||
{
|
||||
__analyzer_eval (a % return_zero () == 0); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (a % return_zero () == 0); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ short s;
|
||||
int
|
||||
foo()
|
||||
{
|
||||
s %= 0; /* { dg-warning "division by zero" } */
|
||||
s %= 0; /* { dg-warning "division by zero \\\[-Wdiv-by-zero\\\]" } */
|
||||
/* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" "" { target *-*-* } .-1 } */
|
||||
return s > 0;
|
||||
}
|
||||
|
||||
@@ -421,11 +421,6 @@ void test_21 (void)
|
||||
__analyzer_eval (i / j == 1); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (i % j == 2); /* { dg-warning "TRUE" } */
|
||||
|
||||
/* Division by zero. */
|
||||
// TODO: should we warn for this?
|
||||
__analyzer_eval (i / zero); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (i % zero); /* { dg-warning "UNKNOWN" } */
|
||||
|
||||
__analyzer_eval ((i & 1) == (5 & 1)); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval ((i & j) == (5 & 3)); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval ((i | 1) == (5 | 1)); /* { dg-warning "TRUE" } */
|
||||
@@ -449,6 +444,28 @@ void test_21 (void)
|
||||
__analyzer_eval (+i == +5); /* { dg-warning "TRUE" } */
|
||||
}
|
||||
|
||||
void test_21_division_by_zero (void)
|
||||
{
|
||||
int i, zero;
|
||||
int *pi = &i;
|
||||
int *pzero = &zero;
|
||||
*pi = 5;
|
||||
*pzero = 0;
|
||||
|
||||
__analyzer_eval (i / zero); /* { dg-warning "Wanalyzer-div-by-zero" } */
|
||||
}
|
||||
|
||||
void test_21_modulus_by_zero (void)
|
||||
{
|
||||
int i, zero;
|
||||
int *pi = &i;
|
||||
int *pzero = &zero;
|
||||
*pi = 5;
|
||||
*pzero = 0;
|
||||
|
||||
__analyzer_eval (i % zero); /* { dg-warning "Wanalyzer-div-by-zero" } */
|
||||
}
|
||||
|
||||
void test_22 (int i, int j)
|
||||
{
|
||||
__analyzer_eval (i + j == i + j); /* { dg-warning "TRUE" } */
|
||||
|
||||
23
gcc/testsuite/gcc.dg/analyzer/divide-by-zero-float.c
Normal file
23
gcc/testsuite/gcc.dg/analyzer/divide-by-zero-float.c
Normal file
@@ -0,0 +1,23 @@
|
||||
float
|
||||
test_1 ()
|
||||
{
|
||||
return 42.f / 0.f; /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
}
|
||||
|
||||
static float __attribute__((noinline))
|
||||
get_zero ()
|
||||
{
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
float
|
||||
test_2 ()
|
||||
{
|
||||
return 42.f / get_zero (); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
}
|
||||
|
||||
float
|
||||
test_3 (float x)
|
||||
{
|
||||
return x / get_zero (); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
}
|
||||
@@ -4,6 +4,6 @@ int c;
|
||||
void
|
||||
foo()
|
||||
{
|
||||
do c %= (5ull << 40) & m;
|
||||
do c %= (5ull << 40) & m; /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
while (c);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@ short s;
|
||||
int
|
||||
foo()
|
||||
{
|
||||
s %= (0, 0);
|
||||
s %= (0, 0); /* { dg-warning "division by zero \\\[-Wanalyzer-div-by-zero\\\]" } */
|
||||
return s > 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user