[cfe-commits] r75356 - in /cfe/trunk: lib/Analysis/GRExprEngine.cpp test/Analysis/misc-ps.m

Zhongxing Xu xuzhongxing at gmail.com
Mon Jul 13 18:28:04 PDT 2009


On Tue, Jul 14, 2009 at 7:37 AM, Ted Kremenek<kremenek at apple.com> wrote:
> On Jul 11, 2009, at 3:42 AM, Zhongxing Xu wrote:
>
> Hi Ted,
>
> Here is another fix for this bug. Instead of recovering from a wrong
> invalidation, this patch aims to invalidate the region correctly. It
> uses the cast-to type to invalidate the region when available. To
> avoid invalid cast-to type like 'void*' or 'id', region store now only
> records non-generic casts of regions.
>
> On Sat, Jul 11, 2009 at 12:38 PM, Ted Kremenek<kremenek at apple.com> wrote:
>
> Author: kremenek
>
> Date: Fri Jul 10 23:38:49 2009
>
> New Revision: 75356
>
> URL: http://llvm.org/viewvc/llvm-project?rev=75356&view=rev
>
> Log:
>
> Handle insidious corner case exposed by RegionStoreManager when handling
> void* values that are bound
>
> to symbolic regions and then treated like integers.
>
> Modified:
>
>    cfe/trunk/lib/Analysis/GRExprEngine.cpp
>
>    cfe/trunk/test/Analysis/misc-ps.m
>
>
> Hi Zhongxing,
> I spent some time looking over this patch and testing it's behavior.  I
> think we're on the right track, but the patch itself isn't where we need it
> yet.  First I'll make some comments inline to mention some specific points,
> and then mention some other issues I observed.
> Index: include/clang/Analysis/PathSensitive/Store.h
> ===================================================================
> --- include/clang/Analysis/PathSensitive/Store.h (revision 75492)
> +++ include/clang/Analysis/PathSensitive/Store.h (working copy)
> @@ -145,6 +145,10 @@
>      return state;
>    }
>
> +  virtual const QualType *getCastType(const GRState *state, const MemRegion
> *R){
> +    return 0;
> +  }
> +
> Seems fine.  This is our notion of type information on the side.  It isn't
> as rich as it needs to be in the long term, but it's a good start.
>
>    /// EvalBinOp - Perform pointer arithmetic.
>    virtual SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,
>                           Loc lhs, NonLoc rhs, QualType resultTy) {
> Index: lib/Analysis/RegionStore.cpp
> ===================================================================
> --- lib/Analysis/RegionStore.cpp (revision 75492)
> +++ lib/Analysis/RegionStore.cpp (working copy)
> @@ -327,6 +327,10 @@
>    const GRState *setCastType(const GRState *state, const MemRegion* R,
>                               QualType T);
>
> +  const QualType *getCastType(const GRState *state, const MemRegion *R) {
> +    return state->get<RegionCasts>(R);
> +  }
> +
> Makes sense.
>
>    static inline RegionBindingsTy GetRegionBindings(Store store) {
>     return RegionBindingsTy(static_cast<const
> RegionBindingsTy::TreeTy*>(store));
>    }
> @@ -348,7 +352,26 @@
>  };
>
>  } // end anonymous namespace
> +static bool isGenericPtr(ASTContext &Ctx, QualType Ty) {
> +  if (Ty->isObjCIdType() || Ty->isObjCQualifiedIdType())
> +    return true;
> +  while (true) {
> +    Ty = Ctx.getCanonicalType(Ty);
>
> +    if (Ty->isVoidType())
> +      return true;
> +
> +    if (const PointerType *PT = Ty->getAsPointerType()) {
> +      Ty = PT->getPointeeType();
> +      continue;
> +    }
> +
> +    break;
> +  }
> +
> +  return false;
> +}
> +
> I have mixed feelings about this.  The problem is that there are wide range
> of generic pointers, e.g. "char *" is also a generic pointer.  I guess as
> long as we are using this just to handle transient type erasure then this
> seems okay.
>  //===----------------------------------------------------------------------===//
>  // RegionStore creation.
>  //===----------------------------------------------------------------------===//
> @@ -1251,6 +1274,8 @@
>
>  const GRState *RegionStoreManager::setCastType(const GRState *state,
>         const MemRegion* R, QualType T) {
> +  if (isGenericPtr(getContext(), T))
> +    return state;
>    return state->set<RegionCasts>(R, T);
>  }
> Makes sense.  I think we should add a comment about why the check for
> 'isGenericPtr' is there.  Also, we should document that if the region
> already has a cast type, casting it to void* doesn't remove that cast type.
> What should the semantics be if there already is a cast type associated with
> a region?

