rjmccall added a comment.

In https://reviews.llvm.org/D25448#571941, @vsk wrote:

> Thanks for your feedback so far, and sorry for the delayed response.
> In https://reviews.llvm.org/D25448#570014, @rjmccall wrote:
> > Wait, can you talk me through the bug here?
> Derived inherits from Base1 and Base2. We upcast an instance of Derived to 
> Base2, then call a method (f1). Clang figures out that the method has to be 
> Derived::f1. Next, clang passes in a pointer to the vtable pointer for 
> **Base1**, along with the typeinfo for **Base2**, into the sanitizer runtime. 
> This confuses the runtime, which reports that the dynamic type of the object 
> is "Base1", and that this does not match the expected type ("Base2").

A pointer to the vtable pointer for Base1 is a pointer to a Derived.  You have 
a multiple inheritance bug, or really a general inheritance bug.  It's being 
covered up in the case of single, non-virtual inheritance because that's the 
case in which a pointer to a base-class object is the same as a pointer to the 
derived class object.

When the devirtualizer sees what's formally a call to a method on Base2, and it 
decides that it can instead treat it as a call to a method on Derived, it has 
to adjust the 'this' pointer to point to a Derived.  (I don't know off-hand 
whether it does this by retroactively adjusting the pointer or whether it just 
avoids adjusting it in the first place.)  When it does this, it should also be 
changing its notion of what class the pointer points to.

> With the 'final' keyword:
>   %6 = ptrtoint <2 x i32 (...)**>* %1 to i64
>   call void @__ubsan_handle_dynamic_type_cache_miss(@1 (TypeInfo for Base2), 
> i64 %6, ...)
> Without the 'final' keyword:
>   %6 = bitcast <2 x i32 (...)**>* %1 to %class.Derived*
>   %7 = getelementptr inbounds %class.Derived, %class.Derived* %6, i64 0, i32 1
>   %8 = ptrtoint %class.Base2* %7 to i64, !nosanitize !5
>   call void @__ubsan_handle_dynamic_type_cache_miss(@1 (TypeInfo for Base2), 
> i64 %8, ...)
>>   Why is final-based devirtualization here different from, say, 
>> user-directed devirtualization via a qualified method name?
> I'm not sure. I tested this by removing the 'final' specifier from 'Derived' 
> and calling:
>   obj.Derived::f1()
> In this case, clang passes the correct typeinfo (for Derived) in to the 
> runtime.
>> It sounds to me from your description that you're not sure why this is 
>> happening.  If this indeed only triggers in the presence of multiple 
>> inheritance, it might just be the case that you're doing your object-extents 
>> analysis starting from the wrong offset.
> It looks like I just haven't done a good job of explaining the issue. The bug 
> really does seem to be that clang isn't passing the right information to the 
> ubsan runtime. However, I'm not sure what the right fix is. Do we disable 
> sanitization in cases where we expect FP's, do we try harder to pass in the 
> right vptr (in this case, the vptr for Base2) into the runtime, or do we try 
> harder to pass in the right typeinfo (in this case, the typeinfo for Derived)?


cfe-commits mailing list

Reply via email to