[StaticAnalyzer] How to allocate SymbolRef for values passed through function parameters


I am new to clang and I am developing a checker to detect resource leaks that is similar to the SimpleStreamChecker except that the target function is passing its return value through parameters. The example code would be like:

int request(int * arg1, int * arg2);
int release(int arg1);

void foo() {
int fd1 = 0, fd2 = 0;

request(&fd1, &fd2);

// … some unrelated code


Here, the integer fd1 and fd2 are resource descriptors that should be assigned with unique integer values after the “request(&fd1, &fd2)” call. The resource will be leaked if someone forgot to call “release(fd)” on a resource descriptor.

The problem is , if I use the “Call.getArgSVal(0)” on the calls to the “release(fd1)” or “release(fd2)” function, I only get a “ConcreteInt” which is the value “0” that I assigned in the initializer instead of a SVal with a SymbolRef. In this case, I cannot determine if the value in “fd1” is the same value that is assigned after the call to the “request(&fd1, &fd2)”.

The original SimpleStreamChecker does not have this issue because the file descriptor (to be precise, it is FILE *) used in “FILE *F = fopen(“mylog.txt”, “w”);” is passed through the return value instead of parameter. In this case, clang will allocate a SymbolRef for “F”. And it will be the same one if I call “Call.getReturnValue().getAsSymbol()” on a “fclose(F)”.

My question is, is there anyway to allocate SymbolRef to the variables pointed by arg1 and arg2 manually in the checkPreCall for the “int request(int * arg1, int * arg2)”? So in checkPostCall for “int release(int arg1);” I can use “Call.getReturnValue().getAsSymbol()” to check if the SymbolRef of “arg1” is the same one that allocated in “int request(int * arg1, int * arg2)”?

Thanks for any help,

Hello Haowei,

After call to request(), both values of fd1 and fd2 should become symbolic. This is because its body is not available in the current translation unit so the analyzer invalidates the values of argument pointers. I can see this behaviour while reproducing your test - both fd1 and fd2 are assigned with SymbolConjured.
This behaviour you observe looks strange. Do you try to perform evalCall() on request() function? If so, you could forgot to invalidate the arguments. Could you post your checker here?

23.05.2017 03:21, Haowei Wu via cfe-dev пишет:

Yep, i don't have much to add to Alexey's answer.

Assuming the body of request() is unavailable and your checker doesn't try to explicitly model it via evalCall() or a body farm, concrete-0 values of local variables fd1 and fd2 should be replaced with conjured symbols, and remain as such until touched by another call or assignment, so you *should* be able to obtain these exact symbols in release().

The analyzer might have found an execution path on which descriptors were never requested, but in the code you posted this is definitely not the case. Or they might have been accidentally overwritten with 0's during the "some unrelated code", which would no longer be unrelated in this case.

It is supposed to just work "out of the box". If it doesn't, you may want to share a small reproducer code.

It turns out that I put a fake body in the code for “request” function. In this case, the fd1 and fd2 are never touched in the fake body so no SymbolRef is created for fd1 and fd2. After I removed the body, it works.

Thanks for your helps.