<div dir="ltr">After arguing about this for like an hour with Richard, David, and Alexey, I think we have a better path forward...<div><br></div><div>Much as you suggest, the key is nuking the upcast in the asserts build. But we can fix a number of other things in the process. For example, it is really annoying that we construct ValueHandle objects for the empty and tombstone keys. Instead, it would be better if we could not construct an object at all, and it turns out there is a nice way to do this. Unfortunately, it requires some refactoring to DenseMap and DenseMapInfo to expose this freedom. I'm going to do that refactoring (which seems like generally good cleanup), and then we can look at a more direct way of fixing the bug here.</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jan 8, 2015 at 3:45 PM, Duncan P. N. Exon Smith <span dir="ltr"><<a href="mailto:dexonsmith@apple.com" target="_blank">dexonsmith@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class=""><br>
> On 2015-Jan-08, at 15:39, Duncan P. N. Exon Smith <<a href="mailto:dexonsmith@apple.com">dexonsmith@apple.com</a>> wrote:<br>
><br>
><br>
>> On 2015-Jan-08, at 15:15, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
>><br>
>> On Thu, Jan 8, 2015 at 3:04 PM, Chandler Carruth <<a href="mailto:chandlerc@google.com">chandlerc@google.com</a>> wrote:<br>
>><br>
>> On Thu, Jan 8, 2015 at 2:59 PM, Alexey Samsonov <<a href="mailto:vonosmas@gmail.com">vonosmas@gmail.com</a>> wrote:<br>
>>  This is where UBSan reports an error - P is not a pointer to an actual object, it's a fake value (0xfffff....), which is not even<br>
>>  properly aligned.<br>
>><br>
>> As I've said before, I believe UBSan is incorrect to report an error at this point. I don't believe the cast to a pointer is UB, I believe using that pointer for anything other than casting back to an integer is UB. We can't even compare it to another pointer (such a compare would also produce 'false', even for comparison with itself).<br>
>><br>
>> It looks like what's happening is that this invalid pointer value is being upcast, and that is what UBSan is complaining about. If so, I think UBSan is right, but the bug is in DenseMapInfo<AssertingVH<T>>: it shouldn't be assuming that DenseMapInfo<T*>'s getEmptyKey produces a valid pointer to a T; it obviously cannot do so.<br>
><br>
> Okay, this makes sense.  Thanks Alexey (and Richard) for clarifying.<br>
><br>
> Interestingly, there's only undefined behaviour in asserts builds,<br>
> since `AssertingVH` only inherits from `ValueHandleBase` (and upcasts)<br>
> in asserts builds.<br>
><br>
> This sort of thing should work:<br>
><br>
>    private:<br>
>    #ifndef NDEBUG<br>
>      AssertingVH(ValueTy *Raw, bool)<br>
>        : ValueHandleBase(Assert, reinterpret_cast<Value *>(Raw)) {}<br>
>    #endif<br>
><br>
>    public:<br>
>      static AssertingVH<T> getDenseMapKey(ValueTy *Raw) {<br>
>    #ifndef NDEBUG<br>
>        assert(Raw == DenseMapInfo<ValueTy *>::getEmptyKey() ||<br>
>               Raw == DenseMapInfo<ValueTy *>::getTombstoneKey());<br>
>        return AssertingVH(Raw, true);<br>
<br>
</span>Or this might need to be:<br>
<br>
    private:<br>
      AssertingVH(Value *Key, bool) : ValueHandleBase(Assert, Key) {}<br>
<br>
    public:<br>
      static AssertingVH<T> getDenseMapKey(ValueTy *Key) {<br>
<span class="">    #ifndef NDEBUG<br>
        assert(Raw == DenseMapInfo<ValueTy *>::getEmptyKey() ||<br>
               Raw == DenseMapInfo<ValueTy *>::getTombstoneKey());<br>
</span>        if (Raw == DenseMapInfo<ValueTy *>::getEmptyKey())<br>
          return AssertingVH(DenseMapInfo<Value *>::getEmptyKey(), bool());<br>
        return AssertingVH(DenseMapInfo<Value *>::getTombstoneKey(), bool());<br>
    #else<br>
        return AssertingVH(Raw);<br>
<div class="HOEnZb"><div class="h5">      }<br>
<br>
>    #else<br>
>        return AssertingVH(Raw);<br>
>    #endif<br>
>      }<br>
><br>
> Then we can have:<br>
><br>
>     template <class T> struct DenseMapInfo<AssertingVH<T>> {<br>
>       static AssertingVH<T> getEmptyKey() {<br>
>         return AssertingVH<T>::getDenseMapKey(DenseMapInfo<T *>::getEmptyKey());<br>
>       }<br>
><br>
>       static AssertingVH<T> getTombstoneKey() {<br>
>         return AssertingVH<T>::getDenseMapKey(DenseMapInfo<T *>::getTombstoneKey());<br>
>       }<br>
><br>
>       // ...<br>
>     };<br>
<br>
</div></div></blockquote></div><br></div>