From 6bced51c9be26e395532da45db9132a45b6b59c1 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 4 Mar 2019 14:50:08 -0500
Subject: [PATCH 49/87] FIXME: more interprocedural

---
 gcc/analyzer/engine.cc                             |  62 +++++++-
 .../arg-affected-by-usage-as-param/input.c         |  34 ----
 .../arg-affected-by-usage-as-param/script.py       |  36 -----
 .../arg-affected-by-usage-as-param/stderr.txt      |  11 --
 .../arg-affected-by-usage-as-param/stdout.txt      |   0
 .../callsite-lhs-inherits-from-return-val/input.c  |  35 -----
 .../stdout.txt                                     |   0
 .../interprocedural/input.c.cpychecker-log.txt     |   1 -
 ...ough_uninitialized_pointer-refcount-errors.html | 175 ---------------------
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-1.c       |  16 +-
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c       |  15 ++
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-3.c       |  23 +++
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-4.c       |  13 ++
 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-5.c       |  13 ++
 14 files changed, 127 insertions(+), 307 deletions(-)
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/input.c
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/script.py
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stderr.txt
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stdout.txt
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/input.c
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/stdout.txt
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.cpychecker-log.txt
 delete mode 100644 gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.test_read_through_uninitialized_pointer-refcount-errors.html
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-3.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-4.c
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/malloc-ipa-5.c

diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 748a64c..9cc27d3 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -1228,7 +1228,7 @@ engine::refine_for_call (sm_instance sm_inst, cgraph_edge *edge,
 }
 
 sm_instance
