]> git.ipfire.org Git - thirdparty/gcc.git/commit - gcc/analyzer/region-model.cc
analyzer: implement four new warnings for <stdarg.h> misuses [PR105103]
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 16 May 2022 19:32:11 +0000 (15:32 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Mon, 16 May 2022 19:34:09 +0000 (15:34 -0400)
commit2402dc6b982c4dacac2360830f0edc123c588110
tree95f38ecf7b3a91c1c413e2b782f1a54eb3b4b894
parent5eb9927aae076200bb7ba3f22c33b0a7c97c5643
analyzer: implement four new warnings for <stdarg.h> misuses [PR105103]

This patch adds support to the analyzer for checking usage of <stdarg.h>,
with four new warnings.

It adds:
(a) a state-machine for tracking "started" and "ended" states on va_list
instances, implementing two new warnings:
  -Wanalyzer-va-list-leak
    for complaining about missing va_end after a va_start or va_copy
  -Wanalyzer-va-list-use-after-va-end:
    for complaining about va_arg or va_copy used on a va_list that's had
    va_end called on it

(b) interprocedural tracking of variadic parameters, tracking symbolic
values, implementing two new warnings:
  -Wanalyzer-va-arg-type-mismatch
     for type-checking va_arg usage against the types of the parameters
     that were actually passed to the variadic call
  -Wanalyzer-va-list-exhausted
     for complaining if va_arg is used too many times on a va_list

Here's an LTO example of a type mismatch in a variadic call that
straddles two source files:

stdarg-lto-1-a.c: In function 'called_by_test_type_mismatch_1':
stdarg-lto-1-a.c:19:7: warning: 'va_arg' expected 'const char *' but
 received 'int' for variadic argument 1 of 'ap' [-Wanalyzer-va-arg-type-mismatch]
   19 |   str = va_arg (ap, const char *);
      |       ^
  'test_type_mismatch_1': events 1-2
    |
    |stdarg-lto-1-b.c:3:6:
    |    3 | void test_type_mismatch_1 (void)
    |      |      ^
    |      |      |
    |      |      (1) entry to 'test_type_mismatch_1'
    |    4 | {
    |    5 |   called_by_test_type_mismatch_1 (42, 1066);
    |      |   ~
    |      |   |
    |      |   (2) calling 'called_by_test_type_mismatch_1' from 'test_type_mismatch_1' with 1 variadic argument
    |
    +--> 'called_by_test_type_mismatch_1': events 3-4
           |
           |stdarg-lto-1-a.c:12:1:
           |   12 | called_by_test_type_mismatch_1 (int placeholder, ...)
           |      | ^
           |      | |
           |      | (3) entry to 'called_by_test_type_mismatch_1'
           |......
           |   19 |   str = va_arg (ap, const char *);
           |      |       ~
           |      |       |
           |      |       (4) 'va_arg' expected 'const char *' but received 'int' for variadic argument 1 of 'ap'
           |

gcc/ChangeLog:
PR analyzer/105103
* Makefile.in (ANALYZER_OBJS): Add analyzer/varargs.o.
* doc/invoke.texi: Add -Wanalyzer-va-arg-type-mismatch,
-Wanalyzer-va-list-exhausted, -Wanalyzer-va-list-leak, and
-Wanalyzer-va-list-use-after-va-end.

gcc/analyzer/ChangeLog:
PR analyzer/105103
* analyzer.cc (make_label_text_n): New.
* analyzer.h (class var_arg_region): New forward decl.
(make_label_text_n): New decl.
* analyzer.opt (Wanalyzer-va-arg-type-mismatch): New option.
(Wanalyzer-va-list-exhausted): New option.
(Wanalyzer-va-list-leak): New option.
(Wanalyzer-va-list-use-after-va-end): New option.
* checker-path.cc (call_event::get_desc): Split out decl access
into..
(call_event::get_caller_fndecl): ...this new function and...
(call_event::get_callee_fndecl): ...this new function.
* checker-path.h (call_event::get_desc): Drop "FINAL".
(call_event::get_caller_fndecl): New decl.
(call_event::get_callee_fndecl): New decl.
(class call_event): Make fields protected.
* diagnostic-manager.cc (null_assignment_sm_context::warn): New
overload.
(null_assignment_sm_context::get_new_program_state): New.
(diagnostic_manager::add_events_for_superedge): Move case
SUPEREDGE_CALL to a new pending_diagnostic::add_call_event vfunc.
* engine.cc (impl_sm_context::warn): Implement new override.
(impl_sm_context::get_new_program_state): New.
* pending-diagnostic.cc: Include "analyzer/diagnostic-manager.h",
"cpplib.h", "digraph.h", "ordered-hash-map.h", "cfg.h",
"basic-block.h", "gimple.h", "gimple-iterator.h", "cgraph.h"
"analyzer/supergraph.h", "analyzer/program-state.h",
"alloc-pool.h", "fibonacci_heap.h", "shortest-paths.h",
"sbitmap.h", "analyzer/exploded-graph.h", "diagnostic-path.h",
and "analyzer/checker-path.h".
(ht_ident_eq): New.
(fixup_location_in_macro_p): New.
(pending_diagnostic::fixup_location): New.
(pending_diagnostic::add_call_event): New.
* pending-diagnostic.h (pending_diagnostic::fixup_location): Drop
no-op inline implementation in favor of the more complex
implementation above.
(pending_diagnostic::add_call_event): New vfunc.
* region-model-impl-calls.cc: Include "analyzer/sm.h",
"diagnostic-path.h", and "analyzer/pending-diagnostic.h".
* region-model-manager.cc
(region_model_manager::get_var_arg_region): New.
(region_model_manager::log_stats): Log m_var_arg_regions.
* region-model.cc (region_model::on_call_pre): Handle IFN_VA_ARG,
BUILT_IN_VA_START, and BUILT_IN_VA_COPY.
(region_model::on_call_post): Handle BUILT_IN_VA_END.
(region_model::get_representative_path_var_1): Handle RK_VAR_ARG.
(region_model::push_frame): Push variadic arguments.
* region-model.h (region_model_manager::get_var_arg_region): New
decl.
(region_model_manager::m_var_arg_regions): New field.
(region_model::impl_call_va_start): New decl.
(region_model::impl_call_va_copy): New decl.
(region_model::impl_call_va_arg): New decl.
(region_model::impl_call_va_end): New decl.
* region.cc (alloca_region::dump_to_pp): Dump the id.
(var_arg_region::dump_to_pp): New.
(var_arg_region::get_frame_region): New.
* region.h (enum region_kind): Add RK_VAR_ARG.
(region::dyn_cast_var_arg_region): New.
(class var_arg_region): New.
(is_a_helper <const var_arg_region *>::test): New.
(struct default_hash_traits<var_arg_region::key_t>): New.
* sm.cc (make_checkers): Call make_va_list_state_machine.
* sm.h (sm_context::warn): New vfunc.
(sm_context::get_old_svalue): Drop unused decl.
(sm_context::get_new_program_state): New vfunc.
(make_va_list_state_machine): New decl.
* varargs.cc: New file.

gcc/testsuite/ChangeLog:
PR analyzer/105103
* gcc.dg/analyzer/stdarg-1.c: New test.
* gcc.dg/analyzer/stdarg-2.c: New test.
* gcc.dg/analyzer/stdarg-fmtstring-1.c: New test.
* gcc.dg/analyzer/stdarg-lto-1-a.c: New test.
* gcc.dg/analyzer/stdarg-lto-1-b.c: New test.
* gcc.dg/analyzer/stdarg-lto-1.h: New test.
* gcc.dg/analyzer/stdarg-sentinel-1.c: New test.
* gcc.dg/analyzer/stdarg-types-1.c: New test.
* gcc.dg/analyzer/stdarg-types-2.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
29 files changed:
gcc/Makefile.in
gcc/analyzer/analyzer.cc
gcc/analyzer/analyzer.h
gcc/analyzer/analyzer.opt
gcc/analyzer/checker-path.cc
gcc/analyzer/checker-path.h
gcc/analyzer/diagnostic-manager.cc
gcc/analyzer/engine.cc
gcc/analyzer/pending-diagnostic.cc
gcc/analyzer/pending-diagnostic.h
gcc/analyzer/region-model-impl-calls.cc
gcc/analyzer/region-model-manager.cc
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/analyzer/region.cc
gcc/analyzer/region.h
gcc/analyzer/sm.cc
gcc/analyzer/sm.h
gcc/analyzer/varargs.cc [new file with mode: 0644]
gcc/doc/invoke.texi
gcc/testsuite/gcc.dg/analyzer/stdarg-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-fmtstring-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-lto-1-a.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-lto-1-b.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-lto-1.h [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-sentinel-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-types-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/stdarg-types-2.c [new file with mode: 0644]