https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105962

--- Comment #2 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by David Malcolm <dmalc...@gcc.gnu.org>:

https://gcc.gnu.org/g:63c073199491b7ec2261d39af51c02147c2f0daf

commit r13-1119-g63c073199491b7ec2261d39af51c02147c2f0daf
Author: David Malcolm <dmalc...@redhat.com>
Date:   Wed Jun 15 17:44:14 2022 -0400

    analyzer: fix up paths for inlining (PR analyzer/105962)

    -fanalyzer runs late compared to other code analysis tools, in that in
    runs on the partially-optimized gimple-ssa representation.  I chose this
    point to run in the hope of easy integration with LTO.

    As PR analyzer/105962 notes, this means that function inlining can occur
    before the -fanalyzer "sees" the user's code.  For example given:

    void foo (void *p)
    {
      __builtin_free (p);
    }

    void bar (void *q)
    {
      foo (q);
      foo (q);
    }

    Below -O2, -fanalyzer shows the calls and returns:

    inline-1.c: In function âfooâ:
    inline-1.c:3:3: warning: double-âfreeâ of âpâ [CWE-415]
[-Wanalyzer-double-free]
        3 |   __builtin_free (p);
          |   ^~~~~~~~~~~~~~~~~~
      âbarâ: events 1-2
        |
        |    6 | void bar (void *q)
        |      |      ^~~
        |      |      |
        |      |      (1) entry to âbarâ
        |    7 | {
        |    8 |   foo (q);
        |      |   ~~~~~~~
        |      |   |
        |      |   (2) calling âfooâ from âbarâ
        |
        +--> âfooâ: events 3-4
               |
               |    1 | void foo (void *p)
               |      |      ^~~
               |      |      |
               |      |      (3) entry to âfooâ
               |    2 | {
               |    3 |   __builtin_free (p);
               |      |   ~~~~~~~~~~~~~~~~~~
               |      |   |
               |      |   (4) first âfreeâ here
               |
        <------+
        |
      âbarâ: events 5-6
        |
        |    8 |   foo (q);
        |      |   ^~~~~~~
        |      |   |
        |      |   (5) returning to âbarâ from âfooâ
        |    9 |   foo (q);
        |      |   ~~~~~~~
        |      |   |
        |      |   (6) passing freed pointer âqâ in call to âfooâ from
âbarâ
        |
        +--> âfooâ: events 7-8
               |
               |    1 | void foo (void *p)
               |      |      ^~~
               |      |      |
               |      |      (7) entry to âfooâ
               |    2 | {
               |    3 |   __builtin_free (p);
               |      |   ~~~~~~~~~~~~~~~~~~
               |      |   |
               |      |   (8) second âfreeâ here; first âfreeâ was at
(4)
               |

    but at -O2, -fanalyzer "sees" this gimple:

    void bar (void * q)
    {
      <bb 2> [local count: 1073741824]:
      __builtin_free (q_2(D));
      __builtin_free (q_2(D));
      return;
    }

    where "foo" has been inlined away, leading to this unhelpful output:

    In function âfooâ,
        inlined from âbarâ at inline-1.c:9:3:
    inline-1.c:3:3: warning: double-âfreeâ of âqâ [CWE-415]
[-Wanalyzer-double-free]
        3 |   __builtin_free (p);
          |   ^~~~~~~~~~~~~~~~~~
      âbarâ: events 1-2
        |
        |    3 |   __builtin_free (p);
        |      |   ^~~~~~~~~~~~~~~~~~
        |      |   |
        |      |   (1) first âfreeâ here
        |      |   (2) second âfreeâ here; first âfreeâ was at (1)

    where the stack frame information in the execution path suggests that these
    events are happening in "bar", in the top stack frame.

    This is what the analyzer sees, but I find it hard to decipher such
    output.  Hence, as a workaround for the fact that -fanalyzer runs so
    late, this patch attempts to reconstruct the "true" stack frame
    information, and to inject events showing inline calls, based on the
    inlining chain information recorded in the location_t values for the
events.

    Doing so leads to this output at -O2 on the above example (with
    -fdiagnostics-show-path-depths):

    In function âfooâ,
        inlined from âbarâ at inline-1.c:9:3:
    inline-1.c:3:3: warning: double-âfreeâ of âqâ [CWE-415]
[-Wanalyzer-double-free]
        3 |   __builtin_free (p);
          |   ^~~~~~~~~~~~~~~~~~
      âbarâ: events 1-2 (depth 1)
        |
        |    6 | void bar (void *q)
        |      |      ^~~
        |      |      |
        |      |      (1) entry to âbarâ
        |    7 | {
        |    8 |   foo (q);
        |      |   ~
        |      |   |
        |      |   (2) inlined call to âfooâ from âbarâ
        |
        +--> âfooâ: event 3 (depth 2)
               |
               |    3 |   __builtin_free (p);
               |      |   ^~~~~~~~~~~~~~~~~~
               |      |   |
               |      |   (3) first âfreeâ here
               |
        <------+
        |
      âbarâ: event 4 (depth 1)
        |
        |    9 |   foo (q);
        |      |   ^
        |      |   |
        |      |   (4) inlined call to âfooâ from âbarâ
        |
        +--> âfooâ: event 5 (depth 2)
               |
               |    3 |   __builtin_free (p);
               |      |   ^~~~~~~~~~~~~~~~~~
               |      |   |
               |      |   (5) second âfreeâ here; first âfreeâ was at
(3)
               |

    reconstructing the calls and returns.

    The patch also adds a new option, -fno-analyzer-undo-inlining, which can
    be used to disable this reconstruction, restoring the output listed
    above (this time with -fdiagnostics-show-path-depths):

    In function âfooâ,
        inlined from âbarâ at inline-1.c:9:3:
    inline-1.c:3:3: warning: double-âfreeâ of âqâ [CWE-415]
[-Wanalyzer-double-free]
        3 |   __builtin_free (p);
          |   ^~~~~~~~~~~~~~~~~~
      âbarâ: events 1-2 (depth 1)
        |
        |    3 |   __builtin_free (p);
        |      |   ^~~~~~~~~~~~~~~~~~
        |      |   |
        |      |   (1) first âfreeâ here
        |      |   (2) second âfreeâ here; first âfreeâ was at (1)
        |

    gcc/analyzer/ChangeLog:
            PR analyzer/105962
            * analyzer.opt (fanalyzer-undo-inlining): New option.
            * checker-path.cc: Include "diagnostic-core.h" and
            "inlining-iterator.h".
            (event_kind_to_string): Handle EK_INLINED_CALL.
            (class inlining_info): New class.
            (checker_event::checker_event): Move here from checker-path.h.
            Store original fndecl and depth, and calculate effective fndecl
            and depth based on inlining information.
            (checker_event::dump): Emit original depth as well as effective
            depth when they differ; likewise for fndecl.
            (region_creation_event::get_desc): Use m_effective_fndecl.
            (inlined_call_event::get_desc): New.
            (inlined_call_event::get_meaning): New.
            (checker_path::inject_any_inlined_call_events): New.
            * checker-path.h (enum event_kind): Add EK_INLINED_CALL.
            (checker_event::checker_event): Make protected, and move
            definition to checker-path.cc.
            (checker_event::get_fndecl): Use effective fndecl.
            (checker_event::get_stack_depth): Use effective stack depth.
            (checker_event::get_logical_location): Use effective stack depth.
            (checker_event::get_original_stack_depth): New.
            (checker_event::m_fndecl): Rename to...
            (checker_event::m_original_fndecl): ...this.
            (checker_event::m_depth): Rename to...
            (checker_event::m_original_depth): ...this.
            (checker_event::m_effective_fndecl): New field.
            (checker_event::m_effective_depth): New field.
            (class inlined_call_event): New checker_event subclass.
            (checker_path::inject_any_inlined_call_events): New decl.
            * diagnostic-manager.cc: Include "inlining-iterator.h".
            (diagnostic_manager::emit_saved_diagnostic): Call
            checker_path::inject_any_inlined_call_events.
            (diagnostic_manager::prune_for_sm_diagnostic): Handle
            EK_INLINED_CALL.
            * engine.cc (tainted_args_function_custom_event::get_desc): Use
            effective fndecl.
            * inlining-iterator.h: New file.

    gcc/testsuite/ChangeLog:
            PR analyzer/105962
            * gcc.dg/analyzer/inlining-1-multiline.c: New test.
            * gcc.dg/analyzer/inlining-1-no-undo.c: New test.
            * gcc.dg/analyzer/inlining-1.c: New test.
            * gcc.dg/analyzer/inlining-2-multiline.c: New test.
            * gcc.dg/analyzer/inlining-2.c: New test.
            * gcc.dg/analyzer/inlining-3-multiline.c: New test.
            * gcc.dg/analyzer/inlining-3.c: New test.
            * gcc.dg/analyzer/inlining-4-multiline.c: New test.
            * gcc.dg/analyzer/inlining-4.c: New test.
            * gcc.dg/analyzer/inlining-5-multiline.c: New test.
            * gcc.dg/analyzer/inlining-5.c: New test.
            * gcc.dg/analyzer/inlining-6-multiline.c: New test.
            * gcc.dg/analyzer/inlining-6.c: New test.
            * gcc.dg/analyzer/inlining-7-multiline.c: New test.
            * gcc.dg/analyzer/inlining-7.c: New test.

    gcc/ChangeLog:
            PR analyzer/105962
            * doc/invoke.texi: Add -fno-analyzer-undo-inlining.
            * tree-diagnostic-path.cc (default_tree_diagnostic_path_printer):
            Extend -fdiagnostics-path-format=separate-events so that with
            -fdiagnostics-show-path-depths it prints fndecls as well as stack
            depths.

    Signed-off-by: David Malcolm <dmalc...@redhat.com>

Reply via email to