This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Fix vcall offsets in construction vtables


Jeffrey's tests found another defect in the way that we compute vcall
offsets in construction vtables, which could result in the `this'
pointer having the wrong value if a virtual function is called during
a constructor or destructor.

This statement

! 	  /* The FN comes from BASE.  So, we must calculate the
! 	     adjustment from vid->vbase to BASE.  We can just look for
! 	     BASE in the complete object because we are converting
! 	     from a virtual base, so if there were multiple copies,
! 	     there would not be a unique final overrider and
! 	     vid->derived would be ill-formed.  */

Fixed with the attached patch.

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2002-11-14  Mark Mitchell  <mark@codesourcery.com>

	* class.c (dfs_find_final_overrider): Adjust so that the most
	derived object is a binfo, rather than a class type.
	(find_final_overrider): Likewise.
	(add_vcall_offset_vtbl_entries_1): Simplify accordingly.
	(add_vcall_offset): Likewise.

2002-11-14  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/vcall1.C: New test.

Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.492
diff -c -5 -p -r1.492 class.c
*** cp/class.c	8 Nov 2002 02:16:45 -0000	1.492
--- cp/class.c	14 Nov 2002 16:49:27 -0000
*************** dfs_find_final_overrider (binfo, data)
*** 2218,2238 ****
  
        /* We haven't found an overrider yet.  */
        method = NULL_TREE;
        /* We've found a path to the declaring base.  Walk down the path
  	 looking for an overrider for FN.  */
!       for (path = reverse_path (binfo);
! 	   path;
! 	   path = TREE_CHAIN (path))
  	{
  	  method = look_for_overrides_here (BINFO_TYPE (TREE_VALUE (path)),
  					    ffod->fn);
  	  if (method)
  	    {
  	      path = TREE_VALUE (path);
  	      break;
  	    }
  	}
  
        /* If we found an overrider, record the overriding function, and
  	 the base from which it came.  */
        if (path)
--- 2218,2242 ----
  
        /* We haven't found an overrider yet.  */
        method = NULL_TREE;
        /* We've found a path to the declaring base.  Walk down the path
  	 looking for an overrider for FN.  */
!       path = reverse_path (binfo);
!       while (!same_type_p (BINFO_TYPE (TREE_VALUE (path)),
! 			   ffod->most_derived_type))
! 	path = TREE_CHAIN (path);
!       while (path)
  	{
  	  method = look_for_overrides_here (BINFO_TYPE (TREE_VALUE (path)),
  					    ffod->fn);
  	  if (method)
  	    {
  	      path = TREE_VALUE (path);
  	      break;
  	    }
+ 
+ 	  path = TREE_CHAIN (path);
  	}
  
        /* If we found an overrider, record the overriding function, and
  	 the base from which it came.  */
        if (path)
*************** dfs_find_final_overrider (binfo, data)
*** 2262,2277 ****
    return NULL_TREE;
  }
  
  /* Returns a TREE_LIST whose TREE_PURPOSE is the final overrider for
     FN and whose TREE_VALUE is the binfo for the base where the
!    overriding occurs.  BINFO (in the hierarchy dominated by T) is the
!    base object in which FN is declared.  */
  
  static tree
! find_final_overrider (t, binfo, fn)
!      tree t;
       tree binfo;
       tree fn;
  {
    find_final_overrider_data ffod;
  
--- 2266,2281 ----
    return NULL_TREE;
  }
  
  /* Returns a TREE_LIST whose TREE_PURPOSE is the final overrider for
     FN and whose TREE_VALUE is the binfo for the base where the
!    overriding occurs.  BINFO (in the hierarchy dominated by the binfo
!    DERIVED) is the base object in which FN is declared.  */
  
  static tree
! find_final_overrider (derived, binfo, fn)
!      tree derived;
       tree binfo;
       tree fn;
  {
    find_final_overrider_data ffod;
  
*************** find_final_overrider (t, binfo, fn)
*** 2293,2314 ****
       
       The solution is to look at all paths to BINFO.  If we find
       different overriders along any two, then there is a problem.  */
    ffod.fn = fn;
    ffod.declaring_base = binfo;
!   ffod.most_derived_type = t;
    ffod.candidates = NULL_TREE;
  
!   dfs_walk (TYPE_BINFO (t),
  	    dfs_find_final_overrider,
  	    NULL,
  	    &ffod);
  
    /* If there was no winner, issue an error message.  */
    if (!ffod.candidates || TREE_CHAIN (ffod.candidates))
      {
!       error ("no unique final overrider for `%D' in `%T'", fn, t);
        return error_mark_node;
      }
  
    return ffod.candidates;
  }
