Skip to content

Commit 8989761

Browse files
authored
Merge pull request github#1987 from geoffw0/toomanyformat
CPP: WrongNumberOfFormatArguments.ql Fix
2 parents 90c91a7 + b3df289 commit 8989761

File tree

8 files changed

+87
-2
lines changed

8 files changed

+87
-2
lines changed

change-notes/1.23/analysis-cpp.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ The following changes in version 1.23 affect C/C++ analysis in all applications.
1818
| Hard-coded Japanese era start date in call (`cpp/japanese-era/constructor-or-method-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
1919
| Hard-coded Japanese era start date in struct (`cpp/japanese-era/struct-with-exact-era-date`) | Deprecated | This query has been deprecated. Use the new combined query Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) instead. |
2020
| Hard-coded Japanese era start date (`cpp/japanese-era/exact-era-date`) | More correct results | This query now checks for the beginning date of the Reiwa era (1st May 2019). |
21+
| Too few arguments to formatting function (`cpp/wrong-number-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. |
22+
| Too many arguments to formatting function (`cpp/too-many-format-arguments`) | Fewer false positive results | Fixed false positives resulting from mistmatching declarations of a formatting function. |
2123

2224
## Changes to QL libraries
2325

cpp/ql/src/semmle/code/cpp/commons/Printf.qll

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,11 @@ class FormattingFunctionCall extends Expr {
169169
* Gets the number of arguments to this call that are parameters to the
170170
* format string.
171171
*/
172-
int getNumFormatArgument() { result = count(this.getFormatArgument(_)) }
172+
int getNumFormatArgument() {
173+
result = count(this.getFormatArgument(_)) and
174+
// format arguments must be known
175+
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
176+
}
173177
}
174178

175179
/**

cpp/ql/src/semmle/code/cpp/models/interfaces/FormattingFunction.qll

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,19 @@ abstract class FormattingFunction extends Function {
115115
* Gets the position of the first format argument, corresponding with
116116
* the first format specifier in the format string.
117117
*/
118-
int getFirstFormatArgumentIndex() { result = getNumberOfParameters() }
118+
int getFirstFormatArgumentIndex() {
119+
result = getNumberOfParameters() and
120+
// the formatting function either has a definition in the snapshot, or all
121+
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
122+
// really know the correct number)
123+
(
124+
hasDefinition()
125+
or
126+
forall(FunctionDeclarationEntry fde | fde = getADeclarationEntry() |
127+
result = fde.getNumberOfParameters()
128+
)
129+
)
130+
}
119131

120132
/**
121133
* Gets the position of the buffer size argument, if any.

cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/TooManyFormatArguments.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
| a.c:18:3:18:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
2+
| b.c:15:3:15:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
3+
| c.c:7:3:7:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 2 |
14
| custom_printf.cpp:31:5:31:12 | call to myPrintf | Format expects 2 arguments but given 3 |
25
| macros.cpp:12:2:12:31 | call to printf | Format expects 2 arguments but given 3 |
36
| macros.cpp:16:2:16:30 | call to printf | Format expects 2 arguments but given 3 |

cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/WrongNumberOfFormatArguments.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
| a.c:16:3:16:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
2+
| b.c:13:3:13:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
3+
| c.c:5:3:5:25 | call to myMultiplyDefinedPrintf | Format expects 1 arguments but given 0 |
14
| custom_printf.cpp:29:5:29:12 | call to myPrintf | Format expects 2 arguments but given 1 |
25
| macros.cpp:14:2:14:37 | call to printf | Format expects 4 arguments but given 3 |
36
| macros.cpp:21:2:21:36 | call to printf | Format expects 4 arguments but given 3 |
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
__attribute__((format(printf, 1, 3)))
3+
void myMultiplyDefinedPrintf(const char *format, int extraArg, ...)
4+
{
5+
// ...
6+
}
7+
8+
__attribute__((format(printf, 1, 3)))
9+
void myMultiplyDefinedPrintf2(const char *format, int extraArg, ...);
10+
11+
__attribute__((format(printf, 2, 3)))
12+
void myMultiplyDefinedPrintf3(const char *extraArg, const char *format, ...);
13+
14+
void test_custom_printf1()
15+
{
16+
myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments)
17+
myMultiplyDefinedPrintf("%i", 0, 1); // GOOD
18+
myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments)
19+
myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
20+
myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
21+
myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
22+
myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
23+
myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
24+
myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
25+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
__attribute__((format(printf, 1, 2)))
3+
void myMultiplyDefinedPrintf(const char *format, ...); // this declaration does not match the definition
4+
5+
__attribute__((format(printf, 1, 2)))
6+
void myMultiplyDefinedPrintf2(const char *format, ...);
7+
8+
__attribute__((format(printf, 1, 2)))
9+
void myMultiplyDefinedPrintf3(const char *format, ...);
10+
11+
void test_custom_printf2()
12+
{
13+
myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments)
14+
myMultiplyDefinedPrintf("%i", 0, 1); // GOOD
15+
myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments)
16+
myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
17+
myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
18+
myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
19+
myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
20+
myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
21+
myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
22+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
void test_custom_printf2()
3+
{
4+
// (implicitly defined)
5+
myMultiplyDefinedPrintf("%i", 0); // BAD (too few format arguments)
6+
myMultiplyDefinedPrintf("%i", 0, 1); // GOOD
7+
myMultiplyDefinedPrintf("%i", 0, 1, 2); // BAD (too many format arguments)
8+
myMultiplyDefinedPrintf2("%i", 0); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
9+
myMultiplyDefinedPrintf2("%i", 0, 1); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
10+
myMultiplyDefinedPrintf2("%i", 0, 1, 2); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
11+
myMultiplyDefinedPrintf3("%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
12+
myMultiplyDefinedPrintf3("%s", "%s", "%s"); // GOOD (we can't tell which definition is correct so we have to assume this is OK)
13+
myMultiplyDefinedPrintf3("%s", "%s", "%s", "%s"); // BAD (too many format arguments regardless of which definition is correct) [NOT DETECTED]
14+
}

0 commit comments

Comments
 (0)