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

Peter Wu via cfe-dev cfe-dev at lists.llvm.org
Sun May 6 15:07:31 PDT 2018


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);

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?
-- 
Kind regards,
Peter Wu
https://lekensteyn.nl



More information about the cfe-dev mailing list