--- 2297,2319 ----
       
       The solution is to look at all paths to BINFO.  If we find
       different overriders along any two, then there is a problem.  */
    ffod.fn = fn;
    ffod.declaring_base = binfo;
!   ffod.most_derived_type = BINFO_TYPE (derived);
    ffod.candidates = NULL_TREE;
  
!   dfs_walk (derived,
  	    dfs_find_final_overrider,
  	    NULL,
  	    &ffod);
  
    /* If there was no winner, issue an error message.  */
    if (!ffod.candidates || TREE_CHAIN (ffod.candidates))
      {
!       error ("no unique final overrider for `%D' in `%T'", fn, 
! 	     BINFO_TYPE (derived));
        return error_mark_node;
      }
  
    return ffod.candidates;
  }
*************** update_vtable_entry_for_fn (t, binfo, fn
*** 2363,2373 ****
  	lost = true;
      }
    first_defn = b;
  
    /* Find the final overrider.  */
!   overrider = find_final_overrider (t, b, fn);
    if (overrider == error_mark_node)
      return;
  
    /* Check for unsupported covariant returns again now that we've
       calculated the base offsets.  */
--- 2368,2378 ----
  	lost = true;
      }
    first_defn = b;
  
    /* Find the final overrider.  */
!   overrider = find_final_overrider (TYPE_BINFO (t), b, fn);
    if (overrider == error_mark_node)
      return;
  
    /* Check for unsupported covariant returns again now that we've
       calculated the base offsets.  */
*************** add_vcall_offset_vtbl_entries_r (binfo, 
*** 7907,7924 ****
  static void
  add_vcall_offset_vtbl_entries_1 (binfo, vid)
       tree binfo;
       vtbl_init_data* vid;
  {
-   tree binfo_in_rtti;
- 
-   if (vid->ctor_vtbl_p)
-     binfo_in_rtti = (get_original_base
- 		     (binfo, TYPE_BINFO (BINFO_TYPE (vid->rtti_binfo))));
-   else
-     binfo_in_rtti = binfo;
- 
    /* Make entries for the rest of the virtuals.  */
    if (abi_version_at_least (2))
      {
        tree orig_fn;
  
--- 7912,7921 ----
*************** add_vcall_offset_vtbl_entries_1 (binfo, 
*** 7926,7936 ****
  	 order.  G++ 3.2 used the order in the vtable.  */
        for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo));
  	   orig_fn;
  	   orig_fn = TREE_CHAIN (orig_fn))
  	if (DECL_VINDEX (orig_fn))
! 	  add_vcall_offset (orig_fn, binfo_in_rtti, vid);
      }
    else
      {
        tree derived_virtuals;
        tree base_virtuals;
--- 7923,7933 ----
  	 order.  G++ 3.2 used the order in the vtable.  */
        for (orig_fn = TYPE_METHODS (BINFO_TYPE (binfo));
  	   orig_fn;
  	   orig_fn = TREE_CHAIN (orig_fn))
  	if (DECL_VINDEX (orig_fn))
! 	  add_vcall_offset (orig_fn, binfo, vid);
      }
    else
      {
        tree derived_virtuals;
        tree base_virtuals;
*************** add_vcall_offset_vtbl_entries_1 (binfo, 
*** 7991,8012 ****
  	     function slots introduced in BINFO.  So don't try to generate
  	     one if the function isn't even defined in BINFO.  */
  	  if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
  	    continue;
  
! 	  add_vcall_offset (orig_fn, binfo_in_rtti, vid);
  	}
      }
  }
  
! /* Add a vcall offset entry for ORIG_FN to the vtable.  In a
!    construction vtable, BINFO_IN_RTTI is the base corresponding to the
!    vtable base in VID->RTTI_BINFO.  */
  
  static void
! add_vcall_offset (tree orig_fn, tree binfo_in_rtti,
! 		  vtbl_init_data *vid)
  {
    size_t i;
    tree vcall_offset;
  
    /* If there is already an entry for a function with the same
--- 7988,8006 ----
  	     function slots introduced in BINFO.  So don't try to generate
  	     one if the function isn't even defined in BINFO.  */
  	  if (!same_type_p (DECL_CONTEXT (orig_fn), BINFO_TYPE (binfo)))
  	    continue;
  
! 	  add_vcall_offset (orig_fn, binfo, vid);
  	}
      }
  }
  
