public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r11-4930] analyzer: warn on invalid shift counts [PR97424]
@ 2020-11-12 2:18 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2020-11-12 2:18 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:5e00ad3ffbfb4df7242c313a0d836f5b538eb2fb
commit r11-4930-g5e00ad3ffbfb4df7242c313a0d836f5b538eb2fb
Author: David Malcolm <dmalcolm@redhat.com>
Date: Wed Nov 11 21:16:45 2020 -0500
analyzer: warn on invalid shift counts [PR97424]
This patch implements -Wanalyzer-shift-count-negative
and -Wanalyzer-shift-count-overflow, analogous to the C/C++
warnings -Wshift-count-negative and -Wshift-count-overflow, but
implemented via interprocedural path analysis rather than via parsing
in a front end, and thus capable of detecting interprocedural cases that the
warnings implemented in the front ends can miss.
gcc/analyzer/ChangeLog:
PR tree-optimization/97424
* analyzer.opt (Wanalyzer-shift-count-negative): New.
(Wanalyzer-shift-count-overflow): New.
* region-model.cc (class shift_count_negative_diagnostic): New.
(class shift_count_overflow_diagnostic): New.
(region_model::get_gassign_result): Complain about shift counts that
are negative or are >= the operand's type's width.
gcc/ChangeLog:
PR tree-optimization/97424
* doc/invoke.texi (Static Analyzer Options): Add
-Wno-analyzer-shift-count-negative and
-Wno-analyzer-shift-count-overflow.
(-Wno-analyzer-shift-count-negative): New.
(-Wno-analyzer-shift-count-overflow): New.
gcc/testsuite/ChangeLog:
PR tree-optimization/97424
* gcc.dg/analyzer/invalid-shift-1.c: New test.
Diff:
---
gcc/analyzer/analyzer.opt | 8 ++
gcc/analyzer/region-model.cc | 102 ++++++++++++++++++++++++
gcc/doc/invoke.texi | 33 ++++++++
gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c | 34 ++++++++
4 files changed, 177 insertions(+)
diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt
index c9df6dc7673..bbf9e429c99 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -98,6 +98,14 @@ Wanalyzer-null-dereference
Common Var(warn_analyzer_null_dereference) Init(1) Warning
Warn about code paths in which a NULL pointer is dereferenced.
+Wanalyzer-shift-count-negative
+Common Var(warn_analyzer_shift_count_negative) Init(1) Warning
+Warn about code paths in which a shift with negative count is attempted.
+
+Wanalyzer-shift-count-overflow
+Common Var(warn_analyzer_shift_count_overflow) Init(1) Warning
+Warn about code paths in which a shift with count >= width of type is attempted.
+
Wanalyzer-stale-setjmp-buffer
Common Var(warn_analyzer_stale_setjmp_buffer) Init(1) Warning
Warn about code paths in which a longjmp rewinds to a jmp_buf saved in a stack frame that has returned.
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index d30047b279d..57c657bf6b8 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -363,6 +363,88 @@ private:
enum poison_kind m_pkind;
};
+/* A subclass of pending_diagnostic for complaining about shifts
+ by negative counts. */
+
+class shift_count_negative_diagnostic
+: public pending_diagnostic_subclass<shift_count_negative_diagnostic>
+{
+public:
+ shift_count_negative_diagnostic (const gassign *assign, tree count_cst)
+ : m_assign (assign), m_count_cst (count_cst)
+ {}
+
+ const char *get_kind () const FINAL OVERRIDE
+ {
+ return "shift_count_negative_diagnostic";
+ }
+
+ bool operator== (const shift_count_negative_diagnostic &other) const
+ {
+ return (m_assign == other.m_assign
+ && same_tree_p (m_count_cst, other.m_count_cst));
+ }
+
+ bool emit (rich_location *rich_loc) FINAL OVERRIDE
+ {
+ return warning_at (rich_loc, OPT_Wanalyzer_shift_count_negative,
+ "shift by negative count (%qE)", m_count_cst);
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
+ {
+ return ev.formatted_print ("shift by negative amount here (%qE)", m_count_cst);
+ }
+
+private:
+ const gassign *m_assign;
+ tree m_count_cst;
+};
+
+/* A subclass of pending_diagnostic for complaining about shifts
+ by counts >= the width of the operand type. */
+
+class shift_count_overflow_diagnostic
+: public pending_diagnostic_subclass<shift_count_overflow_diagnostic>
+{
+public:
+ shift_count_overflow_diagnostic (const gassign *assign,
+ int operand_precision,
+ tree count_cst)
+ : m_assign (assign), m_operand_precision (operand_precision),
+ m_count_cst (count_cst)
+ {}
+
+ const char *get_kind () const FINAL OVERRIDE
+ {
+ return "shift_count_overflow_diagnostic";
+ }
+
+ bool operator== (const shift_count_overflow_diagnostic &other) const
+ {
+ return (m_assign == other.m_assign
+ && m_operand_precision == other.m_operand_precision
+ && same_tree_p (m_count_cst, other.m_count_cst));
+ }
+
+ bool emit (rich_location *rich_loc) FINAL OVERRIDE
+ {
+ return warning_at (rich_loc, OPT_Wanalyzer_shift_count_overflow,
+ "shift by count (%qE) >= precision of type (%qi)",
+ m_count_cst, m_operand_precision);
+ }
+
+ label_text describe_final_event (const evdesc::final_event &ev) FINAL OVERRIDE
+ {
+ return ev.formatted_print ("shift by count %qE here", m_count_cst);
+ }
+
+private:
+ const gassign *m_assign;
+ int m_operand_precision;
+ tree m_count_cst;
+};
+
/* If ASSIGN is a stmt that can be modelled via
set_value (lhs_reg, SVALUE, CTXT)
for some SVALUE, get the SVALUE.
@@ -514,6 +596,26 @@ region_model::get_gassign_result (const gassign *assign,
const svalue *rhs1_sval = get_rvalue (rhs1, ctxt);
const svalue *rhs2_sval = get_rvalue (rhs2, ctxt);
+ if (ctxt && (op == LSHIFT_EXPR || op == RSHIFT_EXPR))
+ {
+ /* "INT34-C. Do not shift an expression by a negative number of bits
+ or by greater than or equal to the number of bits that exist in
+ the operand." */
+ if (const tree rhs2_cst = rhs2_sval->maybe_get_constant ())
+ if (TREE_CODE (rhs2_cst) == INTEGER_CST)
+ {
+ if (tree_int_cst_sgn (rhs2_cst) < 0)
+ ctxt->warn (new shift_count_negative_diagnostic
+ (assign, rhs2_cst));
+ else if (compare_tree_int (rhs2_cst,
+ TYPE_PRECISION (TREE_TYPE (rhs1)))
+ >= 0)
+ ctxt->warn (new shift_count_overflow_diagnostic
+ (assign, TYPE_PRECISION (TREE_TYPE (rhs1)),
+ rhs2_cst));
+ }
+ }
+
const svalue *sval_binop
= m_mgr->get_or_create_binop (TREE_TYPE (lhs), op,
rhs1_sval, rhs2_sval);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 553cc07e330..69bf1fa89dd 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -425,6 +425,8 @@ Objective-C and Objective-C++ Dialects}.
-Wno-analyzer-null-dereference @gol
-Wno-analyzer-possible-null-argument @gol
-Wno-analyzer-possible-null-dereference @gol
+-Wno-analyzer-shift-count-negative @gol
+-Wno-analyzer-shift-count-overflow @gol
-Wno-analyzer-stale-setjmp-buffer @gol
-Wno-analyzer-tainted-array-index @gol
-Wanalyzer-too-complex @gol
@@ -8897,6 +8899,8 @@ Enabling this option effectively enables the following warnings:
-Wanalyzer-possible-null-dereference @gol
-Wanalyzer-null-argument @gol
-Wanalyzer-null-dereference @gol
+-Wanalyzer-shift-count-negative @gol
+-Wanalyzer-shift-count-overflow @gol
-Wanalyzer-stale-setjmp-buffer @gol
-Wanalyzer-tainted-array-index @gol
-Wanalyzer-unsafe-call-within-signal-handler @gol
@@ -9030,6 +9034,35 @@ This warning requires @option{-fanalyzer}, which enables it; use
This diagnostic warns for paths through the code in which a
value known to be NULL is dereferenced.
+@item -Wno-analyzer-shift-count-negative
+@opindex Wanalyzer-shift-count-negative
+@opindex Wno-analyzer-shift-count-negative
+This warning requires @option{-fanalyzer}, which enables it; use
+@option{-Wno-analyzer-shift-count-negative} to disable it.
+
+This diagnostic warns for paths through the code in which a
+shift is attempted with a negative count. It is analogous to
+the @option{-Wshift-count-negative} diagnostic implemented in
+the C/C++ front ends, but is implemented based on analyzing
+interprocedural paths, rather than merely parsing the syntax tree.
+However, the analyzer does not prioritize detection of such paths, so
+false negatives are more likely relative to other warnings.
+
+@item -Wno-analyzer-shift-count-overflow
+@opindex Wanalyzer-shift-count-overflow
+@opindex Wno-analyzer-shift-count-overflow
+This warning requires @option{-fanalyzer}, which enables it; use
+@option{-Wno-analyzer-shift-count-overflow} to disable it.
+
+This diagnostic warns for paths through the code in which a
+shift is attempted with a count greater than or equal to the
+precision of the operand's type. It is analogous to
+the @option{-Wshift-count-overflow} diagnostic implemented in
+the C/C++ front ends, but is implemented based on analyzing
+interprocedural paths, rather than merely parsing the syntax tree.
+However, the analyzer does not prioritize detection of such paths, so
+false negatives are more likely relative to other warnings.
+
@item -Wno-analyzer-stale-setjmp-buffer
@opindex Wanalyzer-stale-setjmp-buffer
@opindex Wno-analyzer-stale-setjmp-buffer
diff --git a/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c b/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c
new file mode 100644
index 00000000000..08e52728748
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/invalid-shift-1.c
@@ -0,0 +1,34 @@
+/* PR tree-optimization/97424. */
+
+#include <stdint.h>
+
+static inline uint32_t
+_dl_hwcaps_subdirs_build_bitmask (int subdirs, int active)
+{
+ /* Leading subdirectories that are not active. */
+ int inactive = subdirs - active;
+ if (inactive == 32)
+ return 0;
+
+ uint32_t mask;
+ if (subdirs != 32)
+ mask = (1 << subdirs) - 1; /* { dg-message "shift by count \\('33'\\) >= precision of type \\('\[0-9\]+'\\)" } */
+ else
+ mask = -1;
+ return mask ^ ((1U << inactive) - 1); /* { dg-message "shift by negative count \\('-1'\\)" } */
+}
+
+void f1 (int);
+
+void
+f2 (void)
+{
+ f1 (_dl_hwcaps_subdirs_build_bitmask (1, 2));
+ f1 (_dl_hwcaps_subdirs_build_bitmask (33, 31));
+}
+
+static int __attribute__((noinline)) op3 (int op, int c) { return op << c; } /* { dg-message "shift by negative count \\('-1'\\)" } */
+int test_3 (void) { return op3 (1, -1); }
+
+static int __attribute__((noinline)) op4 (int op, int c) { return op << c; }
+int test_4 (void) { return op4 (1, 0); }
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2020-11-12 2:18 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-11-12 2:18 [gcc r11-4930] analyzer: warn on invalid shift counts [PR97424] David Malcolm
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).