<div dir="ltr"><div><div><div>Hi Artem!<br><br></div>I wanted to note that a checker about the va_api call odering is under review: <a href="https://reviews.llvm.org/D15227">https://reviews.llvm.org/D15227</a><br><br></div>Regards,<br></div>Gábor<br></div><div class="gmail_extra"><br><div class="gmail_quote">On 28 July 2016 at 21:53, Artem Dergachev via cfe-dev <span dir="ltr"><<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> If i was to write such checker, i'd try the following:<br>
<br>
Map va_list-type variables (as memory regions) upon va_start(), map them to the number of read arguments (0 so far), and to the current StackFrameContext pointer, which represents a particular function call within which we are now (CheckerContext::getCurrentStackFrame()) (second program state map - or map to structure with two items).<br>
<br>
You can retrieve [path-sensitive] function declaration and [path-insensitive] call expression from the stack frame context, and compute the number of variadic arguments passed based on that.<br>
<br>
If va_start() is called upon a variable that is already tracked, warn.<br>
<br>
If va_start() is called twice in the same StackFrameContext, warn.<br>
<br>
Upon va_arg(), increment the number of reads for the respective variable. If the variable is not tracked, then the user has forgotten to call va_start(), hence warn. If the number exceeds the remembered total number of arguments, warn.<br>
<br>
Upon va_copy(), copy the whole map item to the new variable. If the source variable is not va_start()'ed, warn.<br>
<br>
Upon va_end(), erase the map item, which means that you no longer track the variable. If the variable is not va_start()'ed, warn.<br>
<br>
Upon checkDeadSymbols, see if any of the tracked va_list variables is dead (in the sense of SymbolReaper::isLiveRegion()). If it is dead, then va_end() will never be called on it (and it wasn't so far, because the variable is still in the map). Hence warn on forgotten va_end().<br>
<br>
You don't need to track end of function to warn on forgotten va_end() - checkDeadSymbols is already more frequent.<br>
<br>
If you expect seeing a lot of passing va_list variables by pointers (which is insane but i guess possible), then consider the following.<br>
<br>
Upon checkPointerEscape, see if any of the tracked va_list variables escapes. If so, mark it in the map as escaped: it might have va_end()'ed elsewhere, so we should not warn if it dies. Hence you cannot erase it from the program state - instead, you'd essentially need a separate trait flag (though you may put some magic constant into the existing trait).<br>
<br>
If the memory region of the va_list variable has symbolic base (came to us by pointer, rather than variable declaration), then it might have already been initialized with va_start. Hence you shouldn't warn if va_arg()/va_end()/va_copy() is called upon it without prior va_start().<br>
<br>
Hence the checker looks pretty similar to SimpleStreamChecker described in the video, and it's a very typical path-sensitive checker. I don't expect much problems on this path - it may sound like a lot of info, but basically it should be easy.<br>
<br>
If you are only interested in argument count overflows, but not in other va_* API misuse, then probably you may simplify this "typestate machine". But you'd still need to catch va_start() and va_args() and most likely va_copy(), and once you do, you get all other checks for almost-free.<div class="HOEnZb"><div class="h5"><br>
_______________________________________________<br>
cfe-dev mailing list<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
</div></div></blockquote></div><br></div>