|
1 | 1 | /** |
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. |
6 | 6 | * @kind problem |
7 | 7 | * @problem.severity error |
8 | 8 | * @precision high |
9 | 9 | * @id cpp/string-copy-return-value-as-boolean |
10 | 10 | * @tags external/microsoft/C6324 |
| 11 | + * correctness |
11 | 12 | */ |
12 | 13 |
|
13 | 14 | import cpp |
14 | 15 | import semmle.code.cpp.dataflow.DataFlow |
15 | 16 |
|
16 | 17 | 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" |
26 | 27 | } |
27 | 28 |
|
28 | | -predicate isBoolean( Expr e1 ) |
29 | | -{ |
30 | | - exists ( Type t1 | |
| 29 | +predicate isBoolean(Expr e1) { |
| 30 | + exists(Type t1 | |
31 | 31 | t1 = e1.getType() and |
32 | 32 | (t1.hasName("bool") or t1.hasName("BOOL") or t1.hasName("_Bool")) |
33 | 33 | ) |
34 | 34 | } |
35 | 35 |
|
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." |
41 | 41 | } |
42 | 42 |
|
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() |
50 | 51 | ) |
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() |
54 | 56 | ) |
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() |
58 | 61 | ) |
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." |
62 | 64 | 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 | + ) |
69 | 80 | } |
70 | 81 |
|
71 | 82 | 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, _, _) |
75 | 87 | ) |
76 | | - or isStringCopyUsedInLogicalOperationOrCondition(func, expr1, msg) |
| 88 | + or |
| 89 | + isStringCopyUsedInLogicalOperationOrCondition(func, expr1, msg) |
77 | 90 | select expr1, msg |
0 commit comments