Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 45476f3

Browse files
authored
Merge pull request #739 from jbj/strcpy-fixups
C++: Clean up "Use of string copy function in a condition" query
2 parents ea018a2 + 61e23be commit 45476f3

6 files changed

Lines changed: 133 additions & 120 deletions

File tree

change-notes/1.20/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
| **Query** | **Tags** | **Purpose** |
1010
|-----------------------------|-----------|--------------------------------------------------------------------|
11+
| Use of string copy function in a condition (`cpp/string-copy-return-value-as-boolean`) | correctness | This query identifies calls to string copy functions used in conditions, where it's likely that a different function was intended to be called. |
1112
| Lossy function result cast (`cpp/lossy-function-result-cast`) | correctness | Finds function calls whose result type is a floating point type, which are implicitly cast to an integral type. Newly available but not displayed by default on LGTM. |
1213

1314
## Changes to existing queries

cpp/ql/src/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean.qhelp

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,27 @@
44
<qhelp>
55

66
<overview>
7-
<p>This rule finds uses of the string copy function calls that return the <code>destination</code> parameter,
8-
and that do not have a return value reserved to indicate an error.</p>
7+
<p>This query identifies calls to string copy functions used in conditions, either
8+
directly or as part of an equality operator or logical operator. The most
9+
common string copy functions always return their <code>destination</code>
10+
parameter and do not have a return value reserved to indicate an error.
11+
Therefore, such a function call always evaluates to true in a Boolean
12+
context.</p>
913

10-
<p>The rule flags occurrences using such string copy functions as the conditional of an <code>if</code> statement, either directly, as part of an equality operator or a logical operator.</p>
11-
12-
<p>The string copy functions that the rule takes into consideration are: </p>
14+
<p>The string copy functions that the rule takes into consideration are:</p>
1315
<ul>
14-
<li>strcpy</li>
15-
<li>wcscpy</li>
16-
<li>_mbscpy</li>
17-
<li>strncpy</li>
18-
<li>_strncpy_l</li>
19-
<li>wcsncpy</li>
20-
<li>_wcsncpy_l</li>
21-
<li>_mbsncpy</li>
22-
<li>_mbsncpy_l</li>
16+
<li><code>strcpy</code></li>
17+
<li><code>wcscpy</code></li>
18+
<li><code>_mbscpy</code></li>
19+
<li><code>strncpy</code></li>
20+
<li><code>_strncpy_l</code></li>
21+
<li><code>wcsncpy</code></li>
22+
<li><code>_wcsncpy_l</code></li>
23+
<li><code>_mbsncpy</code></li>
24+
<li><code>_mbsncpy_l</code></li>
2325
</ul>
24-
25-
<p>NOTE: It is highly recommended to consider using a more secure version of string manipulation functions suchas as <code>strcpy_s</code>.</p>
26+
27+
<p>NOTE: It is highly recommended to consider using a more secure version of string manipulation functions such as as <code>strcpy_s</code>.</p>
2628

2729
</overview>
2830
<recommendation>
@@ -35,9 +37,9 @@ and that do not have a return value reserved to indicate an error.</p>
3537
</example>
3638

3739
<references>
38-
<li>Microsoft Books on Line: <a href="https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/ccf4h9w8(v=vs.110)">C6324</a></li>
39-
<li>Microsoft Books on Line: <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strcpy-wcscpy-mbscpy?view=vs-2017">strcpy, wcscpy, _mbscpy</a></li>
40-
<li>US-CERT: <a href="https://www.us-cert.gov/bsi/articles/knowledge/coding-practices/strcpy_s-and-strcat_s">strncpy_s() and strncat_s()</a></li>
40+
<li>Microsoft Code Analysis for C/C++ Warnings: <a href="https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/ccf4h9w8(v=vs.110)">C6324</a></li>
41+
<li>Microsoft C library reference: <a href="https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/strcpy-wcscpy-mbscpy">strcpy, wcscpy, _mbscpy</a></li>
42+
<li>US-CERT: <a href="https://www.us-cert.gov/bsi/articles/knowledge/coding-practices/strcpy_s-and-strcat_s">strcpy_s() and strcat_s()</a></li>
4143