-engine::restore_after_call (sm_instance sm_inst, cgraph_edge *edge,
+engine::restore_after_call (sm_instance sm_inst_in_callee, cgraph_edge *edge,
 			    const supernode *rest_of_caller_node)
 {
   JIT_LOG_SCOPE (get_logger ());
@@ -1237,22 +1237,68 @@ engine::restore_after_call (sm_instance sm_inst, cgraph_edge *edge,
       log ("returning to %s from %s",
 	   function_name (edge->caller->get_fun ()),
 	   function_name (edge->callee->get_fun ()));
-      log ("sm_inst was: %s", sm_inst.to_str (m_sm).c_str ());
+      log ("sm_inst was: %s", sm_inst_in_callee.to_str (m_sm).c_str ());
     }
 
   sm_instance sm_inst_in_caller;// (sm_inst);
 
   tree callee = edge->callee->get_fun ()->decl;
   tree result = DECL_RESULT (callee);
-  tree lhs = gimple_call_lhs (rest_of_caller_node->m_returning_call);
+  gcall *call_stmt = rest_of_caller_node->m_returning_call;
+  tree lhs = gimple_call_lhs (call_stmt);
   if (lhs)
     {
       path_state ps; // FIXME
-      on_assignment (rest_of_caller_node, rest_of_caller_node->m_returning_call,
-		     &sm_inst_in_caller, &sm_inst /* FIXME.  */,
+      on_assignment (rest_of_caller_node, call_stmt,
+		     &sm_inst_in_caller, &sm_inst_in_callee /* FIXME.  */,
 		     lhs, result, &ps);
     }
 
+  // TODO: map formal params back to actual args:
+  int i = 0;
+  for (tree parm = DECL_ARGUMENTS (callee); parm;
+       parm = DECL_CHAIN (parm), ++i)
+    {
+      tree arg = gimple_call_arg (call_stmt, i);
+#if 0
+      on_assignment (caller_node, call,
+		     &sm_inst_for_call, &sm_inst /* FIXME.  */,
+		     parm, arg);
+#endif
+      path_state ps; // FIXME
+#if 0
+      tree parm_default_ssa = ssa_default_def (edge->callee->get_fun (), parm);
+      on_assignment (caller_node, call,
+		     &sm_inst_for_call, &sm_inst /* FIXME.  */,
+		     parm_default_ssa, arg, &ps);
+#endif
+
+      /* Use: parm, arg, next_sm_inst, to map from parms in callee
+	 back to args in caller */
+      for (set_of_vars::iterator iter
+	     = sm_inst_in_callee.m_active_vars.begin ();
+	   iter != sm_inst_in_callee.m_active_vars.end ();
+	   ++iter)
+	{
+	  // FIXME: may want ECs for this
+	  tree var = (*iter).m_var;
+	  if (TREE_CODE (var) == SSA_NAME)
+	    var = SSA_NAME_VAR (var);
+	  if (var == parm)
+	    {
+	      log ("got active var for parm %i", i);
+	      engine_sm_context ctxt (this, &sm_inst_in_caller,
+				      &sm_inst_in_callee,
+				      NULL /* FIXME */, &ps);
+	      // FIXME: we want to overwrite any old states
+	      // (but respect the gstate, I think):
+	      ctxt.on_transition (rest_of_caller_node, call_stmt, arg,
+				  0/* FIXME */,
+				  (*iter).m_state);
+	    }
+	}
+    }
+
   // TODO: leak detection
 
   if (get_logger ())
@@ -1282,6 +1328,8 @@ engine::follow_call (sm_instance sm_inst, backtrace b, path_state ps,
   dfs_traverse (callee_sm_inst, backtrace (), ps, callee_node,
 		NULL /* FIXME */);
 
+  log ("building summary edges from callee function summary");
+
   /* Build set S of transition/add edges based on callee
      function summary.  */
   set_of_summary_edges callee_summary_edges;
@@ -1346,6 +1394,10 @@ engine::follow_call (sm_instance sm_inst, backtrace b, path_state ps,
 	  ((*i).m_end.m_varstate); // FIXME
       }
 
+  if (get_logger ())
+    log ("callee_summary_sm_inst: %s",
+	 callee_summary_sm_inst.to_str (m_sm).c_str ());
+
   /* TODO traverse into intraprocedural successor for each
      sm_instance.  */
   const supernode *rest_of_caller_node = m_sg.get_caller_next_node (edge);
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/input.c b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/input.c
deleted file mode 100644
index 958038a..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/input.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-   Copyright 2012 David Malcolm <dmalcolm@redhat.com>
-   Copyright 2012 Red Hat, Inc.
-
-   This is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see
-   <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-static void calls_free(int *q)
-{
-  free(q);
-}
-
-void test(void *p)
-{
-  calls_free(p);
-
-  /* BUG: double-free of p: already freed within calls_free() above */
-  free(p);
-}
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/script.py b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/script.py
deleted file mode 100644
index 063e9c4..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/script.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# -*- coding: utf-8 -*-
-#   Copyright 2012 David Malcolm <dmalcolm@redhat.com>
-#   Copyright 2012 Red Hat, Inc.
-#
-#   This is free software: you can redistribute it and/or modify it
-#   under the terms of the GNU General Public License as published by
-#   the Free Software Foundation, either version 3 of the License, or
-#   (at your option) any later version.
-#
-#   This program is distributed in the hope that it will be useful, but
-#   WITHOUT ANY WARRANTY; without even the implied warranty of
-#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-#   General Public License for more details.
-#
-#   You should have received a copy of the GNU General Public License
-#   along with this program.  If not, see
-#   <http://www.gnu.org/licenses/>.
-
-from sm import main
-from sm.parser import parse_file
-
-def selftest(ctxt, solution):
-    if 0:
-        import sys
-        solution.dump(sys.stderr)
-
-    # Verify that calls_free() converts "p" within the caller from "ptr.start"
-    # to "ptr.free":
-    node = ctxt.find_call_of('calls_free')
-    ctxt.assert_statenames_for_varname(node, 'p', {'ptr.start'})
-
-    node = ctxt.get_intraprocedural_successor(node)
-    ctxt.assert_statenames_for_varname(node, 'p', {'ptr.free'})
-
-checker = parse_file('sm/checkers/malloc_checker.sm')
-main([checker], selftest=selftest)
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stderr.txt b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stderr.txt
deleted file mode 100644
index 4cc823c..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stderr.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c: In function 'test':
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:33:nn: error: double-free of p [CWE-415]
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:30:nn: note: call from test() to calls_free()
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:25:nn: note: q passed to free()
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:30:nn: note: return from calls_free() to test(): state of q ("ptr.free") propagated to p
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:33:nn: note: double-free of p
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:33:nn: error: use-after-free of p [CWE-416]
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:30:nn: note: call from test() to calls_free()
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:25:nn: note: q passed to free()
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:30:nn: note: return from calls_free() to test(): state of q ("ptr.free") propagated to p
-tests/sm/interprocedural/arg-affected-by-usage-as-param/input.c:33:nn: note: use-after-free of p
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stdout.txt b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/arg-affected-by-usage-as-param/stdout.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/input.c b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/input.c
deleted file mode 100644
index 3ae8558..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/input.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-   Copyright 2012 David Malcolm <dmalcolm@redhat.com>
-   Copyright 2012 Red Hat, Inc.
-
-   This is free software: you can redistribute it and/or modify it
-   under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see
-   <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-static int *calls_malloc(void)
-{
-  return malloc(sizeof(int));
-}
-
-int *test(void)
-{
-    int *p = calls_malloc();
-    /* BUG: malloc could have returned NULL */
-    *p = 42;
-    return p;
-}
-
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/stdout.txt b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/callsite-lhs-inherits-from-return-val/stdout.txt
deleted file mode 100644
index e69de29..0000000
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.cpychecker-log.txt b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.cpychecker-log.txt
deleted file mode 100644
index 7499d84..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.cpychecker-log.txt
+++ /dev/null
@@ -1 +0,0 @@
-gcc.Function('test')
diff --git a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.test_read_through_uninitialized_pointer-refcount-errors.html b/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.test_read_through_uninitialized_pointer-refcount-errors.html
deleted file mode 100644
index b92b8e0..0000000
--- a/gcc/testsuite/gcc.dg/TODO-analyzer/interprocedural/input.c.test_read_through_uninitialized_pointer-refcount-errors.html
+++ /dev/null
@@ -1,175 +0,0 @@
-<html>
-  <head>
-    <title>test_read_through_uninitialized_pointer</title>
-    <style type="text/css">
-.unreached-line {
-    #margin:1em;
-    #border:0.1em dotted #00aa00;
-
-    opacity:1.0;
-    filter:alpha(opacity=0);
-    #color:black;
-}
-
-.reached-line {
-    #margin:1em;
-    #border:0.1em dotted #00aa00;
-    border: 0.1em solid blue;
-    font-weight: bold;
-
-    opacity:1.0;
-    filter:alpha(opacity=0);
-    #color:black;
-}
-
-.reached-lineno {
-    border: 0.1em solid blue;
-    font-weight: bold;
-}
-
-pre {
-    #line-height:200%
-}
-
-._jsPlumb_connector { z-index: -2; }
-._jsPlumb_endpoint { z-index: -1; }
-
-.transition {
-    #border: 0.1em dotted #ddffdd;
-    #padding: 1em;
-    border: 0.1em solid #ccc;
-    -moz-box-shadow: 2px 2px 2px #ccc;
-    -webkit-box-shadow: 2px 2px 2px #ccc;
-    box-shadow: 2px 2px 2px #ccc;
-    margin-left: 5em;
-    font-family: proportional;
-    font-style: italic;
-    font-size: 90%;
-}
-
-.error {
-    #border: 0.1em dotted #ddffdd;
-    #padding: 1em;
-    border: 0.1em solid #cc0000;
-    -moz-box-shadow: 2px 2px 2px #cc0000;
-    -webkit-box-shadow: 2px 2px 2px #cc0000;
-    box-shadow: 2px 2px 2px #cc0000;
-    margin-left: 5em;
-    color: red;
-    font-family: proportional;
-    font-weight: bold;
-    font-style: italic;
-    font-size: 90%;
-}
-
-.note {
-    #border: 0.1em dotted #ddffdd;
-    #padding: 1em;
-    border: 0.1em solid #ccc;
-    -moz-box-shadow: 2px 2px 2px #ccc;
-    -webkit-box-shadow: 2px 2px 2px #ccc;
-    box-shadow: 2px 2px 2px #ccc;
-    margin-left: 5em;
-    font-family: proportional;
-    font-weight: bold;
-    font-style: italic;
-    font-size: 90%;
-}
-
-.hll { background-color: #ffffcc }
-.source_c { color: #408080; font-style: italic } /* Comment */
-.source_err { border: 1px solid #FF0000 } /* Error */
-.source_k { color: #008000; font-weight: bold } /* Keyword */
-.source_o { color: #666666 } /* Operator */
-.source_cm { color: #408080; font-style: italic } /* Comment.Multiline */
-.source_cp { color: #BC7A00 } /* Comment.Preproc */
-.source_c1 { color: #408080; font-style: italic } /* Comment.Single */
-.source_cs { color: #408080; font-style: italic } /* Comment.Special */
-.source_gd { color: #A00000 } /* Generic.Deleted */
-.source_ge { font-style: italic } /* Generic.Emph */
-.source_gr { color: #FF0000 } /* Generic.Error */
-.source_gh { color: #000080; font-weight: bold } /* Generic.Heading */
-.source_gi { color: #00A000 } /* Generic.Inserted */
-.source_go { color: #808080 } /* Generic.Output */
-.source_gp { color: #000080; font-weight: bold } /* Generic.Prompt */
-.source_gs { font-weight: bold } /* Generic.Strong */
-.source_gu { color: #800080; font-weight: bold } /* Generic.Subheading */
-.source_gt { color: #0040D0 } /* Generic.Traceback */
-.source_kc { color: #008000; font-weight: bold } /* Keyword.Constant */
-.source_kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
-.source_kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
-.source_kp { color: #008000 } /* Keyword.Pseudo */
-.source_kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
-.source_kt { color: #B00040 } /* Keyword.Type */
-.source_m { color: #666666 } /* Literal.Number */
-.source_s { color: #BA2121 } /* Literal.String */
-.source_na { color: #7D9029 } /* Name.Attribute */
-.source_nb { color: #008000 } /* Name.Builtin */
-.source_nc { color: #0000FF; font-weight: bold } /* Name.Class */
-.source_no { color: #880000 } /* Name.Constant */
-.source_nd { color: #AA22FF } /* Name.Decorator */
-.source_ni { color: #999999; font-weight: bold } /* Name.Entity */
-.source_ne { color: #D2413A; font-weight: bold } /* Name.Exception */
-.source_nf { color: #0000FF } /* Name.Function */
-.source_nl { color: #A0A000 } /* Name.Label */
-.source_nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
-.source_nt { color: #008000; font-weight: bold } /* Name.Tag */
-.source_nv { color: #19177C } /* Name.Variable */
-.source_ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
-.source_w { color: #bbbbbb } /* Text.Whitespace */
-.source_mf { color: #666666 } /* Literal.Number.Float */
-.source_mh { color: #666666 } /* Literal.Number.Hex */
-.source_mi { color: #666666 } /* Literal.Number.Integer */
-.source_mo { color: #666666 } /* Literal.Number.Oct */
-.source_sb { color: #BA2121 } /* Literal.String.Backtick */
-.source_sc { color: #BA2121 } /* Literal.String.Char */
-.source_sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
-.source_s2 { color: #BA2121 } /* Literal.String.Double */
-.source_se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
-.source_sh { color: #BA2121 } /* Literal.String.Heredoc */
-.source_si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
-.source_sx { color: #008000 } /* Literal.String.Other */
-.source_sr { color: #BB6688 } /* Literal.String.Regex */
-.source_s1 { color: #BA2121 } /* Literal.String.Single */
-.source_ss { color: #19177C } /* Literal.String.Symbol */
-.source_bp { color: #008000 } /* Name.Builtin.Pseudo */
-.source_vc { color: #19177C } /* Name.Variable.Class */
-.source_vg { color: #19177C } /* Name.Variable.Global */
-.source_vi { color: #19177C } /* Name.Variable.Instance */
-.source_il { color: #666666 } /* Literal.Number.Integer.Long */    </style>
-  </head>
-  <body>
-<script type="text/javascript" src="http://explorercanvas.googlecode.com/svn/trunk/excanvas.js"></script>
-<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"></script>
-<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js"></script>
-<script type="text/javascript" src="http://jsplumb.googlecode.com/files/jquery.jsPlumb-1.2.6-all-min.js"></script>
-<div id="report-0">
-<table>
-  <tr><td>File:</td> <td><b>tests/cpychecker/absinterp/read-through-uninitialized-ptr/input.c</b></td></tr>
-  <tr><td>Function:</td> <td><b>test_read_through_uninitialized_pointer</b></td></tr>
-  <tr><td>Error:</td> <td><b>dereferencing uninitialized pointer (coord_ptr->x) at tests/cpychecker/absinterp/read-through-uninitialized-ptr/input.c:35</b></td></tr>
-</table>
-<div class="highlight"><pre><span class="lineno">30</span> <span id="trace0-line30" class="unreached-line"><span class="source_kt">int</span> <span class="source_nf">test_read_through_uninitialized_pointer</span><span class="source_p">(</span><span class="source_kt">void</span><span class="source_p">)</span></span>
-<span class="lineno">31</span> <span id="trace0-line31" class="unreached-line"><span class="source_p">{</span></span>
-<span class="lineno">32</span> <span id="trace0-line32" class="unreached-line">    <span class="source_k">struct</span> <span class="source_n">coord</span> <span class="source_o">*</span><span class="source_n">coord_ptr</span><span class="source_p">;</span></span>
-<span class="lineno">33</span> <span id="trace0-line33" class="unreached-line"></span>
-<span class="lineno">34</span> <span id="trace0-line34" class="unreached-line">    <span class="source_k">return</span> <span class="source_n">coord_ptr</span><span class="source_o">-&gt;</span><span class="source_n">x</span><span class="source_p">;</span></span>
-<span class="reached-lineno">35</span> <span id="trace0-line35" class="reached-line"><span class="source_p">}</span></span>
-<span class="error">dereferencing uninitialized pointer (coord_ptr->x) at tests/cpychecker/absinterp/read-through-uninitialized-ptr/input.c:35</span>
-<span class="lineno">36</span> <span id="trace0-line36" class="unreached-line"></pre></div></span>
-</pre></div>
-
-<script type="text/javascript">
-  jsPlumb.bind("ready", function() {
-    /* Set up defaults: */
-    jsPlumb.Defaults.Connector = [ "Bezier", 1 ];
-    jsPlumb.Defaults.Connector = [ "Straight" ];
-    jsPlumb.Defaults.PaintStyle = { strokeStyle:"blue", lineWidth:1 };
-    jsPlumb.Defaults.EndpointStyle = { radius:2, fillStyle:"red" };
-    jsPlumb.Defaults.Anchors =  [ "BottomCenter", "TopCenter" ];
-
-    /* Add lines: */
-  })
-</script>
-<hr/></div>
-  </body>
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-1.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-1.c
index 3e112b7..01eeb2e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-1.c
@@ -7,12 +7,6 @@ calls_malloc (void)
   return result;
 }
 
-void
-calls_free (void *victim)
-{
-  free (victim);
-}
-
 int *test_1 (int i)
 {
   int *ptr = (int *)calls_malloc ();
@@ -20,9 +14,11 @@ int *test_1 (int i)
   return ptr;
 }
 
-void test_2 (void)
+/* Same as test_1, to exercise the caches.  */
+
+int *test_2 (int i)
 {
-  void *ptr = calls_malloc ();
-  calls_free (ptr);
-  calls_free (ptr); /* BUG: double-free.  */
+  int *ptr = (int *)calls_malloc ();
+  *ptr = i; /* { dg-error "use of possibly-NULL 'ptr'" } */
+  return ptr;
 }
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
new file mode 100644
index 0000000..708477a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-2.c
@@ -0,0 +1,15 @@
+#include <stdlib.h>
+
+void
+calls_free (void *victim)
+{
+  free (victim); /* { dg-error "double-free of 'victim'" } */
+  /* TODO: this would be better emitted at the callsite,
+     for such a simple wrapper.  */
+}
+
+void test (void *ptr)
+{
+  calls_free (ptr);
+  calls_free (ptr); /* BUG: double-free.  */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-3.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-3.c
new file mode 100644
index 0000000..dd7ed34
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-3.c
@@ -0,0 +1,23 @@
+#include <stdlib.h>
+
+void *
+calls_malloc (void)
+{
+  void *result = malloc (1024);
+  return result;
+}
+
+void
+calls_free (void *victim)
+{
+  free (victim); /* { dg-error "double-free of 'victim'" } */
+  /* TODO: this would be better emitted at the callsite,
+     for such a simple wrapper.  */
+}
+
+void test (void)
+{
+  void *ptr = calls_malloc ();
+  calls_free (ptr);
+  calls_free (ptr); /* BUG: double-free.  */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-4.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-4.c
new file mode 100644
index 0000000..c3ca150
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-4.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+static void calls_free(int *q)
+{
+  free(q);
+}
+
+void test(void *p)
+{
+  calls_free(p);
+
+  free(p); /* { dg-error "double-free of 'p'" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-5.c b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-5.c
new file mode 100644
index 0000000..a2b7548
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/malloc-ipa-5.c
@@ -0,0 +1,13 @@
+#include <stdlib.h>
+
+static int *calls_malloc(void)
+{
+  return malloc(sizeof(int));
+}
+
+int *test(void)
+{
+    int *p = calls_malloc();
+    *p = 42; /* { dg-error "use of possibly-NULL 'p'" } */
+    return p;
+}
-- 
1.8.5.3

