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 AE3B13947434 for ; Wed, 16 Mar 2022 18:06:46 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AE3B13947434 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-627-FmrHrBJePxiFJWmkULZyiQ-1; Wed, 16 Mar 2022 14:06:41 -0400 X-MC-Unique: FmrHrBJePxiFJWmkULZyiQ-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 955E12999B59 for ; Wed, 16 Mar 2022 18:06:40 +0000 (UTC) Received: from t14s.localdomain.com (unknown [10.2.17.210]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5FCCB441964; Wed, 16 Mar 2022 18:06:40 +0000 (UTC) From: David Malcolm To: gcc-patches@gcc.gnu.org Subject: [committed] analyzer: early rejection of disabled warnings [PR104955] Date: Wed, 16 Mar 2022 14:06:38 -0400 Message-Id: <20220316180638.4039810-1-dmalcolm@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 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.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, 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: Wed, 16 Mar 2022 18:07:05 -0000 Avoid generating execution paths for warnings that are ultimately rejected due to -Wno-analyzer-* flags. This improves the test case from taking at least several minutes (before I killed it) to taking under a second. This doesn't fix the slowdown seen in PR analyzer/104955 with large numbers of warnings when the warnings are still enabled. Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r12-7677-g7fd6e36ea9aa85. gcc/analyzer/ChangeLog: PR analyzer/104955 * diagnostic-manager.cc (get_emission_location): New. (diagnostic_manager::diagnostic_manager): Initialize m_num_disabled_diagnostics. (diagnostic_manager::add_diagnostic): Reject diagnostics that will eventually be rejected due to being disabled. (diagnostic_manager::emit_saved_diagnostics): Log the number of disabled diagnostics. (diagnostic_manager::emit_saved_diagnostic): Split out logic for determining emission location to get_emission_location. * diagnostic-manager.h (diagnostic_manager::m_num_disabled_diagnostics): New field. * engine.cc (stale_jmp_buf::get_controlling_option): New. (stale_jmp_buf::emit): Use it. * pending-diagnostic.h (pending_diagnostic::get_controlling_option): New vfunc. * region-model.cc (poisoned_value_diagnostic::get_controlling_option): New. (poisoned_value_diagnostic::emit): Use it. (shift_count_negative_diagnostic::get_controlling_option): New. (shift_count_negative_diagnostic::emit): Use it. (shift_count_overflow_diagnostic::get_controlling_option): New. (shift_count_overflow_diagnostic::emit): Use it. (dump_path_diagnostic::get_controlling_option): New. (dump_path_diagnostic::emit): Use it. (write_to_const_diagnostic::get_controlling_option): New. (write_to_const_diagnostic::emit): Use it. (write_to_string_literal_diagnostic::get_controlling_option): New. (write_to_string_literal_diagnostic::emit): Use it. * sm-file.cc (double_fclose::get_controlling_option): New. (double_fclose::emit): Use it. (file_leak::get_controlling_option): New. (file_leak::emit): Use it. * sm-malloc.cc (mismatching_deallocation::get_controlling_option): New. (mismatching_deallocation::emit): Use it. (double_free::get_controlling_option): New. (double_free::emit): Use it. (possible_null_deref::get_controlling_option): New. (possible_null_deref::emit): Use it. (possible_null_arg::get_controlling_option): New. (possible_null_arg::emit): Use it. (null_deref::get_controlling_option): New. (null_deref::emit): Use it. (null_arg::get_controlling_option): New. (null_arg::emit): Use it. (use_after_free::get_controlling_option): New. (use_after_free::emit): Use it. (malloc_leak::get_controlling_option): New. (malloc_leak::emit): Use it. (free_of_non_heap::get_controlling_option): New. (free_of_non_heap::emit): Use it. * sm-pattern-test.cc (pattern_match::get_controlling_option): New. (pattern_match::emit): Use it. * sm-sensitive.cc (exposure_through_output_file::get_controlling_option): New. (exposure_through_output_file::emit): Use it. * sm-signal.cc (signal_unsafe_call::get_controlling_option): New. (signal_unsafe_call::emit): Use it. * sm-taint.cc (tainted_array_index::get_controlling_option): New. (tainted_array_index::emit): Use it. (tainted_offset::get_controlling_option): New. (tainted_offset::emit): Use it. (tainted_size::get_controlling_option): New. (tainted_size::emit): Use it. (tainted_divisor::get_controlling_option): New. (tainted_divisor::emit): Use it. (tainted_allocation_size::get_controlling_option): New. (tainted_allocation_size::emit): Use it. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/many-disabled-diagnostics.c: New test. * gcc.dg/plugin/analyzer_gil_plugin.c (gil_diagnostic::get_controlling_option): New. (double_save_thread::emit): Use it. (fncall_without_gil::emit): Likewise. (pyobject_usage_without_gil::emit): Likewise. Signed-off-by: David Malcolm --- gcc/analyzer/diagnostic-manager.cc | 44 ++++++++++-- gcc/analyzer/diagnostic-manager.h | 1 + gcc/analyzer/engine.cc | 7 +- gcc/analyzer/pending-diagnostic.h | 6 ++ gcc/analyzer/region-model.cc | 61 ++++++++++++---- gcc/analyzer/sm-file.cc | 16 ++++- gcc/analyzer/sm-malloc.cc | 72 +++++++++++++++---- gcc/analyzer/sm-pattern-test.cc | 8 ++- gcc/analyzer/sm-sensitive.cc | 8 ++- gcc/analyzer/sm-signal.cc | 8 ++- gcc/analyzer/sm-taint.cc | 71 +++++++++++------- .../analyzer/many-disabled-diagnostics.c | 55 ++++++++++++++ .../gcc.dg/plugin/analyzer_gil_plugin.c | 16 +++-- 13 files changed, 300 insertions(+), 73 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/analyzer/many-disabled-diagnostics.c diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 561bb18cee0..d5e5b6926cc 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -849,13 +849,28 @@ private: const feasibility_problem *m_feasibility_problem; }; +/* Determine the emission location for PD at STMT in FUN. */ + +static location_t +get_emission_location (const gimple *stmt, function *fun, + const pending_diagnostic &pd) +{ + location_t loc = get_stmt_location (stmt, fun); + + /* Allow the pending_diagnostic to fix up the location. */ + loc = pd.fixup_location (loc); + + return loc; +} + /* class diagnostic_manager. */ /* diagnostic_manager's ctor. */ diagnostic_manager::diagnostic_manager (logger *logger, engine *eng, int verbosity) -: log_user (logger), m_eng (eng), m_verbosity (verbosity) +: log_user (logger), m_eng (eng), m_verbosity (verbosity), + m_num_disabled_diagnostics (0) { } @@ -877,6 +892,25 @@ diagnostic_manager::add_diagnostic (const state_machine *sm, through the exploded_graph to the diagnostic. */ gcc_assert (enode); + /* If this warning is ultimately going to be rejected by a -Wno-analyzer-* + flag, reject it now. + We can only do this for diagnostics where we already know the stmt, + and thus can determine the emission location. */ + if (stmt) + { + location_t loc = get_emission_location (stmt, snode->m_fun, *d); + int option = d->get_controlling_option (); + if (!warning_enabled_at (loc, option)) + { + if (get_logger ()) + get_logger ()->log ("rejecting disabled warning %qs", + d->get_kind ()); + delete d; + m_num_disabled_diagnostics++; + return; + } + } + saved_diagnostic *sd = new saved_diagnostic (sm, enode, snode, stmt, finder, var, sval, state, d, m_saved_diagnostics.length ()); @@ -1186,6 +1220,7 @@ diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg) LOG_SCOPE (get_logger ()); auto_timevar tv (TV_ANALYZER_DIAGNOSTICS); log ("# saved diagnostics: %i", m_saved_diagnostics.length ()); + log ("# disabled diagnostics: %i", m_num_disabled_diagnostics); if (get_logger ()) { unsigned i; @@ -1265,11 +1300,10 @@ diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg, emission_path.prepare_for_emission (sd.m_d); - location_t loc = get_stmt_location (sd.m_stmt, sd.m_snode->m_fun); + location_t loc + = get_emission_location (sd.m_stmt, sd.m_snode->m_fun, *sd.m_d); - /* Allow the pending_diagnostic to fix up the primary location - and any locations for events. */ - loc = sd.m_d->fixup_location (loc); + /* Allow the pending_diagnostic to fix up the locations of events. */ emission_path.fixup_locations (sd.m_d); gcc_rich_location rich_loc (loc); diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h index e9a568fd768..34abf56d11f 100644 --- a/gcc/analyzer/diagnostic-manager.h +++ b/gcc/analyzer/diagnostic-manager.h @@ -179,6 +179,7 @@ private: engine *m_eng; auto_delete_vec m_saved_diagnostics; const int m_verbosity; + int m_num_disabled_diagnostics; }; } // namespace ana diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 92dadea7cb6..3c5d3986352 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -1526,10 +1526,15 @@ public: m_setjmp_point (setjmp_point), m_stack_pop_event (NULL) {} + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_stale_setjmp_buffer; + } + bool emit (rich_location *richloc) FINAL OVERRIDE { return warning_at - (richloc, OPT_Wanalyzer_stale_setjmp_buffer, + (richloc, get_controlling_option (), "%qs called after enclosing function of %qs has returned", get_user_facing_name (m_longjmp_call), get_user_facing_name (m_setjmp_call)); diff --git a/gcc/analyzer/pending-diagnostic.h b/gcc/analyzer/pending-diagnostic.h index 0a438fddb26..51039ea1ba5 100644 --- a/gcc/analyzer/pending-diagnostic.h +++ b/gcc/analyzer/pending-diagnostic.h @@ -162,6 +162,12 @@ class pending_diagnostic public: virtual ~pending_diagnostic () {} + /* Vfunc to get the command-line option used when emitting the diagnostic, + or zero if there is none. + Used by diagnostic_manager for early rejection of diagnostics (to avoid + having to generate feasible execution paths for them). */ + virtual int get_controlling_option () const = 0; + /* Vfunc for emitting the diagnostic. The rich_location will have been populated with a diagnostic_path. Return true if a diagnostic is actually emitted. */ diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 6406627db90..1bc71c02849 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -479,6 +479,21 @@ public: && m_src_region == other.m_src_region); } + int get_controlling_option () const FINAL OVERRIDE + { + switch (m_pkind) + { + default: + gcc_unreachable (); + case POISON_KIND_UNINIT: + return OPT_Wanalyzer_use_of_uninitialized_value; + case POISON_KIND_FREED: + return OPT_Wanalyzer_use_after_free; + case POISON_KIND_POPPED_STACK: + return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame; + } + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { switch (m_pkind) @@ -489,8 +504,7 @@ public: { diagnostic_metadata m; m.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */ - return warning_meta (rich_loc, m, - OPT_Wanalyzer_use_of_uninitialized_value, + return warning_meta (rich_loc, m, get_controlling_option (), "use of uninitialized value %qE", m_expr); } @@ -499,8 +513,7 @@ public: { diagnostic_metadata m; m.add_cwe (416); /* "CWE-416: Use After Free". */ - return warning_meta (rich_loc, m, - OPT_Wanalyzer_use_after_free, + return warning_meta (rich_loc, m, get_controlling_option (), "use after % of %qE", m_expr); } @@ -509,8 +522,7 @@ public: { /* TODO: which CWE? */ return warning_at - (rich_loc, - OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame, + (rich_loc, get_controlling_option (), "dereferencing pointer %qE to within stale stack frame", m_expr); } @@ -571,9 +583,14 @@ public: && same_tree_p (m_count_cst, other.m_count_cst)); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_shift_count_negative; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, OPT_Wanalyzer_shift_count_negative, + return warning_at (rich_loc, get_controlling_option (), "shift by negative count (%qE)", m_count_cst); } @@ -613,9 +630,14 @@ public: && same_tree_p (m_count_cst, other.m_count_cst)); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_shift_count_overflow; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, OPT_Wanalyzer_shift_count_overflow, + return warning_at (rich_loc, get_controlling_option (), "shift by count (%qE) >= precision of type (%qi)", m_count_cst, m_operand_precision); } @@ -1095,6 +1117,11 @@ class dump_path_diagnostic : public pending_diagnostic_subclass { public: + int get_controlling_option () const FINAL OVERRIDE + { + return 0; + } + bool emit (rich_location *richloc) FINAL OVERRIDE { inform (richloc, "path"); @@ -2534,6 +2561,11 @@ public: && m_decl == other.m_decl); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_write_to_const; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; @@ -2541,15 +2573,15 @@ public: switch (m_reg->get_kind ()) { default: - warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + warned = warning_at (rich_loc, get_controlling_option (), "write to % object %qE", m_decl); break; case RK_FUNCTION: - warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + warned = warning_at (rich_loc, get_controlling_option (), "write to function %qE", m_decl); break; case RK_LABEL: - warned = warning_at (rich_loc, OPT_Wanalyzer_write_to_const, + warned = warning_at (rich_loc, get_controlling_option (), "write to label %qE", m_decl); break; } @@ -2597,9 +2629,14 @@ public: return m_reg == other.m_reg; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_write_to_string_literal; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, OPT_Wanalyzer_write_to_string_literal, + return warning_at (rich_loc, get_controlling_option (), "write to string literal"); /* Ideally we would show the location of the STRING_CST as well, but it is not available at this point. */ diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc index 1c996f946f6..ffc2809dc57 100644 --- a/gcc/analyzer/sm-file.cc +++ b/gcc/analyzer/sm-file.cc @@ -157,9 +157,14 @@ public: const char *get_kind () const FINAL OVERRIDE { return "double_fclose"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_double_fclose; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, OPT_Wanalyzer_double_fclose, + return warning_at (rich_loc, get_controlling_option (), "double % of FILE %qE", m_arg); } @@ -197,6 +202,11 @@ public: const char *get_kind () const FINAL OVERRIDE { return "file_leak"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_file_leak; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; @@ -204,11 +214,11 @@ public: Effective Lifetime". */ m.add_cwe (775); if (m_arg) - return warning_meta (rich_loc, m, OPT_Wanalyzer_file_leak, + return warning_meta (rich_loc, m, get_controlling_option (), "leak of FILE %qE", m_arg); else - return warning_meta (rich_loc, m, OPT_Wanalyzer_file_leak, + return warning_meta (rich_loc, m, get_controlling_option (), "leak of FILE"); } diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc index a5fa60d020b..4c030803e59 100644 --- a/gcc/analyzer/sm-malloc.cc +++ b/gcc/analyzer/sm-malloc.cc @@ -760,6 +760,11 @@ public: return "mismatching_deallocation"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_mismatching_deallocation; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; @@ -767,13 +772,13 @@ public: m.add_cwe (762); /* CWE-762: Mismatched Memory Management Routines. */ if (const deallocator *expected_dealloc = m_expected_deallocators->maybe_get_single ()) - return warning_meta (rich_loc, m, OPT_Wanalyzer_mismatching_deallocation, + return warning_meta (rich_loc, m, get_controlling_option (), "%qE should have been deallocated with %qs" " but was deallocated with %qs", m_arg, expected_dealloc->m_name, m_actual_dealloc->m_name); else - return warning_meta (rich_loc, m, OPT_Wanalyzer_mismatching_deallocation, + return warning_meta (rich_loc, m, get_controlling_option (), "%qs called on %qE returned from a mismatched" " allocation function", m_actual_dealloc->m_name, m_arg); @@ -834,12 +839,17 @@ public: const char *get_kind () const FINAL OVERRIDE { return "double_free"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_double_free; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; diagnostic_metadata m; m.add_cwe (415); /* CWE-415: Double Free. */ - return warning_meta (rich_loc, m, OPT_Wanalyzer_double_free, + return warning_meta (rich_loc, m, get_controlling_option (), "double-%qs of %qE", m_funcname, m_arg); } @@ -925,13 +935,17 @@ public: const char *get_kind () const FINAL OVERRIDE { return "possible_null_deref"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_possible_null_dereference; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { /* CWE-690: Unchecked Return Value to NULL Pointer Dereference. */ diagnostic_metadata m; m.add_cwe (690); - return warning_meta (rich_loc, m, - OPT_Wanalyzer_possible_null_dereference, + return warning_meta (rich_loc, m, get_controlling_option (), "dereference of possibly-NULL %qE", m_arg); } @@ -1010,6 +1024,10 @@ public: && m_arg_idx == sub_other.m_arg_idx); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_possible_null_argument; + } bool emit (rich_location *rich_loc) FINAL OVERRIDE { @@ -1018,7 +1036,7 @@ public: diagnostic_metadata m; m.add_cwe (690); bool warned - = warning_meta (rich_loc, m, OPT_Wanalyzer_possible_null_argument, + = warning_meta (rich_loc, m, get_controlling_option (), "use of possibly-NULL %qE where non-null expected", m_arg); if (warned) @@ -1058,13 +1076,17 @@ public: const char *get_kind () const FINAL OVERRIDE { return "null_deref"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_null_dereference; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { /* CWE-476: NULL Pointer Dereference. */ diagnostic_metadata m; m.add_cwe (476); - return warning_meta (rich_loc, m, - OPT_Wanalyzer_null_dereference, + return warning_meta (rich_loc, m, get_controlling_option (), "dereference of NULL %qE", m_arg); } @@ -1106,6 +1128,11 @@ public: && m_arg_idx == sub_other.m_arg_idx); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_null_argument; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { /* CWE-476: NULL Pointer Dereference. */ @@ -1115,10 +1142,10 @@ public: bool warned; if (zerop (m_arg)) - warned = warning_meta (rich_loc, m, OPT_Wanalyzer_null_argument, + warned = warning_meta (rich_loc, m, get_controlling_option (), "use of NULL where non-null expected"); else - warned = warning_meta (rich_loc, m, OPT_Wanalyzer_null_argument, + warned = warning_meta (rich_loc, m, get_controlling_option (), "use of NULL %qE where non-null expected", m_arg); if (warned) @@ -1159,12 +1186,17 @@ public: const char *get_kind () const FINAL OVERRIDE { return "use_after_free"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_use_after_free; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { /* CWE-416: Use After Free. */ diagnostic_metadata m; m.add_cwe (416); - return warning_meta (rich_loc, m, OPT_Wanalyzer_use_after_free, + return warning_meta (rich_loc, m, get_controlling_option (), "use after %<%s%> of %qE", m_deallocator->m_name, m_arg); } @@ -1248,15 +1280,20 @@ public: const char *get_kind () const FINAL OVERRIDE { return "malloc_leak"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_malloc_leak; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; m.add_cwe (401); if (m_arg) - return warning_meta (rich_loc, m, OPT_Wanalyzer_malloc_leak, + return warning_meta (rich_loc, m, get_controlling_option (), "leak of %qE", m_arg); else - return warning_meta (rich_loc, m, OPT_Wanalyzer_malloc_leak, + return warning_meta (rich_loc, m, get_controlling_option (), "leak of %qs", ""); } @@ -1316,6 +1353,11 @@ public: && m_freed_reg == other.m_freed_reg); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_free_of_non_heap; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; @@ -1330,13 +1372,13 @@ public: case MEMSPACE_CODE: case MEMSPACE_GLOBALS: case MEMSPACE_READONLY_DATA: - return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap, + return warning_meta (rich_loc, m, get_controlling_option (), "%<%s%> of %qE which points to memory" " not on the heap", m_funcname, m_arg); break; case MEMSPACE_STACK: - return warning_meta (rich_loc, m, OPT_Wanalyzer_free_of_non_heap, + return warning_meta (rich_loc, m, get_controlling_option (), "%<%s%> of %qE which points to memory" " on the stack", m_funcname, m_arg); diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc index 57b346bd410..68b976aeb45 100644 --- a/gcc/analyzer/sm-pattern-test.cc +++ b/gcc/analyzer/sm-pattern-test.cc @@ -89,9 +89,15 @@ public: && same_tree_p (m_rhs, other.m_rhs)); } + int get_controlling_option () const FINAL OVERRIDE + { + return 0; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, 0, "pattern match on %<%E %s %E%>", + return warning_at (rich_loc, get_controlling_option (), + "pattern match on %<%E %s %E%>", m_lhs, op_symbol_code (m_op), m_rhs); } diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc index 1720d8d0135..f40f3e8eb2f 100644 --- a/gcc/analyzer/sm-sensitive.cc +++ b/gcc/analyzer/sm-sensitive.cc @@ -91,13 +91,17 @@ public: return same_tree_p (m_arg, other.m_arg); } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_exposure_through_output_file; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; /* CWE-532: Information Exposure Through Log Files */ m.add_cwe (532); - return warning_meta (rich_loc, m, - OPT_Wanalyzer_exposure_through_output_file, + return warning_meta (rich_loc, m, get_controlling_option (), "sensitive value %qE written to output file", m_arg); } diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc index 8d3e5ff07b1..77044e10805 100644 --- a/gcc/analyzer/sm-signal.cc +++ b/gcc/analyzer/sm-signal.cc @@ -113,14 +113,18 @@ public: return m_unsafe_call == other.m_unsafe_call; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_unsafe_call_within_signal_handler; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; diagnostic_metadata m; /* CWE-479: Signal Handler Use of a Non-reentrant Function. */ m.add_cwe (479); - if (warning_meta (rich_loc, m, - OPT_Wanalyzer_unsafe_call_within_signal_handler, + if (warning_meta (rich_loc, m, get_controlling_option (), "call to %qD from within signal handler", m_unsafe_fndecl)) { diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc index a13c2fe2cfa..e2c78cdd42b 100644 --- a/gcc/analyzer/sm-taint.cc +++ b/gcc/analyzer/sm-taint.cc @@ -180,6 +180,11 @@ public: const char *get_kind () const FINAL OVERRIDE { return "tainted_array_index"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_tainted_array_index; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; @@ -190,19 +195,19 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_array_index, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE" " in array lookup without bounds checking", m_arg); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_array_index, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE" " in array lookup without checking for negative", m_arg); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_array_index, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE" " in array lookup without upper-bounds checking", m_arg); @@ -248,6 +253,11 @@ public: const char *get_kind () const FINAL OVERRIDE { return "tainted_offset"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_tainted_offset; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; @@ -259,19 +269,19 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as offset" " without bounds checking", m_arg); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as offset" " without lower-bounds checking", m_arg); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as offset" " without upper-bounds checking", m_arg); @@ -283,17 +293,17 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as offset" " without bounds checking"); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as offset" " without lower-bounds checking"); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_offset, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as offset" " without upper-bounds checking"); break; @@ -353,6 +363,11 @@ public: const char *get_kind () const OVERRIDE { return "tainted_size"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_tainted_size; + } + bool emit (rich_location *rich_loc) OVERRIDE { diagnostic_metadata m; @@ -362,19 +377,19 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as size" " without bounds checking", m_arg); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as size" " without lower-bounds checking", m_arg); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as size" " without upper-bounds checking", m_arg); @@ -455,18 +470,23 @@ public: const char *get_kind () const FINAL OVERRIDE { return "tainted_divisor"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_tainted_divisor; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; /* CWE-369: "Divide By Zero". */ m.add_cwe (369); if (m_arg) - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_divisor, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as divisor" " without checking for zero", m_arg); else - return warning_meta (rich_loc, m, OPT_Wanalyzer_tainted_divisor, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as divisor" " without checking for zero"); } @@ -503,6 +523,11 @@ public: return "tainted_allocation_size"; } + int get_controlling_option () const FINAL OVERRIDE + { + return OPT_Wanalyzer_tainted_allocation_size; + } + bool emit (rich_location *rich_loc) FINAL OVERRIDE { diagnostic_metadata m; @@ -515,22 +540,19 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as" " allocation size without bounds checking", m_arg); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as" " allocation size without lower-bounds checking", m_arg); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value %qE as" " allocation size without upper-bounds checking", m_arg); @@ -542,22 +564,19 @@ public: default: gcc_unreachable (); case BOUNDS_NONE: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as" " allocation size without bounds" " checking"); break; case BOUNDS_UPPER: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as" " allocation size without lower-bounds" " checking"); break; case BOUNDS_LOWER: - return warning_meta (rich_loc, m, - OPT_Wanalyzer_tainted_allocation_size, + return warning_meta (rich_loc, m, get_controlling_option (), "use of attacker-controlled value as" " allocation size without upper-bounds" " checking"); diff --git a/gcc/testsuite/gcc.dg/analyzer/many-disabled-diagnostics.c b/gcc/testsuite/gcc.dg/analyzer/many-disabled-diagnostics.c new file mode 100644 index 00000000000..48d4023946a --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/many-disabled-diagnostics.c @@ -0,0 +1,55 @@ +/* { dg-additional-options "-Wno-analyzer-double-free" } */ + +#define DOUBLE_FREE() \ + do { \ + void *p = __builtin_malloc (1024); \ + __builtin_free (p); \ + __builtin_free (p); \ + } while (0) + +#define DOUBLE_FREE_x_10() \ + do { \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + DOUBLE_FREE(); \ + } while (0) + +#define DOUBLE_FREE_x_100() \ + do { \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + DOUBLE_FREE_x_10(); \ + } while (0) + +#define DOUBLE_FREE_x_1000() \ + do { \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + DOUBLE_FREE_x_100(); \ + } while (0) + +void test_1 (void) +{ + DOUBLE_FREE_x_1000 (); +} diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c index 61dd490436a..12d1c8d0ba2 100644 --- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c +++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.c @@ -81,6 +81,12 @@ public: class gil_diagnostic : public pending_diagnostic { public: + /* There isn't a warning ID for us to use. */ + int get_controlling_option () const FINAL OVERRIDE + { + return 0; + } + location_t fixup_location (location_t loc) const FINAL OVERRIDE { /* Ideally we'd check for specific macros here, and only @@ -133,7 +139,7 @@ class double_save_thread : public gil_diagnostic bool emit (rich_location *rich_loc) FINAL OVERRIDE { - return warning_at (rich_loc, 0, + return warning_at (rich_loc, get_controlling_option (), "nested usage of %qs", "Py_BEGIN_ALLOW_THREADS"); } @@ -173,14 +179,13 @@ class fncall_without_gil : public gil_diagnostic bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; - /* There isn't a warning ID for use to use. */ if (m_callee_fndecl) - return warning_at (rich_loc, 0, + return warning_at (rich_loc, get_controlling_option (), "use of PyObject as argument %i of %qE" " without the GIL", m_arg_idx + 1, m_callee_fndecl); else - return warning_at (rich_loc, 0, + return warning_at (rich_loc, get_controlling_option (), "use of PyObject as argument %i of call" " without the GIL", m_arg_idx + 1, m_callee_fndecl); @@ -225,8 +230,7 @@ class pyobject_usage_without_gil : public gil_diagnostic bool emit (rich_location *rich_loc) FINAL OVERRIDE { auto_diagnostic_group d; - /* There isn't a warning ID for use to use. */ - return warning_at (rich_loc, 0, + return warning_at (rich_loc, get_controlling_option (), "use of PyObject %qE without the GIL", m_expr); } -- 2.26.3