4244
</references>
4345
</qhelp>
Lines changed: 60 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,90 @@
11
/**
2-
* @name Using the return value of a strcpy or related string copy function as a boolean operator
3-
* @description The return value for strcpy, strncpy, or related string copy functions have no reserved return value to indicate an error.
4-
* Using the return values of these functions as boolean function .
5-
* Either the intent was to use a more secure version of a string copy function (such as strcpy_s), or a string compare function (such as strcmp).
2+
* @name Use of string copy function in a condition
3+
* @description The return value for strcpy, strncpy, or related string copy
4+
* functions have no reserved return value to indicate an error.
5+
* Using them in a condition is likely to be a logic error.
66
* @kind problem
77
* @problem.severity error
88
* @precision high
99
* @id cpp/string-copy-return-value-as-boolean
1010
* @tags external/microsoft/C6324
11+
* correctness
1112
*/
1213

1314
import cpp
1415
import semmle.code.cpp.dataflow.DataFlow
1516

1617
predicate isStringComparisonFunction(string functionName) {
17-
functionName = "strcpy"
18-
or functionName = "wcscpy"
19-
or functionName = "_mbscpy"
20-
or functionName = "strncpy"
21-
or functionName = "_strncpy_l"
22-
or functionName = "wcsncpy"
23-
or functionName = "_wcsncpy_l"
24-
or functionName = "_mbsncpy"
25-
or functionName = "_mbsncpy_l"
18+
functionName = "strcpy" or
19+
functionName = "wcscpy" or
20+
functionName = "_mbscpy" or
21+
functionName = "strncpy" or
22+
functionName = "_strncpy_l" or
23+
functionName = "wcsncpy" or
24+
functionName = "_wcsncpy_l" or
25+
functionName = "_mbsncpy" or
26+
functionName = "_mbsncpy_l"
2627
}
2728

