bool should_purge_p (const svalue *sval) const
   {
-    return !sval->live_p (m_live_svalues, m_model);
+    return !sval->live_p (&m_live_svalues, m_model);
   }
 
 private:
 
        ++iter)
     {
       const svalue *iter_sval = (*iter).first;
-      if (!iter_sval->live_p (live_svalues, model))
+      if (!iter_sval->live_p (&live_svalues, model))
        {
          svals_to_unset.add (iter_sval);
          entry_t e = (*iter).second;
         live in DEST_STATE: either explicitly reachable, or implicitly
         live based on the set of explicitly reachable svalues.
         Record those that have ceased to be live.  */
-      if (!sval->live_p (dest_svalues, dest_state.m_region_model))
+      if (!sval->live_p (&dest_svalues, dest_state.m_region_model))
        dead_svals.quick_push (sval);
     }
 
 
   if (const symbolic_region *sym_reg = base_reg->dyn_cast_symbolic_region ())
     {
       const svalue *ptr = sym_reg->get_pointer ();
+      if (ptr->implicitly_live_p (NULL, m_model))
+       add (base_reg, true);
       switch (ptr->get_kind ())
        {
        default:
 
   /* If we have a pointer to something within a stack frame, it can't be the
      initial value of a param.  */
   if (pointee->maybe_get_frame_region ())
-    {
-      const region *reg = init->get_region ();
-      if (tree reg_decl = reg->maybe_get_decl ())
-       if (TREE_CODE (reg_decl) == SSA_NAME)
-         {
-           tree ssa_name = reg_decl;
-           if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)
-               && SSA_NAME_VAR (ssa_name)
-               && TREE_CODE (SSA_NAME_VAR (ssa_name)) == PARM_DECL)
-             return tristate::TS_FALSE;
-         }
-    }
+    if (init->initial_value_of_param_p ())
+      return tristate::TS_FALSE;
 
   return tristate::TS_UNKNOWN;
 }
 
 }
 
 /* Determine if this svalue is either within LIVE_SVALUES, or is implicitly
-   live with respect to LIVE_SVALUES and MODEL.  */
+   live with respect to LIVE_SVALUES and MODEL.
+   LIVE_SVALUES can be NULL, in which case determine if this svalue is
+   intrinsically live.  */
 
 bool
