Skip to content

Commit b393c6a

Browse files
authored
Add files via upload
1 parent a67db45 commit b393c6a

File tree

3 files changed

+176
-0
lines changed

3 files changed

+176
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
...
2+
int myFclose(FILE * fmy)
3+
{
4+
if(!fclose(fmy)) {
5+
fmy = NULL;
6+
return 0;
7+
}
8+
return -1;
9+
}
10+
...
11+
fe = fopen("myFile.txt", "wt");
12+
...
13+
fclose(fe); // BAD
14+
...
15+
fe = fopen("myFile.txt", "wt");
16+
...
17+
myFclose(fe); // GOOD
18+
...
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>Finding for function calls for which wrapper functions exist.</p>
7+
8+
</overview>
9+
10+
<example>
11+
<p>The following example demonstrates fallacious and fixed methods of using wrapper functions.</p>
12+
<sample src="FindWrapperFunctions.cpp" />
13+
14+
</example>
15+
<references>
16+
17+
</references>
18+
</qhelp>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/**
2+
* @name Find Wrapper Functions
3+
* @description --Finding for function calls for which wrapper functions exist.
4+
* @kind problem
5+
* @id cpp/find-wrapper-functions
6+
* @problem.severity warning
7+
* @precision medium
8+
* @tags correctness
9+
* security
10+
* external/cwe/cwe-1041
11+
*/
12+
13+
import cpp
14+
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
15+
import semmle.code.cpp.commons.Assertions
16+
17+
/**
18+
* A function call that is used in error situations (logging, throwing an exception, abnormal termination).
19+
*/
20+
class CallUsedToHandleErrors extends FunctionCall {
21+
CallUsedToHandleErrors() {
22+
// call that is known to not return
23+
not exists(this.(ControlFlowNode).getASuccessor())
24+
or
25+
// call throwing an exception
26+
exists(ThrowExpr tex | tex = this.(ControlFlowNode).getASuccessor())
27+
or
28+
// call logging a message, possibly an error
29+
exists(FormattingFunction ff | ff = this.(ControlFlowNode).getASuccessor())
30+
or
31+
// enabling recursive search
32+
exists(CallUsedToHandleErrors fr | getTarget() = fr.getEnclosingFunction())
33+
}
34+
}
35+
36+
/** Holds if the conditions for a call outside the wrapper function are met. */
37+
predicate conditionsOutsideWrapper(FunctionCall fcp) {
38+
fcp.getNumberOfArguments() > 0 and
39+
not exists(ConditionalStmt cdtmp | fcp.getEnclosingStmt().getParentStmt*() = cdtmp) and
40+
not exists(Loop lptmp | fcp.getEnclosingStmt().getParentStmt*() = lptmp) and
41+
not exists(ReturnStmt rttmp | fcp.getEnclosingStmt().getParentStmt*() = rttmp) and
42+
not exists(FunctionCall fctmp2 | fcp = fctmp2.getAnArgument().getAChild*()) and
43+
not exists(Assignment astmp | fcp = astmp.getRValue().getAChild*()) and
44+
not exists(Initializer intmp | fcp = intmp.getExpr().getAChild*()) and
45+
not exists(Assertion astmp | fcp = astmp.getAsserted().getAChild*()) and
46+
not exists(Operation optmp | fcp = optmp.getAChild*()) and
47+
not exists(ArrayExpr aetmp | fcp = aetmp.getAChild*()) and
48+
not exists(ExprCall ectmp | fcp = ectmp.getAnArgument().getAChild*())
49+
}
50+
51+
/** Holds if the conditions for a call within the wrapper function are met. */
52+
pragma[inline]
53+
predicate conditionsInsideWrapper(FunctionCall fcp, Function fnp) {
54+
not exists(FunctionCall fctmp2 |
55+
fctmp2.getEnclosingFunction() = fnp and fcp = fctmp2.getAnArgument().getAChild*()
56+
) and
57+
not fcp instanceof CallUsedToHandleErrors and
58+
not fcp.getAnArgument().isConstant() and
59+
fcp.getEnclosingFunction() = fnp and
60+
fnp.getNumberOfParameters() > 0 and
61+
// the call arguments must be passed through the arguments of the wrapper function
62+
forall(int i | i in [0 .. fcp.getNumberOfArguments() - 1] |
63+
fcp.getArgument(i).(VariableAccess).getTarget() = fnp.getAParameter().getAnAccess().getTarget()
64+
) and
65+
// there should be no more than one required call inside the wrapper function
66+
not exists(FunctionCall fctmp |
67+
fctmp.getTarget() = fcp.getTarget() and
68+
fctmp.getFile() = fcp.getFile() and
69+
fctmp != fcp and
70+
fctmp.getEnclosingFunction() = fnp
71+
) and
72+
// inside the wrapper function there should be no calls without paths to the desired function
73+
not exists(FunctionCall fctmp |
74+
fctmp.getEnclosingFunction() = fnp and
75+
fctmp.getFile() = fcp.getFile() and
76+
fctmp != fcp and
77+
(
78+
fctmp = fcp.getAPredecessor+()
79+
or
80+
not exists(FunctionCall fctmp1 |
81+
fctmp1 = fcp and
82+
(
83+
fctmp.getASuccessor+() = fctmp1 or
84+
fctmp.getAPredecessor+() = fctmp1
85+
)
86+
)
87+
)
88+
)
89+
}
90+
91+
/** Holds if the conditions for the wrapper function are met. */
92+
pragma[inline]
93+
predicate conditionsForWrapper(FunctionCall fcp, Function fnp) {
94+
not exists(ExprCall ectmp | fnp = ectmp.getEnclosingFunction()) and
95+
not exists(Loop lp | lp.getEnclosingFunction() = fnp) and
96+
not exists(SwitchStmt sw | sw.getEnclosingFunction() = fnp) and
97+
not fnp instanceof Operator and
98+
// inside the wrapper function there should be checks of arguments or the result,
99+
// perhaps by means of passing the latter as an argument to some function
100+
(
101+
exists(IfStmt ifs |
102+
ifs.getEnclosingFunction() = fnp and
103+
(
104+
globalValueNumber(ifs.getCondition().getAChild*()) = globalValueNumber(fcp.getAnArgument()) and
105+
ifs.getASuccessor*() = fcp
106+
or
107+
ifs.getCondition().getAChild() = fcp
108+
)
109+
)
110+
or
111+
exists(FunctionCall fctmp |
112+
fctmp.getEnclosingFunction() = fnp and
113+
globalValueNumber(fctmp.getAnArgument().getAChild*()) = globalValueNumber(fcp)
114+
)
115+
) and
116+
// inside the wrapper function there must be a function call to handle the error
117+
exists(CallUsedToHandleErrors fctmp |
118+
fctmp.getEnclosingFunction() = fnp and
119+
forall(int i | i in [0 .. fnp.getNumberOfParameters() - 1] |
120+
fnp.getParameter(i).getAnAccess().getTarget() =
121+
fcp.getAnArgument().(VariableAccess).getTarget() or
122+
fnp.getParameter(i).getType() instanceof Class or
123+
fnp.getParameter(i).getType().(ReferenceType).getBaseType() instanceof Class or
124+
fnp.getParameter(i).getAnAccess().getTarget() =
125+
fctmp.getAnArgument().(VariableAccess).getTarget()
126+
)
127+
)
128+
}
129+
130+
from FunctionCall fc, Function fn
131+
where
132+
exists(FunctionCall fctmp |
133+
conditionsInsideWrapper(fctmp, fn) and
134+
conditionsForWrapper(fctmp, fn) and
135+
conditionsOutsideWrapper(fc) and
136+
fctmp.getTarget() = fc.getTarget() and
137+
fc.getEnclosingFunction() != fn and
138+
fc.getEnclosingFunction().getMetrics().getNumberOfCalls() > fn.getMetrics().getNumberOfCalls()
139+
)
140+
select fc, "consider changing the call to $@", fn, fn.getName()

0 commit comments

Comments
 (0)