[PATCH] ADT: Remove misaligned pointeres from DenseMapInfo

Duncan P. N. Exon Smith dexonsmith at apple.com
Thu Jan 8 15:45:13 PST 2015


> On 2015-Jan-08, at 15:39, Duncan P. N. Exon Smith <dexonsmith at apple.com> wrote:
> 
> 
>> On 2015-Jan-08, at 15:15, Richard Smith <richard at metafoo.co.uk> wrote:
>> 
>> On Thu, Jan 8, 2015 at 3:04 PM, Chandler Carruth <chandlerc at google.com> wrote:
>> 
>> On Thu, Jan 8, 2015 at 2:59 PM, Alexey Samsonov <vonosmas at gmail.com> wrote:
>>  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
>>  properly aligned.
>> 
>> 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).
>> 
>> 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.
> 
> Okay, this makes sense.  Thanks Alexey (and Richard) for clarifying.
> 
> Interestingly, there's only undefined behaviour in asserts builds,
> since `AssertingVH` only inherits from `ValueHandleBase` (and upcasts)
> in asserts builds.
> 
> This sort of thing should work:
> 
>    private:
>    #ifndef NDEBUG
>      AssertingVH(ValueTy *Raw, bool)
>        : ValueHandleBase(Assert, reinterpret_cast<Value *>(Raw)) {}
>    #endif
> 
>    public:
>      static AssertingVH<T> getDenseMapKey(ValueTy *Raw) {
>    #ifndef NDEBUG
>        assert(Raw == DenseMapInfo<ValueTy *>::getEmptyKey() ||
>               Raw == DenseMapInfo<ValueTy *>::getTombstoneKey());
>        return AssertingVH(Raw, true);

Or this might need to be:

    private:
      AssertingVH(Value *Key, bool) : ValueHandleBase(Assert, Key) {}

    public:
      static AssertingVH<T> getDenseMapKey(ValueTy *Key) {
    #ifndef NDEBUG
        assert(Raw == DenseMapInfo<ValueTy *>::getEmptyKey() ||
               Raw == DenseMapInfo<ValueTy *>::getTombstoneKey());
        if (Raw == DenseMapInfo<ValueTy *>::getEmptyKey())
          return AssertingVH(DenseMapInfo<Value *>::getEmptyKey(), bool());
        return AssertingVH(DenseMapInfo<Value *>::getTombstoneKey(), bool());
    #else
        return AssertingVH(Raw);
      }

>    #else
>        return AssertingVH(Raw);
>    #endif
>      }
> 
> Then we can have:
> 
>     template <class T> struct DenseMapInfo<AssertingVH<T>> {
>       static AssertingVH<T> getEmptyKey() {
>         return AssertingVH<T>::getDenseMapKey(DenseMapInfo<T *>::getEmptyKey());
>       }
> 
>       static AssertingVH<T> getTombstoneKey() {
>         return AssertingVH<T>::getDenseMapKey(DenseMapInfo<T *>::getTombstoneKey());
>       }
> 
>       // ...
>     };





More information about the llvm-commits mailing list