! /* Add a vcall offset entry for ORIG_FN to the vtable.  */
  
  static void
! add_vcall_offset (tree orig_fn, tree binfo, vtbl_init_data *vid)
  {
    size_t i;
    tree vcall_offset;
  
    /* If there is already an entry for a function with the same
*************** add_vcall_offset (tree orig_fn, tree bin
*** 8043,8081 ****
    VARRAY_PUSH_TREE (vid->fns, orig_fn);
  
    if (vid->generate_vcall_entries)
      {
        tree base;
-       tree base_binfo;
        tree fn;
  
        /* Find the overriding function.  */
!       fn = find_final_overrider (BINFO_TYPE (vid->rtti_binfo), 
! 				 binfo_in_rtti, orig_fn);
        if (fn == error_mark_node)
  	vcall_offset = build1 (NOP_EXPR, vtable_entry_type,
  			       integer_zero_node);
        else
  	{
! 	  fn = TREE_PURPOSE (fn);
! 	  /* The FN comes from BASE.  So, we must calculate the
! 	     adjustment from vid->vbase to BASE.  We can just look for
! 	     BASE in the complete object because we are converting
! 	     from a virtual base, so if there were multiple copies,
! 	     there would not be a unique final overrider and
! 	     vid->derived would be ill-formed.  */
! 	  base = DECL_CONTEXT (fn);
! 	  base_binfo = lookup_base (vid->derived, base, ba_any, NULL);
! 
! 	  /* Compute the vcall offset.  */
! 	  /* As mentioned above, the vbase we're working on is a
! 	     primary base of vid->binfo.  But it might be a lost
! 	     primary, so its BINFO_OFFSET might be wrong, so we just
! 	     use the BINFO_OFFSET from vid->binfo.  */
! 	  vcall_offset = BINFO_OFFSET (vid->binfo);
! 	  vcall_offset = size_diffop (BINFO_OFFSET (base_binfo),
! 				      vcall_offset);
  	  vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
  				       vcall_offset));
  	}
        /* Add the intiailizer to the vtable.  */
        *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
--- 8037,8063 ----
    VARRAY_PUSH_TREE (vid->fns, orig_fn);
  
    if (vid->generate_vcall_entries)
      {
        tree base;
        tree fn;
  
        /* Find the overriding function.  */
!       fn = find_final_overrider (vid->rtti_binfo, binfo, orig_fn);
        if (fn == error_mark_node)
  	vcall_offset = build1 (NOP_EXPR, vtable_entry_type,
  			       integer_zero_node);
        else
  	{
! 	  base = TREE_VALUE (fn);
! 
! 	  /* The vbase we're working on is a primary base of
! 	     vid->binfo.  But it might be a lost primary, so its
! 	     BINFO_OFFSET might be wrong, so we just use the
! 	     BINFO_OFFSET from vid->binfo.  */
! 	  vcall_offset = size_diffop (BINFO_OFFSET (base),
! 				      BINFO_OFFSET (vid->binfo));
  	  vcall_offset = fold (build1 (NOP_EXPR, vtable_entry_type,
  				       vcall_offset));
  	}
        /* Add the intiailizer to the vtable.  */
        *vid->last_init = build_tree_list (NULL_TREE, vcall_offset);
Index: testsuite/g++.dg/abi/vcall1.C
===================================================================
RCS file: testsuite/g++.dg/abi/vcall1.C
diff -N testsuite/g++.dg/abi/vcall1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/vcall1.C	14 Nov 2002 16:49:28 -0000
***************
*** 0 ****
--- 1,36 ----
+ // { dg-do run }
+ // { dg-options "-w" }
+ 
+ extern "C" void abort ();
+ 
+ struct B;
+ 
+ B* b;
+ 
+ struct A {
+   virtual void f () {}
+ };
+ 
+ struct B : virtual public A {
+   B () {
+     b = this;
+     ((A*) this)->f ();
+   }
+ 
+   virtual void f () {
+     if (this != b)
+       abort ();
+   }
+ };
+ 
+ struct C : public B {
+ };
+ 
+ struct D : public C, public B {
+   virtual void f () {}
+ };
+ 
+ int main () {
+   D d;
+ }
+ 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]