Skip to content
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

Merged
merged 13 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: feature
---
* Added the predicate `mayBeFromImplicitlyDeclaredFunction()` to the `Call` class to represent calls that may be the return value of an implicitly declared C function.
* Added the predicate `getAnExplicitDeclarationEntry()` to the `Function` class to get a `FunctionDeclarationEntry` that is not implicit.
8 changes: 8 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/Function.qll
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
)
}

/**
* Gets a non-implicit function declaration entry.
*/
FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
result = this.getADeclarationEntry() and
not result.isImplicit()
}

private predicate declEntry(FunctionDeclarationEntry fde) {
fun_decls(unresolveElement(fde), underlyingElement(this), _, _, _) and
// If one .cpp file specializes a function, and another calls the
Expand Down
5 changes: 5 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/exprs/Call.qll
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ class Call extends Expr, NameQualifiableElement, TCall {
variableAddressEscapesTreeNonConst(va, this.getQualifier().getFullyConverted()) and
i = -1
}

/** Holds if this expression could be the return value of an implicitly declared function. */
predicate mayBeFromImplicitlyDeclaredFunction() {
this.getTarget().getADeclarationEntry().isImplicit()
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,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 = super.getFirstFormatArgumentIndex()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,21 @@ private Type getAFormatterWideTypeOrDefault() {
* A standard library function that uses a `printf`-like formatting string.
*/
abstract class FormattingFunction extends ArrayFunction, TaintFunction {
int firstFormatArgumentIndex;

FormattingFunction() {
firstFormatArgumentIndex > 0 and
if this.hasDefinition()
then firstFormatArgumentIndex = this.getDefinition().getNumberOfParameters()
else
if this instanceof BuiltInFunction
then firstFormatArgumentIndex = this.getNumberOfParameters()
else
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
firstFormatArgumentIndex = fde.getNumberOfParameters()
)
}

/** Gets the position at which the format parameter occurs. */
abstract int getFormatParameterIndex();

Expand Down Expand Up @@ -121,33 +136,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
* the first format specifier in the format string. We ignore all
* implicit function definitions.
*/
int getFirstFormatArgumentIndex() {
// 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)
if this.hasDefinition()
then result = this.getDefinition().getNumberOfParameters()
else result = this.getNumberOfExplicitParameters()
}

/**
* Gets a non-implicit function declaration entry.
*/
private FunctionDeclarationEntry getAnExplicitDeclarationEntry() {
result = this.getADeclarationEntry() and
not result.isImplicit()
}

/**
* Gets the number of parameters, excluding any parameters that have been defined
* from implicit function declarations. If there is some inconsistency in the number
* of parameters, then don't return anything.
*/
private int getNumberOfExplicitParameters() {
forex(FunctionDeclarationEntry fde | fde = this.getAnExplicitDeclarationEntry() |
result = fde.getNumberOfParameters()
)
}
int getFirstFormatArgumentIndex() { result = firstFormatArgumentIndex }

/**
* Gets the position of the buffer size argument, if any.
Expand Down
3 changes: 2 additions & 1 deletion cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ where
) and
not arg.isAffectedByMacro() and
not arg.isFromUninstantiatedTemplate(_) and
not actual.getUnspecifiedType() instanceof ErroneousType
not actual.getUnspecifiedType() instanceof ErroneousType and
not arg.(Call).mayBeFromImplicitlyDeclaredFunction()
select arg,
"This format specifier for type '" + expected.getName() + "' does not match the argument type '" +
actual.getUnspecifiedType().getName() + "'."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Remove results from the `cpp/wrong-type-format-argument` ("Wrong type of arguments to formatting function") query if the argument is the return value of an implicitly declared function.
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 Call c
where c.mayBeFromImplicitlyDeclaredFunction()
select c
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is now good, because int fprintf() now no longer yields a value for getFirstFormatArgumentIndex?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ void *malloc(size_t size);
double strtod(const char *ptr, char **endptr);
char *getenv(const char *name);
ssize_t read(int fd, void *buffer, size_t count);
int snprintf(char *s, size_t n, const char *format, ...);
Loading