28-
predicate isBoolean( Expr e1 )
29-
{
30-
exists ( Type t1 |
29+
predicate isBoolean(Expr e1) {
30+
exists(Type t1 |
3131
t1 = e1.getType() and
3232
(t1.hasName("bool") or t1.hasName("BOOL") or t1.hasName("_Bool"))
3333
)
3434
}
3535

36-
predicate isStringCopyCastedAsBoolean( FunctionCall func, Expr expr1, string msg ) {
37-
DataFlow::localFlow(DataFlow::exprNode(func), DataFlow::exprNode(expr1))
38-
and isBoolean( expr1.getConversion*())
39-
and isStringComparisonFunction( func.getTarget().getQualifiedName())
40-
and msg = "Return Value of " + func.getTarget().getQualifiedName() + " used as boolean."
36+
predicate isStringCopyCastedAsBoolean(FunctionCall func, Expr expr1, string msg) {
37+
DataFlow::localFlow(DataFlow::exprNode(func), DataFlow::exprNode(expr1)) and
38+
isBoolean(expr1.getConversion*()) and
39+
isStringComparisonFunction(func.getTarget().getName()) and
40+
msg = "Return value of " + func.getTarget().getName() + " used as a Boolean."
4141
}
4242

43-
predicate isStringCopyUsedInLogicalOperationOrCondition( FunctionCall func, Expr expr1, string msg ) {
44-
isStringComparisonFunction( func.getTarget().getQualifiedName() )
45-
and (((
46-
// it is being used in an equality or logical operation
47-
exists( EqualityOperation eop |
48-
eop = expr1
49-
and func = eop.getAChild()
43+
predicate isStringCopyUsedInLogicalOperationOrCondition(FunctionCall func, Expr expr1, string msg) {
44+
isStringComparisonFunction(func.getTarget().getName()) and
45+
(
46+
(
47+
// it is being used in an equality or logical operation
48+
exists(EqualityOperation eop |
49+
eop = expr1 and
50+
func = eop.getAnOperand()
5051
)
51-
or exists( UnaryLogicalOperation ule |
52-
expr1 = ule
53-
and func = ule.getAChild()
52+
or
53+
exists(UnaryLogicalOperation ule |
54+
expr1 = ule and
55+
func = ule.getOperand()
5456
)
55-
or exists( BinaryLogicalOperation ble |
56-
expr1 = ble
57-
and func = ble.getAChild()
57+
or
58+
exists(BinaryLogicalOperation ble |
59+
expr1 = ble and
60+
func = ble.getAnOperand()
5861
)
59-
)
60-
and msg = "Return Value of " + func.getTarget().getQualifiedName() + " used in a logical operation."
61-
)
62+
) and
63+
msg = "Return value of " + func.getTarget().getName() + " used in a logical operation."
6264
or
63-
exists( ConditionalStmt condstmt |
64-
condstmt.getAChild() = expr1 |
65-
// or the string copy function is used directly as the conditional expression
66-
func = condstmt.getChild(0)
67-
and msg = "Return Value of " + func.getTarget().getQualifiedName() + " used directly in a conditional expression."
68-
))
65+
// or the string copy function is used directly as the conditional expression
66+
(
67+
exists(ConditionalStmt condstmt |
68+
func = condstmt.getControllingExpr() and
69+
expr1 = func
70+
)
71+
or
72+
exists(ConditionalExpr ce |
73+
expr1 = ce and
74+
func = ce.getCondition()
75+
)
76+
) and
77+
msg = "Return value of " + func.getTarget().getName() +
78+
" used directly in a conditional expression."
79+
)
6980
}
7081

7182
from FunctionCall func, Expr expr1, string msg
72-
where
73-
( isStringCopyCastedAsBoolean(func, expr1, msg) and
74-
not isStringCopyUsedInLogicalOperationOrCondition(func, expr1, _)
83+
where
84+
(
85+
isStringCopyCastedAsBoolean(func, expr1, msg) and
86+
not isStringCopyUsedInLogicalOperationOrCondition(func, _, _)
7587
)
76-
or isStringCopyUsedInLogicalOperationOrCondition(func, expr1, msg)
88+
or
89+
isStringCopyUsedInLogicalOperationOrCondition(func, expr1, msg)
7790
select expr1, msg
Lines changed: 31 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,31 @@
1-
| test.c:34:9:34:14 | call to strcpy | Return Value of strcpy used directly in a conditional expression. |
2-
| test.c:38:9:38:31 | ! ... | Return Value of strcpy used in a logical operation. |
3-
| test.c:42:9:42:35 | ... == ... | Return Value of strcpy used in a logical operation. |
4-
| test.c:46:9:46:48 | ... && ... | Return Value of strcpy used in a logical operation. |
5-
| test.c:50:9:50:15 | call to strncpy | Return Value of strncpy used directly in a conditional expression. |
6-
| test.c:54:6:54:34 | ! ... | Return Value of strncpy used in a logical operation. |
7-
| test.c:58:11:58:39 | ! ... | Return Value of strncpy used in a logical operation. |
8-
| test.c:60:11:60:37 | ... && ... | Return Value of strcpy used in a logical operation. |
9-
| test.c:62:11:62:37 | ... == ... | Return Value of strcpy used in a logical operation. |
10-
| test.c:64:11:64:37 | ... != ... | Return Value of strcpy used in a logical operation. |
11-
| test.cpp:75:9:75:14 | call to strcpy | Return Value of strcpy used directly in a conditional expression. |
12-
| test.cpp:79:9:79:31 | ! ... | Return Value of strcpy used in a logical operation. |
13-
| test.cpp:79:10:79:15 | call to strcpy | Return Value of strcpy used as boolean. |
14-
| test.cpp:83:9:83:35 | ... == ... | Return Value of strcpy used in a logical operation. |
15-
| test.cpp:87:9:87:48 | ... && ... | Return Value of strcpy used in a logical operation. |
16-
| test.cpp:87:27:87:32 | call to strcpy | Return Value of strcpy used as boolean. |
17-
| test.cpp:91:9:91:37 | call to wcscpy | Return Value of wcscpy used directly in a conditional expression. |
18-
| test.cpp:95:9:95:14 | call to wcscpy | Return Value of wcscpy used directly in a conditional expression. |
19-
| test.cpp:99:9:99:15 | call to _mbscpy | Return Value of _mbscpy used directly in a conditional expression. |
20-
| test.cpp:103:9:103:15 | call to strncpy | Return Value of strncpy used directly in a conditional expression. |
21-
| test.cpp:107:9:107:15 | call to wcsncpy | Return Value of wcsncpy used directly in a conditional expression. |
22-
| test.cpp:111:9:111:16 | call to _mbsncpy | Return Value of _mbsncpy used directly in a conditional expression. |
23-
| test.cpp:115:9:115:18 | call to _strncpy_l | Return Value of _strncpy_l used directly in a conditional expression. |
24-
| test.cpp:119:9:119:18 | call to _wcsncpy_l | Return Value of _wcsncpy_l used directly in a conditional expression. |
25-
| test.cpp:123:9:123:18 | call to _mbsncpy_l | Return Value of _mbsncpy_l used directly in a conditional expression. |
26-
| test.cpp:127:6:127:34 | ! ... | Return Value of strncpy used in a logical operation. |
27-
| test.cpp:127:7:127:13 | call to strncpy | Return Value of strncpy used as boolean. |
28-
| test.cpp:131:11:131:17 | call to strncpy | Return Value of strncpy used as boolean. |
29-
| test.cpp:133:16:133:44 | ! ... | Return Value of strncpy used in a logical operation. |
30-
| test.cpp:133:17:133:23 | call to strncpy | Return Value of strncpy used as boolean. |
31-
| test.cpp:135:11:135:16 | call to strcpy | Return Value of strcpy used as boolean. |
32-
| test.cpp:135:11:135:37 | ... && ... | Return Value of strcpy used in a logical operation. |
33-
| test.cpp:137:11:137:37 | ... == ... | Return Value of strcpy used in a logical operation. |
34-
| test.cpp:139:11:139:37 | ... != ... | Return Value of strcpy used in a logical operation. |
1+
| test.c:34:9:34:14 | call to strcpy | Return value of strcpy used directly in a conditional expression. |
2+
| test.c:38:9:38:31 | ! ... | Return value of strcpy used in a logical operation. |
3+
| test.c:42:9:42:35 | ... == ... | Return value of strcpy used in a logical operation. |
4+
| test.c:46:9:46:48 | ... && ... | Return value of strcpy used in a logical operation. |
5+
| test.c:50:9:50:15 | call to strncpy | Return value of strncpy used directly in a conditional expression. |
6+
| test.c:54:9:54:37 | ! ... | Return value of strncpy used in a logical operation. |
7+
| test.c:58:14:58:42 | ! ... | Return value of strncpy used in a logical operation. |
8+
| test.c:59:14:59:43 | ... ? ... : ... | Return value of strcpy used directly in a conditional expression. |
9+
| test.c:60:14:60:40 | ... && ... | Return value of strcpy used in a logical operation. |
10+
| test.c:62:14:62:40 | ... == ... | Return value of strcpy used in a logical operation. |
11+
| test.c:64:14:64:40 | ... != ... | Return value of strcpy used in a logical operation. |
12+
| test.cpp:75:9:75:14 | call to strcpy | Return value of strcpy used directly in a conditional expression. |
13+
| test.cpp:79:9:79:31 | ! ... | Return value of strcpy used in a logical operation. |
14+
| test.cpp:83:9:83:35 | ... == ... | Return value of strcpy used in a logical operation. |
15+
| test.cpp:87:9:87:48 | ... && ... | Return value of strcpy used in a logical operation. |
16+
| test.cpp:91:9:91:37 | call to wcscpy | Return value of wcscpy used directly in a conditional expression. |
17+
| test.cpp:95:9:95:14 | call to wcscpy | Return value of wcscpy used directly in a conditional expression. |
18+
| test.cpp:99:9:99:15 | call to _mbscpy | Return value of _mbscpy used directly in a conditional expression. |
19+
| test.cpp:103:9:103:15 | call to strncpy | Return value of strncpy used directly in a conditional expression. |
20+
| test.cpp:107:9:107:15 | call to wcsncpy | Return value of wcsncpy used directly in a conditional expression. |
21+
| test.cpp:111:9:111:16 | call to _mbsncpy | Return value of _mbsncpy used directly in a conditional expression. |
22+
| test.cpp:115:9:115:18 | call to _strncpy_l | Return value of _strncpy_l used directly in a conditional expression. |
23+
| test.cpp:119:9:119:18 | call to _wcsncpy_l | Return value of _wcsncpy_l used directly in a conditional expression. |
24+
| test.cpp:123:9:123:18 | call to _mbsncpy_l | Return value of _mbsncpy_l used directly in a conditional expression. |
25+
| test.cpp:127:9:127:37 | ! ... | Return value of strncpy used in a logical operation. |
26+
| test.cpp:131:14:131:20 | call to strncpy | Return value of strncpy used as a Boolean. |
27+
| test.cpp:133:19:133:47 | ! ... | Return value of strncpy used in a logical operation. |
28+
| test.cpp:134:14:134:43 | ... ? ... : ... | Return value of strcpy used directly in a conditional expression. |
29+
| test.cpp:135:14:135:40 | ... && ... | Return value of strcpy used in a logical operation. |
30+
| test.cpp:137:14:137:40 | ... == ... | Return value of strcpy used in a logical operation. |
31+
| test.cpp:139:14:139:40 | ... != ... | Return value of strcpy used in a logical operation. |

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ void PositiveCases()
2929
{
3030
char szbuf1[100];
3131
char szbuf2[100];
32-
int result;
32+
int result;
3333

3434
if (strcpy(szbuf1, "test")) // Bug, direct usage
3535
{
@@ -51,17 +51,17 @@ void PositiveCases()
5151
{
5252
}
5353

54-
if (!strncpy(szbuf1, "test", 100)) // Bug
55-
{
56-
}
57-
58-
result = !strncpy(szbuf1, "test", 100);
54+
if (!strncpy(szbuf1, "test", 100)) // Bug
55+
{
56+
}
5957

60-
result = strcpy(szbuf1, "test") && 1;
58+
result = !strncpy(szbuf1, "test", 100); // Bug
59+
result = strcpy(szbuf1, "test") ? 1 : 0; // Bug
60+
result = strcpy(szbuf1, "test") && 1; // Bug
6161

62-
result = strcpy(szbuf1, "test") == 0;
62+
result = strcpy(szbuf1, "test") == 0; // Bug
6363

64-
result = strcpy(szbuf1, "test") != 0;
64+
result = strcpy(szbuf1, "test") != 0; // Bug
6565
}
6666

6767
void NegativeCases()
@@ -80,4 +80,4 @@ void NegativeCases()
8080
{
8181
}
8282

83-
}
83+
}

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/UsingStrcpyAsBoolean/test.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,19 +124,19 @@ void PositiveCases()
124124
{
125125
}
126126

127-
if (!strncpy(szbuf1, "test", 100)) // Bug
128-
{
129-
}
130-
131-
bool b = strncpy(szbuf1, "test", 100);
127+
if (!strncpy(szbuf1, "test", 100)) // Bug
128+
{
129+
}
132130

133-
bool result = !strncpy(szbuf1, "test", 100);
131+
bool b = strncpy(szbuf1, "test", 100); // Bug
134132

135-
result = strcpy(szbuf1, "test") && 1;
133+
bool result = !strncpy(szbuf1, "test", 100); // Bug
134+
result = strcpy(szbuf1, "test") ? 1 : 0; // Bug
135+
result = strcpy(szbuf1, "test") && 1; // Bug
136136

137-
result = strcpy(szbuf1, "test") == 0;
137+
result = strcpy(szbuf1, "test") == 0; // Bug
138138

139-
result = strcpy(szbuf1, "test") != 0;
139+
result = strcpy(szbuf1, "test") != 0; // Bug
140140

141141
}
142142

@@ -160,4 +160,4 @@ void NegativeCases()
160160
{
161161
}
162162

163-
}
163+
}

0 commit comments

Comments
 (0)