I think it's seldom that programmer would cast it back to generic
pointer intentionally. Often it is cast back to generic
pointer passively. E.g.:

void invalidate(void* p);
int *p = (int*)alloca();
void *q = (void*) p; // people don't do this.
invalidate(p); // people often do this.

>
> Index: lib/Analysis/Store.cpp
> ===================================================================
> --- lib/Analysis/Store.cpp (revision 75492)
> +++ lib/Analysis/Store.cpp (working copy)
> @@ -235,8 +235,16 @@
>
>    const TypedRegion *TR = cast<TypedRegion>(R);
>
> -  QualType T = TR->getValueType(Ctx);
> +  QualType T;
>
> +  // If the region is cast to another type, use that type.
> +  const QualType *CastTy = getCastType(state, R);
> +  if (CastTy) {
> +    T = (*CastTy)->getAsPointerType()->getPointeeType();
> +  }
> As a nitpick, I strongly prefer the style:
>
>   if (const QualType *CastTy = ...)
>   to
>   const QualType *CastTy;
>   if (CastTy = ...)
> The first case takes less code and restricts the scope of CastTy to the 'if'
> statement.  I like restricting scope of local variables to just the place
> where they are logically used, and no bigger.  It allows people reading the
> code to understand immediately that the value isn't used later.  It also
> reduces some subtle programming errors from a variable (incorrectly) being
> re-used.
> Second, this doesn't handle the case anymore where the value is an
> Objective-C pointer, since Objective-C pointers are now represented using
> ObjCObjectPointerType.  That actually might not be an issue since those
> regions shouldn't be boundable, but it's worth putting in an assertion.
> +  else
> +    T = TR->getValueType(Ctx);
> +
>    if (Loc::IsLocType(T) || (T->isIntegerType() && T->isScalarType())) {
>      SVal V = ValMgr.getConjuredSymbolVal(E, T, Count);
>      return Bind(state, ValMgr.makeLoc(TR), V);
> Looking at the rest of the InvalidateRegion code, I'm actually a little
> dubious.  I know you didn't write it, but I think we should consider what
> the general solution should be here.  Consider:
>     int x;
>     struct s *p = (struct s*) &x;
>     foo(p);
> This code might actually be valid if 'sizeof(struct s) <= sizeof(int)' and
> the alignments of both 'int' and 'struct s' are compatible.  Otherwise,
> we'll get a potential buffer overflow that we won't catch. Alternatively, we
> might not actually be doing the right thing.  I think this is something
> worth discussing.

The check is done (or should be done) in NewCastRegion(). If the cast
is legal, then type 'struct s' is used to
invalidate the region. I actually am not very clear about what you are
worrying about here.

> Index: lib/Analysis/GRExprEngine.cpp
> ===================================================================
> --- lib/Analysis/GRExprEngine.cpp (revision 75492)
> +++ lib/Analysis/GRExprEngine.cpp (working copy)
> @@ -1119,9 +1119,9 @@
>      //  invalidate(y);  // 'x' now binds to a symbolic region
>      //  int z = *y;
>      //
> -    if (isa<Loc>(V) && !Loc::IsLocType(Ex->getType())) {
> -      V = EvalCast(V, Ex->getType());
> -    }
> +    //if (isa<Loc>(V) && !Loc::IsLocType(Ex->getType())) {
> +    //  V = EvalCast(V, Ex->getType());
> +    // }
> This is the main change, but I cannot actually evaluate it yet.  Using the
> '-analyzer-viz-egraph-graphviz' option, I saw that for the following code:
>     int *__gruep__ = ((int *)&((b)->grue));
>     int __gruev__ = *__gruep__;
> that all we end up doing is conjuring a new symbol for the second
> declaration of '__gruev__' (even when using RegionStoreManager).

This is expected. We invalidate *__gruep__ with a conjured symbol.

> This can
> be seen readily with some enhancements I made today to the pretty-printing
> code for regions and symbols.  This issue may be related to the test case I
> added to 'misc-ps-region-store.m' (which causes that file to now XFAIL).
> I think your patch is a step in the right direction, and aside from the few
> comments I made I'd be happy with applying it and iterating on the design
> from there.
> Ted




More information about the cfe-commits mailing list