* [committed] analyzer: add notes to write-to-const/string from access attr [PR104793]
@ 2022-03-10 14:19 David Malcolm
0 siblings, 0 replies; only message in thread
From: David Malcolm @ 2022-03-10 14:19 UTC (permalink / raw)
To: gcc-patches
The previous patch extended
-Wanalyzer-write-to-const
-Wanalyzer-write-to-string-literal
to make use of __attribute__ ((access, ....), but the results could be
inscrutable.
This patch adds notes to such diagnostics to give the user a reason for
why the analyzer is complaining.
Example output:
test.c: In function 'main':
test.c:15:13: warning: write to string literal [-Wanalyzer-write-to-string-literal]
15 | if (getrandom((char *)test, sizeof(buf), GRND_RANDOM))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
'main': event 1
|
| 15 | if (getrandom((char *)test, sizeof(buf), GRND_RANDOM))
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (1) write to string literal here
|
test.c:3:5: note: parameter 1 of 'getrandom' marked with attribute 'access (write_only, 1, 2)'
3 | int getrandom (void *__buffer, size_t __length,
| ^~~~~~~~~
Unfortunately we don't have location information for the attributes
themselves, just the function declaration, and there doesn't seem to be
a good way of getting at the location of the individual parameters from
the middle end (the C and C++ FEs both have get_fndecl_argument_location,
but the implementations are different).
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r12-7596-gc65d3c7f9dade1.
gcc/analyzer/ChangeLog:
PR analyzer/104793
* analyzer.h (class pending_note): New forward decl.
* diagnostic-manager.cc (saved_diagnostic::saved_diagnostic):
Initialize m_notes.
(saved_diagnostic::operator==): Compare m_notes.
(saved_diagnostic::add_note): New.
(saved_diagnostic::emit_any_notes): New.
(diagnostic_manager::add_note): New.
(diagnostic_manager::emit_saved_diagnostic): Call emit_any_notes
after emitting the warning.
* diagnostic-manager.h (saved_diagnostic::add_note): New decl.
(saved_diagnostic::emit_any_notes): New decl.
(saved_diagnostic::m_notes): New field.
(diagnostic_manager::add_note): New decl.
* engine.cc (impl_region_model_context::add_note): New.
* exploded-graph.h (impl_region_model_context::add_note): New
decl.
* pending-diagnostic.h (class pending_note): New.
(class pending_note_subclass): New template.
* region-model.cc (class reason_attr_access): New.
(check_external_function_for_access_attr): Add class
annotating_ctxt and use it when checking region.
(noop_region_model_context::add_note): New.
* region-model.h (region_model_context::add_note): New vfunc.
(noop_region_model_context::add_note): New decl.
(class region_model_context_decorator): New.
(class note_adding_context): New.
gcc/testsuite/ChangeLog:
PR analyzer/104793
* gcc.dg/analyzer/write-to-const-2.c: Add dg-message directives
for expected notes.
* gcc.dg/analyzer/write-to-function-1.c: Likewise.
* gcc.dg/analyzer/write-to-string-literal-2.c: Likewise.
* gcc.dg/analyzer/write-to-string-literal-3.c: Likewise.
* gcc.dg/analyzer/write-to-string-literal-4.c: Likewise.
* gcc.dg/analyzer/write-to-string-literal-5.c: New test.
Signed-off-by: David Malcolm <dmalcolm@redhat.com>
---
gcc/analyzer/analyzer.h | 1 +
gcc/analyzer/diagnostic-manager.cc | 43 +++++-
gcc/analyzer/diagnostic-manager.h | 7 +
gcc/analyzer/engine.cc | 10 ++
gcc/analyzer/exploded-graph.h | 1 +
gcc/analyzer/pending-diagnostic.h | 43 ++++++
gcc/analyzer/region-model.cc | 73 ++++++++-
gcc/analyzer/region-model.h | 146 ++++++++++++++++++
.../gcc.dg/analyzer/write-to-const-2.c | 8 +-
.../gcc.dg/analyzer/write-to-function-1.c | 2 +-
.../analyzer/write-to-string-literal-2.c | 2 +-
.../analyzer/write-to-string-literal-3.c | 8 +-
.../analyzer/write-to-string-literal-4.c | 2 +-
.../analyzer/write-to-string-literal-5.c | 31 ++++
14 files changed, 362 insertions(+), 15 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/analyzer.h
index 36db4f2b538..223ab7075f3 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/analyzer.h
@@ -85,6 +85,7 @@ class bounded_ranges;
class bounded_ranges_manager;
class pending_diagnostic;
+class pending_note;
class state_change_event;
class checker_path;
class extrinsic_state;
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 680016e94bc..561bb18cee0 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -629,7 +629,8 @@ saved_diagnostic::saved_diagnostic (const state_machine *sm,
m_var (var), m_sval (sval), m_state (state),
m_d (d), m_trailing_eedge (NULL),
m_idx (idx),
- m_best_epath (NULL), m_problem (NULL)
+ m_best_epath (NULL), m_problem (NULL),
+ m_notes ()
{
gcc_assert (m_stmt || m_stmt_finder);
@@ -651,6 +652,11 @@ saved_diagnostic::~saved_diagnostic ()
bool
saved_diagnostic::operator== (const saved_diagnostic &other) const
{
+ if (m_notes.length () != other.m_notes.length ())
+ return false;
+ for (unsigned i = 0; i < m_notes.length (); i++)
+ if (!m_notes[i]->equal_p (*other.m_notes[i]))
+ return false;
return (m_sm == other.m_sm
/* We don't compare m_enode. */
&& m_snode == other.m_snode
@@ -662,6 +668,15 @@ saved_diagnostic::operator== (const saved_diagnostic &other) const
&& m_trailing_eedge == other.m_trailing_eedge);
}
+/* Add PN to this diagnostic, taking ownership of it. */
+
+void
+saved_diagnostic::add_note (pending_note *pn)
+{
+ gcc_assert (pn);
+ m_notes.safe_push (pn);
+}
+
/* Return a new json::object of the form
{"sm": optional str,
"enode": int,
@@ -697,6 +712,7 @@ saved_diagnostic::to_json () const
exploded_edge *m_trailing_eedge;
enum status m_status;
feasibility_problem *m_problem;
+ auto_delete_vec <pending_note> m_notes;
*/
return sd_obj;
@@ -769,6 +785,15 @@ saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
return m_d->supercedes_p (*other.m_d);
}
+/* Emit any pending notes owned by this diagnostic. */
+
+void
+saved_diagnostic::emit_any_notes () const
+{
+ for (auto pn : m_notes)
+ pn->emit ();
+}
+
/* State for building a checker_path from a particular exploded_path.
In particular, this precomputes reachability information: the set of
source enodes for which a path be found to the diagnostic enode. */
@@ -875,6 +900,20 @@ diagnostic_manager::add_diagnostic (exploded_node *enode,
add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE, NULL, 0, d);
}
+/* Add PN to the most recent saved_diagnostic. */
+
+void
+diagnostic_manager::add_note (pending_note *pn)
+{
+ LOG_FUNC (get_logger ());
+ gcc_assert (pn);
+
+ /* Get most recent saved_diagnostic. */
+ gcc_assert (m_saved_diagnostics.length () > 0);
+ saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
+ sd->add_note (pn);
+}
+
/* Return a new json::object of the form
{"diagnostics" : [obj for saved_diagnostic]}. */
@@ -1240,6 +1279,8 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
auto_cfun sentinel (sd.m_snode->m_fun);
if (sd.m_d->emit (&rich_loc))
{
+ sd.emit_any_notes ();
+
unsigned num_dupes = sd.get_num_dupes ();
if (flag_analyzer_show_duplicate_count && num_dupes > 0)
inform_n (loc, num_dupes,
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index cfc0d86a871..e9a568fd768 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -42,6 +42,8 @@ public:
bool operator== (const saved_diagnostic &other) const;
+ void add_note (pending_note *pn);
+
json::object *to_json () const;
const feasibility_problem *get_feasibility_problem () const
@@ -60,6 +62,8 @@ public:
bool supercedes_p (const saved_diagnostic &other) const;
+ void emit_any_notes () const;
+
//private:
const state_machine *m_sm;
const exploded_node *m_enode;
@@ -80,6 +84,7 @@ private:
feasibility_problem *m_problem; // owned
auto_vec<const saved_diagnostic *> m_duplicates;
+ auto_delete_vec <pending_note> m_notes;
};
class path_builder;
@@ -116,6 +121,8 @@ public:
stmt_finder *finder,
pending_diagnostic *d);
+ void add_note (pending_note *pn);
+
void emit_saved_diagnostics (const exploded_graph &eg);
void emit_saved_diagnostic (const exploded_graph &eg,
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 8c3133e2444..92dadea7cb6 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -142,6 +142,16 @@ impl_region_model_context::warn (pending_diagnostic *d)
}
}
+void
+impl_region_model_context::add_note (pending_note *pn)
+{
+ LOG_FUNC (get_logger ());
+ if (m_eg)
+ m_eg->get_diagnostic_manager ().add_note (pn);
+ else
+ delete pn;
+}
+
void
impl_region_model_context::on_svalue_leak (const svalue *sval)
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 1f52725dc98..af0ab8d42c8 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -48,6 +48,7 @@ class impl_region_model_context : public region_model_context
logger *logger = NULL);
bool warn (pending_diagnostic *d) FINAL OVERRIDE;
+ void add_note (pending_note *pn) FINAL OVERRIDE;
void on_svalue_leak (const svalue *) OVERRIDE;
void on_liveness_change (const svalue_set &live_svalues,
const region_model *model) FINAL OVERRIDE;
diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h
index 5a407c82869..0a438fddb26 100644
--- a/gcc/analyzer/pending-diagnostic.h
+++ b/gcc/analyzer/pending-diagnostic.h
@@ -329,6 +329,49 @@ class pending_diagnostic_subclass : public pending_diagnostic
}
};
+/* An abstract base class for capturing additional notes that are to be
+ emitted with a diagnostic. */
+
+class pending_note
+{
+public:
+ virtual ~pending_note () {}
+
+ /* Hand-coded RTTI: get an ID for the subclass. */
+ virtual const char *get_kind () const = 0;
+
+ /* Vfunc for emitting the note. */
+ virtual void emit () const = 0;
+
+ bool equal_p (const pending_note &other) const
+ {
+ /* Check for pointer equality on the IDs from get_kind. */
+ if (get_kind () != other.get_kind ())
+ return false;
+ /* Call vfunc now we know they have the same ID: */
+ return subclass_equal_p (other);
+ }
+
+ /* A vfunc for testing for equality, where we've already
+ checked they have the same ID. See pending_note_subclass
+ below for a convenience subclass for implementing this. */
+ virtual bool subclass_equal_p (const pending_note &other) const = 0;
+};
+
+/* Analogous to pending_diagnostic_subclass, but for pending_note. */
+
+template <class Subclass>
+class pending_note_subclass : public pending_note
+{
+ public:
+ bool subclass_equal_p (const pending_note &base_other) const
+ FINAL OVERRIDE
+ {
+ const Subclass &other = (const Subclass &)base_other;
+ return *(const Subclass*)this == other;
+ }
+};
+
} // namespace ana
#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 5760ff70938..6406627db90 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1583,6 +1583,41 @@ region_model::purge_state_involving (const svalue *sval,
ctxt->purge_state_involving (sval);
}
+/* A pending_note subclass for adding a note about an
+ __attribute__((access, ...)) to a diagnostic. */
+
+class reason_attr_access : public pending_note_subclass<reason_attr_access>
+{
+public:
+ reason_attr_access (tree callee_fndecl, const attr_access &access)
+ : m_callee_fndecl (callee_fndecl),
+ m_ptr_argno (access.ptrarg),
+ m_access_str (TREE_STRING_POINTER (access.to_external_string ()))
+ {
+ }
+
+ const char *get_kind () const FINAL OVERRIDE { return "reason_attr_access"; }
+
+ void emit () const
+ {
+ inform (DECL_SOURCE_LOCATION (m_callee_fndecl),
+ "parameter %i of %qD marked with attribute %qs",
+ m_ptr_argno + 1, m_callee_fndecl, m_access_str);
+ }
+
+ bool operator== (const reason_attr_access &other) const
+ {
+ return (m_callee_fndecl == other.m_callee_fndecl
+ && m_ptr_argno == other.m_ptr_argno
+ && !strcmp (m_access_str, other.m_access_str));
+ }
+
+private:
+ tree m_callee_fndecl;
+ unsigned m_ptr_argno;
+ const char *m_access_str;
+};
+
/* Check CALL a call to external function CALLEE_FNDECL based on
any __attribute__ ((access, ....) on the latter, complaining to
CTXT about any issues.
@@ -1629,10 +1664,36 @@ check_external_function_for_access_attr (const gcall *call,
if (access->mode == access_write_only
|| access->mode == access_read_write)
{
+ /* Subclass of decorated_region_model_context that
+ adds a note about the attr access to any saved diagnostics. */
+ class annotating_ctxt : public note_adding_context
+ {
+ public:
+ annotating_ctxt (tree callee_fndecl,
+ const attr_access &access,
+ region_model_context *ctxt)
+ : note_adding_context (ctxt),
+ m_callee_fndecl (callee_fndecl),
+ m_access (access)
+ {
+ }
+ pending_note *make_note () FINAL OVERRIDE
+ {
+ return new reason_attr_access (m_callee_fndecl, m_access);
+ }
+ private:
+ tree m_callee_fndecl;
+ const attr_access &m_access;
+ };
+
+ /* Use this ctxt below so that any diagnostics get the
+ note added to them. */
+ annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt);
+
tree ptr_tree = gimple_call_arg (call, access->ptrarg);
- const svalue *ptr_sval = get_rvalue (ptr_tree, ctxt);
- const region *reg = deref_rvalue (ptr_sval, ptr_tree, ctxt);
- check_region_for_write (reg, ctxt);
+ const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt);
+ const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt);
+ check_region_for_write (reg, &my_ctxt);
/* We don't use the size arg for now. */
}
}
@@ -4148,6 +4209,12 @@ region_model::unset_dynamic_extents (const region *reg)
/* class noop_region_model_context : public region_model_context. */
+void
+noop_region_model_context::add_note (pending_note *pn)
+{
+ delete pn;
+}
+
void
noop_region_model_context::bifurcate (custom_edge_info *info)
{
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 788d0c22bca..4ee8a765e72 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -881,6 +881,10 @@ class region_model_context
Return true if the diagnostic was stored, or false if it was deleted. */
virtual bool warn (pending_diagnostic *d) = 0;
+ /* Hook for clients to add a note to the last previously stored pending diagnostic.
+ Takes ownership of the pending_node (or deletes it). */
+ virtual void add_note (pending_note *pn) = 0;
+
/* Hook for clients to be notified when an SVAL that was reachable
in a previous state is no longer live, so that clients can emit warnings
about leaks. */
@@ -954,6 +958,7 @@ class noop_region_model_context : public region_model_context
{
public:
bool warn (pending_diagnostic *) OVERRIDE { return false; }
+ void add_note (pending_note *pn) OVERRIDE;
void on_svalue_leak (const svalue *) OVERRIDE {}
void on_liveness_change (const svalue_set &,
const region_model *) OVERRIDE {}
@@ -1020,6 +1025,147 @@ private:
int m_num_unexpected_codes;
};
+/* Subclass of region_model_context that wraps another context, allowing
+ for extra code to be added to the various hooks. */
+
+class region_model_context_decorator : public region_model_context
+{
+ public:
+ bool warn (pending_diagnostic *d) OVERRIDE
+ {
+ return m_inner->warn (d);
+ }
+
+ void add_note (pending_note *pn) OVERRIDE
+ {
+ m_inner->add_note (pn);
+ }
+
+ void on_svalue_leak (const svalue *sval) OVERRIDE
+ {
+ m_inner->on_svalue_leak (sval);
+ }
+
+ void on_liveness_change (const svalue_set &live_svalues,
+ const region_model *model) OVERRIDE
+ {
+ m_inner->on_liveness_change (live_svalues, model);
+ }
+
+ logger *get_logger () OVERRIDE
+ {
+ return m_inner->get_logger ();
+ }
+
+ void on_condition (const svalue *lhs,
+ enum tree_code op,
+ const svalue *rhs) OVERRIDE
+ {
+ m_inner->on_condition (lhs, op, rhs);
+ }
+
+ void on_unknown_change (const svalue *sval, bool is_mutable) OVERRIDE
+ {
+ m_inner->on_unknown_change (sval, is_mutable);
+ }
+
+ void on_phi (const gphi *phi, tree rhs) OVERRIDE
+ {
+ m_inner->on_phi (phi, rhs);
+ }
+
+ void on_unexpected_tree_code (tree t,
+ const dump_location_t &loc) OVERRIDE
+ {
+ m_inner->on_unexpected_tree_code (t, loc);
+ }
+
+ void on_escaped_function (tree fndecl) OVERRIDE
+ {
+ m_inner->on_escaped_function (fndecl);
+ }
+
+ uncertainty_t *get_uncertainty () OVERRIDE
+ {
+ return m_inner->get_uncertainty ();
+ }
+
+ void purge_state_involving (const svalue *sval) OVERRIDE
+ {
+ m_inner->purge_state_involving (sval);
+ }
+
+ void bifurcate (custom_edge_info *info) OVERRIDE
+ {
+ m_inner->bifurcate (info);
+ }
+
+ void terminate_path () OVERRIDE
+ {
+ m_inner->terminate_path ();
+ }
+
+ const extrinsic_state *get_ext_state () const OVERRIDE
+ {
+ return m_inner->get_ext_state ();
+ }
+
+ bool get_malloc_map (sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx) OVERRIDE
+ {
+ return m_inner->get_malloc_map (out_smap, out_sm, out_sm_idx);
+ }
+
+ bool get_taint_map (sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx) OVERRIDE
+ {
+ return m_inner->get_taint_map (out_smap, out_sm, out_sm_idx);
+ }
+
+ const gimple *get_stmt () const OVERRIDE
+ {
+ return m_inner->get_stmt ();
+ }
+
+protected:
+ region_model_context_decorator (region_model_context *inner)
+ : m_inner (inner)
+ {
+ gcc_assert (m_inner);
+ }
+
+ region_model_context *m_inner;
+};
+
+/* Subclass of region_model_context_decorator that adds a note
+ when saving diagnostics. */
+
+class note_adding_context : public region_model_context_decorator
+{
+public:
+ bool warn (pending_diagnostic *d) OVERRIDE
+ {
+ if (m_inner->warn (d))
+ {
+ add_note (make_note ());
+ return true;
+ }
+ else
+ return false;
+ }
+
+ /* Hook to make the new note. */
+ virtual pending_note *make_note () = 0;
+
+protected:
+ note_adding_context (region_model_context *inner)
+ : region_model_context_decorator (inner)
+ {
+ }
+};
+
/* A bundle of data for use when attempting to merge two region_model
instances to make a third. */
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c b/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
index d0f2f29e985..bd9f3c667ee 100644
--- a/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-const-2.c
@@ -2,17 +2,17 @@ typedef __SIZE_TYPE__ size_t;
void read_only (void *)
__attribute__ ((access (read_only, 1)));
-void write_only (void *)
+void write_only (void *) /* { dg-message "parameter 1 of 'write_only' marked with attribute 'access \\(write_only, 1\\)'" } */
__attribute__ ((access (write_only, 1)));
-void read_write (void *)
+void read_write (void *) /* { dg-message "parameter 1 of 'read_write' marked with attribute 'access \\(read_write, 1\\)'" } */
__attribute__ ((access (read_write, 1)));
void none (void *)
__attribute__ ((access (none, 1)));
void read_only_with_size (void *, size_t)
__attribute__ ((access (read_only, 1, 2)));
-void write_only_with_size (void *, size_t)
+void write_only_with_size (void *, size_t) /* { dg-message "parameter 1 of 'write_only_with_size' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
__attribute__ ((access (write_only, 1, 2)));
-void read_write_with_size (void *, size_t)
+void read_write_with_size (void *, size_t) /* { dg-message "parameter 1 of 'read_write_with_size' marked with attribute 'access \\(read_write, 1, 2\\)'" } */
__attribute__ ((access (read_write, 1, 2)));
void none_with_size (void *, size_t)
__attribute__ ((access (none, 1, 2)));
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
index 38374ddf9e4..c1bece632ce 100644
--- a/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-function-1.c
@@ -1,6 +1,6 @@
typedef __SIZE_TYPE__ size_t;
-int getrandom (void *__buffer, size_t __length,
+int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
unsigned int __flags)
__attribute__ ((access (__write_only__, 1, 2)));
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
index e5906cd5546..657ada64cea 100644
--- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-2.c
@@ -1,6 +1,6 @@
typedef __SIZE_TYPE__ size_t;
-int getrandom (void *__buffer, size_t __length,
+int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
unsigned int __flags)
__attribute__ ((access (__write_only__, 1, 2)));
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
index 7f4fb4f3aa0..9d5d07d4d19 100644
--- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-3.c
@@ -2,17 +2,17 @@ typedef __SIZE_TYPE__ size_t;
void read_only (void *)
__attribute__ ((access (read_only, 1)));
-void write_only (void *)
+void write_only (void *) /* { dg-message "parameter 1 of 'write_only' marked with attribute 'access \\(write_only, 1\\)'" } */
__attribute__ ((access (write_only, 1)));
-void read_write (void *)
+void read_write (void *) /* { dg-message "parameter 1 of 'read_write' marked with attribute 'access \\(read_write, 1\\)'" } */
__attribute__ ((access (read_write, 1)));
void none (void *)
__attribute__ ((access (none, 1)));
void read_only_with_size (void *, size_t)
__attribute__ ((access (read_only, 1, 2)));
-void write_only_with_size (void *, size_t)
+void write_only_with_size (void *, size_t) /* { dg-message "parameter 1 of 'write_only_with_size' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
__attribute__ ((access (write_only, 1, 2)));
-void read_write_with_size (void *, size_t)
+void read_write_with_size (void *, size_t) /* { dg-message "parameter 1 of 'read_write_with_size' marked with attribute 'access \\(read_write, 1, 2\\)'" } */
__attribute__ ((access (read_write, 1, 2)));
void none_with_size (void *, size_t)
__attribute__ ((access (none, 1, 2)));
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
index 3d3270ffdbb..a8f600f81a3 100644
--- a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-4.c
@@ -1,6 +1,6 @@
typedef __SIZE_TYPE__ size_t;
-int getrandom (void *__buffer, size_t __length,
+int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
unsigned int __flags)
__attribute__ ((access (__write_only__, 1, 2)));
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c
new file mode 100644
index 00000000000..b7ac4659012
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-5.c
@@ -0,0 +1,31 @@
+/* Verify that deduplication of -Wanalyzer-write-to-string-literal (and their
+ notes) works. */
+
+/* { dg-additional-options "-fanalyzer-show-duplicate-count" } */
+
+#include "analyzer-decls.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+int getrandom (void *__buffer, size_t __length, /* { dg-message "parameter 1 of 'getrandom' marked with attribute 'access \\(write_only, 1, 2\\)'" } */
+ unsigned int __flags)
+ __attribute__ ((access (__write_only__, 1, 2)));
+
+#define GRND_RANDOM 0x02
+
+void *test (int flag)
+{
+ char *ptr;
+ if (flag)
+ ptr = __builtin_malloc (1024);
+ else
+ ptr = __builtin_alloca (1024);
+
+ __analyzer_dump_exploded_nodes (0); /* { dg-warning "2 processed enodes" } */
+
+ if (getrandom((char *)"foo", 3, GRND_RANDOM)) /* { dg-warning "write to string literal" "warning" } */
+ /* { dg-message "1 duplicate" "dup" { target *-*-* } .-1 } */
+ __builtin_printf("ok\n");
+
+ return ptr;
+}
--
2.26.3
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-03-10 14:20 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-10 14:19 [committed] analyzer: add notes to write-to-const/string from access attr [PR104793] 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).