From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id B98D23857C68 for ; Thu, 10 Mar 2022 14:20:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B98D23857C68 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-349-5i2AZxV5OdKITC78EnVhfQ-1; Thu, 10 Mar 2022 09:20:05 -0500 X-MC-Unique: 5i2AZxV5OdKITC78EnVhfQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6BC90824FA6 for ; Thu, 10 Mar 2022 14:20:04 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.210]) by smtp.corp.redhat.com (Postfix) with ESMTP id E462C7B8C9; Thu, 10 Mar 2022 14:20:00 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Subject: [committed] analyzer: add notes to write-to-const/string from access attr [PR104793] Date: Thu, 10 Mar 2022 09:19:59 -0500 Message-Id: <20220310141959.3402712-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-12.3 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 10 Mar 2022 14:20:12 -0000 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 --- 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 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 m_duplicates; + auto_delete_vec 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 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 +{ +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