Skip to content

Commit 27b5902

Browse files
authored
Merge pull request #2707 from geoffw0/taint-format
C++: Add TaintFunction model to FormattingFunction
2 parents 9504da5 + fc1816c commit 27b5902

File tree

9 files changed

+295
-5
lines changed

9 files changed

+295
-5
lines changed

change-notes/1.24/analysis-cpp.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,4 @@ The following changes in version 1.24 affect C/C++ analysis in all applications.
4040
* The taint tracking library (`semmle.code.cpp.dataflow.TaintTracking`) has had
4141
the following improvements:
4242
* The library now models data flow through `strdup` and similar functions.
43-
43+
* The library now models data flow through formatting functions such as `sprintf`.

cpp/ql/src/semmle/code/cpp/Parameter.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,5 +163,8 @@ class Parameter extends LocalScopeVariable, @parameter {
163163
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
164164
*/
165165
class ParameterIndex extends int {
166-
ParameterIndex() { exists(Parameter p | this = p.getIndex()) }
166+
ParameterIndex() {
167+
exists(Parameter p | this = p.getIndex()) or
168+
exists(Call c | exists(c.getArgument(this))) // permit indexing varargs
169+
}
167170
}

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* `FormattingFunction` to match the flow within that function.
77
*/
88

9-
import semmle.code.cpp.Function
9+
import semmle.code.cpp.models.interfaces.ArrayFunction
10+
import semmle.code.cpp.models.interfaces.Taint
1011

1112
private Type stripTopLevelSpecifiersOnly(Type t) {
1213
result = stripTopLevelSpecifiersOnly(t.(SpecifiedType).getBaseType())
@@ -39,7 +40,7 @@ private Type getAFormatterWideTypeOrDefault() {
3940
/**
4041
* A standard library function that uses a `printf`-like formatting string.
4142
*/
42-
abstract class FormattingFunction extends Function {
43+
abstract class FormattingFunction extends ArrayFunction, TaintFunction {
4344
/** Gets the position at which the format parameter occurs. */
4445
abstract int getFormatParameterIndex();
4546

@@ -133,4 +134,33 @@ abstract class FormattingFunction extends Function {
133134
* Gets the position of the buffer size argument, if any.
134135
*/
135136
int getSizeParameterIndex() { none() }
137+
138+
override predicate hasArrayWithNullTerminator(int bufParam) {
139+
bufParam = getFormatParameterIndex()
140+
}
141+
142+
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
143+
bufParam = getOutputParameterIndex() and
144+
countParam = getSizeParameterIndex()
145+
}
146+
147+
override predicate hasArrayWithUnknownSize(int bufParam) {
148+
bufParam = getOutputParameterIndex() and
149+
not exists(getSizeParameterIndex())
150+
}
151+
152+
override predicate hasArrayInput(int bufParam) { bufParam = getFormatParameterIndex() }
153+
154+
override predicate hasArrayOutput(int bufParam) { bufParam = getOutputParameterIndex() }
155+
156+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
157+
exists(int arg |
158+
(
159+
arg = getFormatParameterIndex() or
160+
arg >= getFirstFormatArgumentIndex()
161+
) and
162+
input.isParameterDeref(arg) and
163+
output.isParameterDeref(getOutputParameterIndex())
164+
)
165+
}
136166
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
2+
typedef unsigned long size_t;
3+
typedef struct {} FILE;
4+
5+
int snprintf(char *s, size_t n, const char *format, ...);
6+
int sprintf(char *s, const char *format, ...);
7+
int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...);
8+
9+
typedef void *va_list;
10+
#define va_start(ap, parmN)
11+
#define va_end(ap)
12+
#define va_arg(ap, type) ((type)0)
13+
14+
int vsnprintf(char *s, size_t n, const char *format, va_list arg);
15+
16+
int mysprintf(char *s, size_t n, const char *format, ...)
17+
{
18+
va_list args;
19+
va_start(args, format);
20+
vsnprintf(s, n, format, args);
21+
va_end(args);
22+
}
23+
24+
int sscanf(const char *s, const char *format, ...);
25+
26+
// ----------
27+
28+
int source();
29+
void sink(...) {};
30+
31+
namespace string
32+
{
33+
char *source();
34+
};
35+
36+
namespace wstring
37+
{
38+
wchar_t *source();
39+
};
40+
41+
// ----------
42+
43+
void test1()
44+
{
45+
{
46+
char buffer[256] = {0};
47+
sink(snprintf(buffer, 256, "%s", "Hello."));
48+
sink(buffer);
49+
}
50+
{
51+
char buffer[256] = {0};
52+
sink(snprintf(buffer, 256, "%s", string::source()));
53+
sink(buffer); // tainted
54+
}
55+
{
56+
char buffer[256] = {0};
57+
sink(snprintf(buffer, 256, string::source(), "Hello."));
58+
sink(buffer); // tainted
59+
}
60+
{
61+
char buffer[256] = {0};
62+
sink(snprintf(buffer, 256, "%s %s %s", "a", "b", string::source()));
63+
sink(buffer); // tainted
64+
}
65+
{
66+
char buffer[256] = {0};
67+
sink(snprintf(buffer, 256, "%.*s", 10, string::source()));
68+
sink(buffer); // tainted
69+
}
70+
71+
{
72+
char buffer[256] = {0};
73+
sink(snprintf(buffer, 256, "%i", 0));
74+
sink(buffer);
75+
}
76+
{
77+
char buffer[256] = {0};
78+
sink(snprintf(buffer, 256, "%i", source()));
79+
sink(buffer); // tainted
80+
}
81+
{
82+
char buffer[256] = {0};
83+
sink(snprintf(buffer, 256, "%.*s", source(), "Hello."));
84+
sink(buffer); // tainted
85+
}
86+
87+
{
88+
char buffer[256] = {0};
89+
sink(snprintf(buffer, 256, "%p", string::source()));
90+
sink(buffer); // tainted (debatable)
91+
}
92+
93+
{
94+
char buffer[256] = {0};
95+
sink(sprintf(buffer, "%s", string::source()));
96+
sink(buffer); // tainted
97+
}
98+
{
99+
char buffer[256] = {0};
100+
sink(sprintf(buffer, "%ls", wstring::source()));
101+
sink(buffer); // tainted
102+
}
103+
{
104+
wchar_t wbuffer[256] = {0};
105+
sink(swprintf(wbuffer, 256, L"%s", wstring::source()));
106+
sink(wbuffer); // tainted
107+
}
108+
{
109+
char buffer[256] = {0};
110+
sink(mysprintf(buffer, 256, "%s", string::source()));
111+
sink(buffer); // tainted [NOT DETECTED - implement UserDefinedFormattingFunction.getOutputParameterIndex()]
112+
}
113+
114+
{
115+
int i = 0;
116+
sink(sscanf("123", "%i", &i));
117+
sink(i);
118+
}
119+
{
120+
int i = 0;
121+
sink(sscanf(string::source(), "%i", &i));
122+
sink(i); // tainted [NOT DETECTED]
123+
}
124+
{
125+
char buffer[256] = {0};
126+
sink(sscanf("Hello.", "%s", &buffer));
127+
sink(buffer);
128+
}
129+
{
130+
char buffer[256] = {0};
131+
sink(sscanf(string::source(), "%s", &buffer));
132+
sink(buffer); // tainted [NOT DETECTED]
133+
}
134+
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,108 @@
33
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
44
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
55
| file://:0:0:0:0 | p#0 | file://:0:0:0:0 | p#0 | |
6+
| format.cpp:16:21:16:21 | s | format.cpp:20:13:20:13 | s | |
7+
| format.cpp:16:31:16:31 | n | format.cpp:20:16:20:16 | n | |
8+
| format.cpp:16:46:16:51 | format | format.cpp:20:19:20:24 | format | |
9+
| format.cpp:18:10:18:13 | args | format.cpp:20:27:20:30 | args | |
10+
| format.cpp:46:21:46:24 | {...} | format.cpp:47:17:47:22 | buffer | |
11+
| format.cpp:46:21:46:24 | {...} | format.cpp:48:8:48:13 | buffer | |
12+
| format.cpp:46:23:46:23 | 0 | format.cpp:46:21:46:24 | {...} | TAINT |
13+
| format.cpp:47:17:47:22 | ref arg buffer | format.cpp:48:8:48:13 | buffer | |
14+
| format.cpp:47:30:47:33 | %s | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
15+
| format.cpp:47:36:47:43 | Hello. | format.cpp:47:17:47:22 | ref arg buffer | TAINT |
16+
| format.cpp:51:21:51:24 | {...} | format.cpp:52:17:52:22 | buffer | |
17+
| format.cpp:51:21:51:24 | {...} | format.cpp:53:8:53:13 | buffer | |
18+
| format.cpp:51:23:51:23 | 0 | format.cpp:51:21:51:24 | {...} | TAINT |
19+
| format.cpp:52:17:52:22 | ref arg buffer | format.cpp:53:8:53:13 | buffer | |
20+
| format.cpp:52:30:52:33 | %s | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
21+
| format.cpp:52:36:52:49 | call to source | format.cpp:52:17:52:22 | ref arg buffer | TAINT |
22+
| format.cpp:56:21:56:24 | {...} | format.cpp:57:17:57:22 | buffer | |
23+
| format.cpp:56:21:56:24 | {...} | format.cpp:58:8:58:13 | buffer | |
24+
| format.cpp:56:23:56:23 | 0 | format.cpp:56:21:56:24 | {...} | TAINT |
25+
| format.cpp:57:17:57:22 | ref arg buffer | format.cpp:58:8:58:13 | buffer | |
26+
| format.cpp:57:30:57:43 | call to source | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
27+
| format.cpp:57:48:57:55 | Hello. | format.cpp:57:17:57:22 | ref arg buffer | TAINT |
28+
| format.cpp:61:21:61:24 | {...} | format.cpp:62:17:62:22 | buffer | |
29+
| format.cpp:61:21:61:24 | {...} | format.cpp:63:8:63:13 | buffer | |
30+
| format.cpp:61:23:61:23 | 0 | format.cpp:61:21:61:24 | {...} | TAINT |
31+
| format.cpp:62:17:62:22 | ref arg buffer | format.cpp:63:8:63:13 | buffer | |
32+
| format.cpp:62:30:62:39 | %s %s %s | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
33+
| format.cpp:62:42:62:44 | a | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
34+
| format.cpp:62:47:62:49 | b | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
35+
| format.cpp:62:52:62:65 | call to source | format.cpp:62:17:62:22 | ref arg buffer | TAINT |
36+
| format.cpp:66:21:66:24 | {...} | format.cpp:67:17:67:22 | buffer | |
37+
| format.cpp:66:21:66:24 | {...} | format.cpp:68:8:68:13 | buffer | |
38+
| format.cpp:66:23:66:23 | 0 | format.cpp:66:21:66:24 | {...} | TAINT |
39+
| format.cpp:67:17:67:22 | ref arg buffer | format.cpp:68:8:68:13 | buffer | |
40+
| format.cpp:67:30:67:35 | %.*s | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
41+
| format.cpp:67:38:67:39 | 10 | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
42+
| format.cpp:67:42:67:55 | call to source | format.cpp:67:17:67:22 | ref arg buffer | TAINT |
43+
| format.cpp:72:21:72:24 | {...} | format.cpp:73:17:73:22 | buffer | |
44+
| format.cpp:72:21:72:24 | {...} | format.cpp:74:8:74:13 | buffer | |
45+
| format.cpp:72:23:72:23 | 0 | format.cpp:72:21:72:24 | {...} | TAINT |
46+
| format.cpp:73:17:73:22 | ref arg buffer | format.cpp:74:8:74:13 | buffer | |
47+
| format.cpp:73:30:73:33 | %i | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
48+
| format.cpp:73:36:73:36 | 0 | format.cpp:73:17:73:22 | ref arg buffer | TAINT |
49+
| format.cpp:77:21:77:24 | {...} | format.cpp:78:17:78:22 | buffer | |
50+
| format.cpp:77:21:77:24 | {...} | format.cpp:79:8:79:13 | buffer | |
51+
| format.cpp:77:23:77:23 | 0 | format.cpp:77:21:77:24 | {...} | TAINT |
52+
| format.cpp:78:17:78:22 | ref arg buffer | format.cpp:79:8:79:13 | buffer | |
53+
| format.cpp:78:30:78:33 | %i | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
54+
| format.cpp:78:36:78:41 | call to source | format.cpp:78:17:78:22 | ref arg buffer | TAINT |
55+
| format.cpp:82:21:82:24 | {...} | format.cpp:83:17:83:22 | buffer | |
56+
| format.cpp:82:21:82:24 | {...} | format.cpp:84:8:84:13 | buffer | |
57+
| format.cpp:82:23:82:23 | 0 | format.cpp:82:21:82:24 | {...} | TAINT |
58+
| format.cpp:83:17:83:22 | ref arg buffer | format.cpp:84:8:84:13 | buffer | |
59+
| format.cpp:83:30:83:35 | %.*s | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
60+
| format.cpp:83:38:83:43 | call to source | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
61+
| format.cpp:83:48:83:55 | Hello. | format.cpp:83:17:83:22 | ref arg buffer | TAINT |
62+
| format.cpp:88:21:88:24 | {...} | format.cpp:89:17:89:22 | buffer | |
63+
| format.cpp:88:21:88:24 | {...} | format.cpp:90:8:90:13 | buffer | |
64+
| format.cpp:88:23:88:23 | 0 | format.cpp:88:21:88:24 | {...} | TAINT |
65+
| format.cpp:89:17:89:22 | ref arg buffer | format.cpp:90:8:90:13 | buffer | |
66+
| format.cpp:89:30:89:33 | %p | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
67+
| format.cpp:89:36:89:49 | call to source | format.cpp:89:17:89:22 | ref arg buffer | TAINT |
68+
| format.cpp:94:21:94:24 | {...} | format.cpp:95:16:95:21 | buffer | |
69+
| format.cpp:94:21:94:24 | {...} | format.cpp:96:8:96:13 | buffer | |
70+
| format.cpp:94:23:94:23 | 0 | format.cpp:94:21:94:24 | {...} | TAINT |
71+
| format.cpp:95:16:95:21 | ref arg buffer | format.cpp:96:8:96:13 | buffer | |
72+
| format.cpp:95:24:95:27 | %s | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
73+
| format.cpp:95:30:95:43 | call to source | format.cpp:95:16:95:21 | ref arg buffer | TAINT |
74+
| format.cpp:99:21:99:24 | {...} | format.cpp:100:16:100:21 | buffer | |
75+
| format.cpp:99:21:99:24 | {...} | format.cpp:101:8:101:13 | buffer | |
76+
| format.cpp:99:23:99:23 | 0 | format.cpp:99:21:99:24 | {...} | TAINT |
77+
| format.cpp:100:16:100:21 | ref arg buffer | format.cpp:101:8:101:13 | buffer | |
78+
| format.cpp:100:24:100:28 | %ls | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
79+
| format.cpp:100:31:100:45 | call to source | format.cpp:100:16:100:21 | ref arg buffer | TAINT |
80+
| format.cpp:104:25:104:28 | {...} | format.cpp:105:17:105:23 | wbuffer | |
81+
| format.cpp:104:25:104:28 | {...} | format.cpp:106:8:106:14 | wbuffer | |
82+
| format.cpp:104:27:104:27 | 0 | format.cpp:104:25:104:28 | {...} | TAINT |
83+
| format.cpp:105:17:105:23 | ref arg wbuffer | format.cpp:106:8:106:14 | wbuffer | |
84+
| format.cpp:105:31:105:35 | %s | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
85+
| format.cpp:105:38:105:52 | call to source | format.cpp:105:17:105:23 | ref arg wbuffer | TAINT |
86+
| format.cpp:109:21:109:24 | {...} | format.cpp:110:18:110:23 | buffer | |
87+
| format.cpp:109:21:109:24 | {...} | format.cpp:111:8:111:13 | buffer | |
88+
| format.cpp:109:23:109:23 | 0 | format.cpp:109:21:109:24 | {...} | TAINT |
89+
| format.cpp:110:18:110:23 | ref arg buffer | format.cpp:111:8:111:13 | buffer | |
90+
| format.cpp:115:10:115:11 | 0 | format.cpp:116:29:116:29 | i | |
91+
| format.cpp:115:10:115:11 | 0 | format.cpp:117:8:117:8 | i | |
92+
| format.cpp:116:28:116:29 | ref arg & ... | format.cpp:117:8:117:8 | i | |
93+
| format.cpp:116:29:116:29 | i | format.cpp:116:28:116:29 | & ... | |
94+
| format.cpp:120:10:120:11 | 0 | format.cpp:121:40:121:40 | i | |
95+
| format.cpp:120:10:120:11 | 0 | format.cpp:122:8:122:8 | i | |
96+
| format.cpp:121:39:121:40 | ref arg & ... | format.cpp:122:8:122:8 | i | |
97+
| format.cpp:121:40:121:40 | i | format.cpp:121:39:121:40 | & ... | |
98+
| format.cpp:125:21:125:24 | {...} | format.cpp:126:32:126:37 | buffer | |
99+
| format.cpp:125:21:125:24 | {...} | format.cpp:127:8:127:13 | buffer | |
100+
| format.cpp:125:23:125:23 | 0 | format.cpp:125:21:125:24 | {...} | TAINT |
101+
| format.cpp:126:31:126:37 | ref arg & ... | format.cpp:127:8:127:13 | buffer | |
102+
| format.cpp:126:32:126:37 | buffer | format.cpp:126:31:126:37 | & ... | |
103+
| format.cpp:130:21:130:24 | {...} | format.cpp:131:40:131:45 | buffer | |
104+
| format.cpp:130:21:130:24 | {...} | format.cpp:132:8:132:13 | buffer | |
105+
| format.cpp:130:23:130:23 | 0 | format.cpp:130:21:130:24 | {...} | TAINT |
106+
| format.cpp:131:39:131:45 | ref arg & ... | format.cpp:132:8:132:13 | buffer | |
107+
| format.cpp:131:40:131:45 | buffer | format.cpp:131:39:131:45 | & ... | |
6108
| taint.cpp:4:27:4:33 | source1 | taint.cpp:6:13:6:19 | source1 | |
7109
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:5:8:5:13 | clean1 | |
8110
| taint.cpp:4:40:4:45 | clean1 | taint.cpp:6:3:6:8 | clean1 | |

cpp/ql/test/library-tests/dataflow/taint-tests/taint.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
| format.cpp:53:8:53:13 | buffer | format.cpp:52:36:52:49 | call to source |
2+
| format.cpp:58:8:58:13 | buffer | format.cpp:57:30:57:43 | call to source |
3+
| format.cpp:63:8:63:13 | buffer | format.cpp:62:52:62:65 | call to source |
4+
| format.cpp:68:8:68:13 | buffer | format.cpp:67:42:67:55 | call to source |
5+
| format.cpp:79:8:79:13 | buffer | format.cpp:78:36:78:41 | call to source |
6+
| format.cpp:84:8:84:13 | buffer | format.cpp:83:38:83:43 | call to source |
7+
| format.cpp:90:8:90:13 | buffer | format.cpp:89:36:89:49 | call to source |
8+
| format.cpp:96:8:96:13 | buffer | format.cpp:95:30:95:43 | call to source |
9+
| format.cpp:101:8:101:13 | buffer | format.cpp:100:31:100:45 | call to source |
10+
| format.cpp:106:8:106:14 | wbuffer | format.cpp:105:38:105:52 | call to source |
111
| taint.cpp:8:8:8:13 | clean1 | taint.cpp:4:27:4:33 | source1 |
212
| taint.cpp:16:8:16:14 | source1 | taint.cpp:12:22:12:27 | call to source |
313
| taint.cpp:17:8:17:16 | ++ ... | taint.cpp:12:22:12:27 | call to source |

cpp/ql/test/library-tests/dataflow/taint-tests/test_diff.expected

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
1+
| format.cpp:53:8:53:13 | format.cpp:52:36:52:49 | AST only |
2+
| format.cpp:58:8:58:13 | format.cpp:57:30:57:43 | AST only |
3+
| format.cpp:63:8:63:13 | format.cpp:62:52:62:65 | AST only |
4+
| format.cpp:68:8:68:13 | format.cpp:67:42:67:55 | AST only |
5+
| format.cpp:79:8:79:13 | format.cpp:78:36:78:41 | AST only |
6+
| format.cpp:84:8:84:13 | format.cpp:83:38:83:43 | AST only |
7+
| format.cpp:90:8:90:13 | format.cpp:89:36:89:49 | AST only |
8+
| format.cpp:96:8:96:13 | format.cpp:95:30:95:43 | AST only |
9+
| format.cpp:101:8:101:13 | format.cpp:100:31:100:45 | AST only |
10+
| format.cpp:106:8:106:14 | format.cpp:105:38:105:52 | AST only |
111
| taint.cpp:41:7:41:13 | taint.cpp:35:12:35:17 | AST only |
212
| taint.cpp:42:7:42:13 | taint.cpp:35:12:35:17 | AST only |
313
| taint.cpp:43:7:43:13 | taint.cpp:37:22:37:27 | AST only |

cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/NoSpaceForZeroTerminator.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| test.c:32:20:32:25 | call to malloc | This allocation does not include space to null-terminate the string. |
55
| test.c:49:20:49:25 | call to malloc | This allocation does not include space to null-terminate the string. |
66
| test.cpp:24:35:24:40 | call to malloc | This allocation does not include space to null-terminate the string. |
7+
| test.cpp:45:28:45:33 | call to malloc | This allocation does not include space to null-terminate the string. |
78
| test.cpp:63:28:63:33 | call to malloc | This allocation does not include space to null-terminate the string. |
89
| test.cpp:71:28:71:33 | call to malloc | This allocation does not include space to null-terminate the string. |
910
| test.cpp:79:28:79:33 | call to malloc | This allocation does not include space to null-terminate the string. |

cpp/ql/test/query-tests/Security/CWE/CWE-131/semmle/NoSpaceForZeroTerminator/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void good1(wchar_t *wstr) {
4141
}
4242

4343
void bad3(char *str) {
44-
// BAD -- zero-termination proved by sprintf (as destination) [NOT DETECTED]
44+
// BAD -- zero-termination proved by sprintf (as destination)
4545
char *buffer = (char *)malloc(strlen(str));
4646
sprintf(buffer, "%s", str);
4747
free(buffer);

0 commit comments

Comments
 (0)