Skip to content

Commit

Permalink
Merge pull request #17775 from github/calumgrant/bmn/wrong-type-forma…
Browse files Browse the repository at this point in the history
…t-arguments-test

C++: Reduce FPs in cpp/wrong-type-format-argument due to extraction errors
  • Loading branch information
calumgrant authored Oct 24, 2024
2 parents 226756e + 421413a commit a8f1d57
Show file tree
Hide file tree
Showing 22 changed files with 95 additions and 29 deletions.
5 changes: 5 additions & 0 deletions cpp/ql/lib/change-notes/2014-10-16-implicitly-declared-fns.md
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
43 changes: 16 additions & 27 deletions cpp/ql/lib/semmle/code/cpp/models/interfaces/FormattingFunction.qll
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 |
4 changes: 4 additions & 0 deletions cpp/ql/test/library-tests/exprs/implicitly_declared/errors.ql
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
}
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, ...);

0 comments on commit a8f1d57

Please sign in to comment.