[cfe-dev] [analyzer] Expressing dependencies between arguments and return values

Aleksei Sidorin via cfe-dev cfe-dev at lists.llvm.org
Mon May 7 01:59:32 PDT 2018


Hello Peter,

07.05.2018 01:07, Peter Wu via cfe-dev пишет:
> Hi!
>
> I just got started with writing a Clang Static Analyzer checker,
> primarily to detect these classes of issues in C:
>
> - allocator/deallocator mismatch: e.g. "g_malloc" must be accompanied by
>    "g_free" and not "free".
> - memory leak due to allocator mismatch: e.g. "g_list_new" must be
>    accompanied by "g_list_free" and not "g_free".
> - memory leaks and use-after-free issues in general.
>
> I have an initial version working based on Anna's and Jordan's talk, but
> am looking at methods to reduce false positives and false negatives.
> Consider this example:
>
>      void checkIdentityFunctionLeak() {
>        char *p = g_strdup("");
>        char *q = g_strdelimit(p, "_", '-');
>      } // expected-warning {{Memory leak}}
>
> To avoid false positives with memleak reporting, I added a pointerEscape
> callback that removes symbols. This however has as side-effect that "p"
> in the above example is not reported as leaked. "g_strdelimit" can be
> modelled as an identity function (p==q), but my attempt to express this
> constraint in the PostCall callback failed:
>
>      SValBuilder &svalBuilder = C.getSValBuilder();
>      ProgramStateRef State = C.getState();
>      SVal Arg0 = Call.getArgSVal(0);
>      SVal RetVal = Call.getReturnValue();
>      DefinedOrUnknownSVal arg0 = Arg0.castAs<DefinedOrUnknownSVal>();
>      DefinedOrUnknownSVal retVal = RetVal.castAs<DefinedOrUnknownSVal>();
>      DefinedOrUnknownSVal PtrEQ = svalBuilder.evalEQ(State, arg0, retVal);
>      State = State->assume(PtrEQ, true);
>      C.addTransition(State);
The best way to tell the analyzer that some expression returns _exactly 
same_ value as the argument is to bind the value of the argument as the 
return result of this expression.

     ProgramStateRef State = C.getState();
     SVal Arg0Val = Call.getArgSVal(0);
     State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), Arg0Val);
     C.addTransition(State);

Our primary solver (RangeConstraintManager) has very limited possibilities of handling complex symbolic expressions so it is better to simplify them as much as possible.

> While the debug.ViewExplodedGraph option shows that the symbols are
> assumed to be the same in the CallExpr node:
>
>      conj_$1{gpointer} : { [1, 18446744073709551615] }
>      (conj_$4{gchar *}) - (conj_$1{gpointer}) : { [0, 0] }
>
> this range information is somehow lost in the next nodes.
>
> Another example which is currently not caught either (strstr returns an
> address from the region of "p"):
>
>      int main() {
>          char *p = strdup("xyz");
>          if (!p) return 1;
>          char *p2 = strstr(p, "z");
>          free(p);
>          puts(p2); // expected-warning {{Use-after-free}}
>      }
>
> Have I misunderstood something in modelling this? Is it possible to
> express dependencies between the return value and the arguments of a
> library function?

strstr() lacks modeling in analyzer so it just returns a conjured value. 
A correct return value should be an ElementRegion whose base region is 
the region pointed by 'p'. You can try construct this return value using 
MemRegionManager methods.

Hope this helps.

-- 
Best regards,
Aleksei Sidorin,
SRR, Samsung Electronics




More information about the cfe-dev mailing list