-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
C++: Reduce FPs in cpp/wrong-type-format-argument due to extraction errors #17775
Changes from 8 commits
fe85e00
853128c
6a48ad0
d88a674
ceceee1
9758e02
5315a5c
4341fab
4197805
0fcabc4
c5a082f
f37be68
421413a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: feature | ||
--- | ||
* Added the predicate `mayBeFromImplicitlyDeclaredFunction()` to the `Expr` class to represent expressions that may be the return value of an implicitly declared C function. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -125,6 +125,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction { | |
// The formatting function either has a definition in the snapshot, or all | ||
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't | ||
// really know the correct number) | ||
result > 0 and // Avoid invalid declarations | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would make more sense to me to make this condition part of the charPred of this abstract class. Reasoning: there are no arguments besides vararg ones, then there is no explicit argument for the formatting string, which would be very odd for a formatting function. Maybe something like: abstract class FormattingFunction extends ArrayFunction, TaintFunction {
int firstFormatArgumentIndex;
int numberOfExplicitParameters;
FormattingFunction() {
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
numberOfExplicitParameters = fde.getNumberOfParameters()
) and
(
if this.hasDefinition()
then firstFormatArgumentIndex = this.getDefinition().getNumberOfParameters()
else firstFormatArgumentIndex = numberOfExplicitParameters
) and
firstFormatArgumentIndex > 0
} and implement the relevant I think it would also make sense at this point to move There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will this also work for intrinsic functions like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Intrinsic functions should still have a prototype in the database. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried this out, and encountered a couple of problems:
I'll need to run DCA on this (once the tests pass), fix changenotes, and fix the tests on semmle-code. Are you still ok with this design? @jketema There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
That's an extractor bug, if it's reproducible in an integration test. Otherwise it's a bug in how we run tests. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've looked at this a bit:
Questions (I'll also have a look at whether I can answer this myself):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We look at declaration entries in order to figure out if the declaration was implicit or not. There can be spurious function parameters caused by extraction errors, so we need to double-check the function declaration entries. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've opened a PR for an additional internal test related to this. I think the right solution here is to use the information from the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I originally added There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds good. |
||
if this.hasDefinition() | ||
then result = this.getDefinition().getNumberOfParameters() | ||
else result = this.getNumberOfExplicitParameters() | ||
|
@@ -143,7 +144,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction { | |
* from implicit function declarations. If there is some inconsistency in the number | ||
* of parameters, then don't return anything. | ||
*/ | ||
private int getNumberOfExplicitParameters() { | ||
int getNumberOfExplicitParameters() { | ||
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() | | ||
result = fde.getNumberOfParameters() | ||
) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
--- | ||
category: minorAnalysis | ||
--- | ||
* Fixed false positives in the `cpp/wrong-type-format-argument` ("Wrong type of arguments to formatting function") query if there are extraction errors in the function. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is technically not true, as there are valid cases where a function is implicitly defined and correctly being used as a argument in a printf call. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it might also reject true-positives. Do you have a suggested text I could use? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we mostly want to be explicit about what we ignore, i.e., calls to functions that are implicitly declared, as in the majority of cases we see that these are due to extraction errors, and not because the codebase is pre-C99 C-code, which allows implicit function declarations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
| file://:0:0:0:0 | <error expr> | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import cpp | ||
|
||
from Expr e | ||
where e.getType() instanceof ErroneousType | ||
select e |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
| file://:0:0:0:0 | There was an error during this compilation | | ||
| implicit.cpp:5:5:5:5 | identifier 'g' is undefined | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import cpp | ||
|
||
from Diagnostic d | ||
select d |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
| implicit2.c:1:7:1:7 | g | file://:0:0:0:0 | float | | ||
| implicit2.c:1:7:1:7 | g | file://:0:0:0:0 | int | | ||
| implicit.c:1:6:1:6 | f | file://:0:0:0:0 | void | | ||
| implicit.c:3:5:3:5 | g | file://:0:0:0:0 | float | | ||
| implicit.c:3:5:3:5 | g | file://:0:0:0:0 | int | | ||
| implicit.cpp:3:6:3:6 | f | file://:0:0:0:0 | void | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import cpp | ||
|
||
from Function fn | ||
where fn.fromSource() | ||
select fn, fn.getType() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
void f() { | ||
f(); | ||
g(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// semmle-extractor-options: --expect_errors | ||
|
||
void f() { | ||
f(); | ||
g(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
| implicit.c:3:5:3:5 | call to g | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import cpp | ||
|
||
from Expr e | ||
where e.mayBeFromImplicitlyDeclaredFunction() | ||
select e |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
float g(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
| tests.c:7:18:7:18 | 1 | This format specifier for type 'char *' does not match the argument type 'int'. | |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Likely Bugs/Format/WrongTypeFormatArguments.ql |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// semmle-extractor-options: --expect_errors | ||
|
||
int printf(const char * format, ...); | ||
int fprintf(); | ||
|
||
void f() { | ||
printf("%s", 1); // BAD | ||
printf("%s", implicit_function()); // GOOD - we should ignore the type | ||
sprintf(0, "%s", ""); // GOOD | ||
fprintf(0, "%s", ""); // GOOD | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is now good, because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just make this a predicate of
Call
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we need to ask an
Expr
if it came from an implicitly-declared function. I suppose, we could have donearg.(Call).mayBeFromImplicitlyDeclaredFunction()
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think that would be better.