-svalue::live_p (const svalue_set &live_svalues,
+svalue::live_p (const svalue_set *live_svalues,
                const region_model *model) const
 {
   /* Determine if SVAL is explicitly live.  */
-  if (const_cast<svalue_set &> (live_svalues).contains (this))
-    return true;
+  if (live_svalues)
+    if (const_cast<svalue_set *> (live_svalues)->contains (this))
+      return true;
 
   /* Otherwise, determine if SVAL is implicitly live due to being made of
      other live svalues.  */
 /* Base implementation of svalue::implicitly_live_p.  */
 
 bool
-svalue::implicitly_live_p (const svalue_set &, const region_model *) const
+svalue::implicitly_live_p (const svalue_set *, const region_model *) const
 {
   return false;
 }
 /* Implementation of svalue::implicitly_live_p vfunc for region_svalue.  */
 
 bool
-region_svalue::implicitly_live_p (const svalue_set &,
+region_svalue::implicitly_live_p (const svalue_set *,
                                  const region_model *model) const
 {
   /* Pointers into clusters that have escaped should be treated as live.  */
    Constants are implicitly live.  */
 
 bool
-constant_svalue::implicitly_live_p (const svalue_set &,
+constant_svalue::implicitly_live_p (const svalue_set *,
                                    const region_model *) const
 {
   return true;
 /* Implementation of svalue::implicitly_live_p vfunc for initial_svalue.  */
 
 bool
-initial_svalue::implicitly_live_p (const svalue_set &,
+initial_svalue::implicitly_live_p (const svalue_set *,
                                   const region_model *model) const
 {
   /* This svalue may be implicitly live if the region still implicitly
        return true;
     }
 
+  /* Assume that the initial values of params for the top level frame
+     are still live, because (presumably) they're still
+     live in the external caller.  */
+  if (initial_value_of_param_p ())
+    if (const frame_region *frame_reg = m_reg->maybe_get_frame_region ())
+      if (frame_reg->get_calling_frame () == NULL)
+       return true;
+
+  return false;
+}
+
+/* Return true if this is the initial value of a function parameter.  */
+
+bool
+initial_svalue::initial_value_of_param_p () const
+{
+  if (tree reg_decl = m_reg->maybe_get_decl ())
+    if (TREE_CODE (reg_decl) == SSA_NAME)
+      {
+       tree ssa_name = reg_decl;
+       if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)
+           && SSA_NAME_VAR (ssa_name)
+           && TREE_CODE (SSA_NAME_VAR (ssa_name)) == PARM_DECL)
+         return true;
+      }
   return false;
 }
 
 /* Implementation of svalue::implicitly_live_p vfunc for unaryop_svalue.  */
 
 bool
-unaryop_svalue::implicitly_live_p (const svalue_set &live_svalues,
+unaryop_svalue::implicitly_live_p (const svalue_set *live_svalues,
                                   const region_model *model) const
 {
   return get_arg ()->live_p (live_svalues, model);
 /* Implementation of svalue::implicitly_live_p vfunc for binop_svalue.  */
 
 bool
-binop_svalue::implicitly_live_p (const svalue_set &live_svalues,
+binop_svalue::implicitly_live_p (const svalue_set *live_svalues,
                                 const region_model *model) const
 {
   return (get_arg0 ()->live_p (live_svalues, model)
 /* Implementation of svalue::implicitly_live_p vfunc for sub_svalue.  */
 
 bool
-sub_svalue::implicitly_live_p (const svalue_set &live_svalues,
+sub_svalue::implicitly_live_p (const svalue_set *live_svalues,
                               const region_model *model) const
 {
   return get_parent ()->live_p (live_svalues, model);
 /* Implementation of svalue::implicitly_live_p vfunc for unmergeable_svalue.  */
 
 bool
-unmergeable_svalue::implicitly_live_p (const svalue_set &live_svalues,
+unmergeable_svalue::implicitly_live_p (const svalue_set *live_svalues,
                                       const region_model *model) const
 {
   return get_arg ()->live_p (live_svalues, model);
 
 
   virtual void accept (visitor *v) const  = 0;
 
-  bool live_p (const svalue_set &live_svalues,
+  bool live_p (const svalue_set *live_svalues,
               const region_model *model) const;
-  virtual bool implicitly_live_p (const svalue_set &live_svalues,
+  virtual bool implicitly_live_p (const svalue_set *live_svalues,
                                  const region_model *model) const;
 
   static int cmp_ptr (const svalue *, const svalue *);
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   const region * get_pointee () const { return m_reg; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   tree get_constant () const { return m_cst_expr; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
+  bool initial_value_of_param_p () const;
+
   const region *get_region () const { return m_reg; }
 
  private:
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   enum tree_code get_op () const { return m_op; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   enum tree_code get_op () const { return m_op; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   const svalue *get_parent () const { return m_parent_svalue; }
 
   void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
   void accept (visitor *v) const FINAL OVERRIDE;
-  bool implicitly_live_p (const svalue_set &,
+  bool implicitly_live_p (const svalue_set *,
                          const region_model *) const FINAL OVERRIDE;
 
   const svalue *get_arg () const { return m_arg; }
 
 void list_tokens() {
   for (__normal_iterator base = list_tokens_token_list.begin();;) {
     int *add_info = new int;
-    (*base).add_info = add_info; // { dg-bogus "leak" "PR analyzer/98969" { xfail *-*-* } }
+    (*base).add_info = add_info; // { dg-warning "leak" }
   }
 }
 
-/* { dg-additional-options "-O1 -Wno-builtin-declaration-mismatch" } */
+/* { dg-additional-options "-Wno-analyzer-too-complex -O1 -Wno-builtin-declaration-mismatch" } */
 
 int
 l8 (void);
     {
       *mf = 0;
       (*mf)[ny] = (int *) malloc (sizeof (int));
-      th ((*mf)[ny]); /* { dg-warning "leak" } */
+      th ((*mf)[ny]);
     }
 }
 
 {
   struct foo *f = (struct foo *)i;
   f->expr = __builtin_malloc (1024);
-} /* { dg-bogus "leak" "PR analyzer/98969" { xfail *-*-* } } */
+} /* { dg-bogus "leak" } */
 
 void
 test_2 (long int i)
   __builtin_free (((struct foo *)i)->expr);
   __builtin_free (((struct foo *)i)->expr); /* { dg-warning "double-'free' of '\\*\\(\\(struct foo \\*\\)i\\)\\.expr'" } */
 }
+
+void
+test_3 (void *p)
+{
+  void **q = (void **)p;
+  *q = __builtin_malloc (1024);  
+}