[PATCH] Fix UBSan error reports in ValueMapCallbackVH and AssertingVH<T> empty/tombstone keys generation.

Duncan P. N. Exon Smith dexonsmith at apple.com
Fri Jan 9 14:28:59 PST 2015


> On 2015-Jan-09, at 14:26, Alexey Samsonov <vonosmas at gmail.com> wrote:
> 
> ================
> Comment at: include/llvm/IR/ValueHandle.h:192-203
> @@ -191,14 +191,14 @@
> 
> #ifndef NDEBUG
>   ValueTy *getValPtr() const {
>     return static_cast<ValueTy*>(ValueHandleBase::getValPtr());
>   }
>   void setValPtr(ValueTy *P) {
>     ValueHandleBase::operator=(GetAsValue(P));
>   }
> #else
> -  ValueTy *ThePtr;
> -  ValueTy *getValPtr() const { return ThePtr; }
> -  void setValPtr(ValueTy *P) { ThePtr = P; }
> +  Value *ThePtr;
> +  ValueTy *getValPtr() const { return static_cast<ValueTy *>(ThePtr); }
> +  void setValPtr(ValueTy *P) { ThePtr = GetAsValue(P); }
> #endif
> 
> ----------------
> chandlerc wrote:
>> I would define helpers here for getRawValPtr and setRawValPtr which do the indirection between NDEBUG and debug builds. Then use them below (see comments).
> Done
> 
> ================
> Comment at: include/llvm/IR/ValueHandle.h:239-272
> @@ -239,23 +238,36 @@
> struct DenseMapInfo<AssertingVH<T> > {
> -  typedef DenseMapInfo<T*> PointerInfo;
>   static inline AssertingVH<T> getEmptyKey() {
> -    return AssertingVH<T>(PointerInfo::getEmptyKey());
> +    AssertingVH<T> Res;
> +    Value *V = DenseMapInfo<Value *>::getEmptyKey();
> +#ifndef NDEBUG
> +    Res.ValueHandleBase::operator=(V);
> +#else
> +    Res.ThePtr = V;
> +#endif
> +    return Res;
>   }
> -  static inline T* getTombstoneKey() {
> -    return AssertingVH<T>(PointerInfo::getTombstoneKey());
> +  static inline AssertingVH<T> getTombstoneKey() {
> +    AssertingVH<T> Res;
> +    Value *V = DenseMapInfo<Value *>::getTombstoneKey();
> +#ifndef NDEBUG
> +    Res.ValueHandleBase::operator=(V);
> +#else
> +    Res.ThePtr = V;
> +#endif
> +    return Res;
>   }
>   static unsigned getHashValue(const AssertingVH<T> &Val) {
> -    return PointerInfo::getHashValue(Val);
> +    return DenseMapInfo<T *>::getHashValue(Val);
>   }
> #ifndef NDEBUG
>   static bool isEqual(const AssertingVH<T> &LHS, const AssertingVH<T> &RHS) {
>     // Avoid downcasting AssertingVH<T> to T*, as empty/tombstone keys may not
>     // be properly aligned pointers to T*.
>     return LHS.ValueHandleBase::getValPtr() == RHS.ValueHandleBase::getValPtr();
>   }
> #else
>   static bool isEqual(const AssertingVH<T> &LHS, const AssertingVH<T> &RHS) {
>     return LHS == RHS;
>   }
> #endif
> };
> ----------------
> chandlerc wrote:
>> All of these NDEBUG vs. not can go away by using helpers defined once in the class above to get the raw Value* and set the raw Value*.
>> 
>> I also think you want to have both isEqual and getHashValue use the raw Value* and delegate to DenseMapInfo<Value *>.
> Done. However, what if some subclass MyValue of Value provides its own DenseMapInfo<MyValue*>::isEqual or DenseMapInfo<MyValue*>::getHashValue ?

This is would be pretty strange, but either way I think it's reasonable
for `AssertingVH<MyValue>` to base its values on `DenseMapInfo<Value *>`.



More information about the llvm-commits mailing list