-
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 4 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 |
---|---|---|
|
@@ -534,6 +534,9 @@ class Expr extends StmtParent, @expr { | |
|
||
/** Gets the function containing this control-flow node. */ | ||
override Function getControlFlowScope() { result = this.getEnclosingFunction() } | ||
|
||
/** Holds if this expression could be the return value of an implicitly declared function. */ | ||
predicate mayBeFromImplicitlyDeclaredFunction() { none() } | ||
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. Why not just make this a predicate of 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. Because we need to ask an 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. Yeah, I think that would be better. |
||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,8 @@ private class Fprintf extends FormattingFunction, NonThrowingFunction { | |
override int getFormatParameterIndex() { result = 1 } | ||
|
||
override int getOutputParameterIndex(boolean isStream) { result = 0 and isStream = true } | ||
|
||
override int getFirstFormatArgumentIndex() { result = 2 } | ||
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 looks odd. It feels like there might be a bug in one of the super classes. Otherwise, why doesn't 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 don't fully understand this, but it's what's needed to remove false-positives on the This line is safe because class 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. The root cause is actually that the extractor sometimes fails to mark function declarations as implicit. Hmm. Maybe that's the fix. 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. Fixed instead using 4341fab. I couldn't find a nice way to identify these extraction errors but hopefully the solution makes sense. |
||
} | ||
|
||
/** | ||
|
@@ -91,7 +93,7 @@ private class Sprintf extends FormattingFunction, NonThrowingFunction { | |
override int getFirstFormatArgumentIndex() { | ||
if this.hasName("__builtin___sprintf_chk") | ||
then result = 4 | ||
else result = this.getNumberOfParameters() | ||
else result = this.getNumberOfExplicitParameters() | ||
} | ||
} | ||
|
||
|
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,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 @@ | ||
| tests.c:6:18:6: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,10 @@ | ||
// semmle-extractor-options: --expect_errors | ||
|
||
int printf(const char * format, ...); | ||
|
||
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.
How can this be anything else than
int
?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.
I don't think it can be, so perhaps this test is redundant. But, I'm wondering what happens if a function is implicit in some compilation units, but explicit in others?
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.
It sound like that's something that need further thought, especially with regard to the implications that has for the changes made here?
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.
I've added a test for this scenario, and removed the redundant test. So it seems that
Function::getType()
can return multiple things if there are conflicting declarations.