Skip to content

Commit f9a2c5e

Browse files
authored
Package Contracts4
* Rule ERR30-C
1 parent d734833 commit f9a2c5e

25 files changed

+1625
-39
lines changed

c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.md

Lines changed: 263 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* @id c/cert/errno-not-set-to-zero
3+
* @name ERR30-C: Errno is not set to zero prior to an errno-setting call
4+
* @description Set errno to zero prior to each call to an errno-setting function. Failing to do so
5+
* might end in spurious errno values.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/err30-c
10+
* correctness
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.c.Errno
17+
18+
/**
19+
* CFG nodes preceding a `ErrnoSettingFunctionCall`
20+
*/
21+
ControlFlowNode notZeroedPriorToErrnoSet(InBandErrnoSettingFunctionCall fc) {
22+
result = fc
23+
or
24+
exists(ControlFlowNode mid |
25+
result = mid.getAPredecessor() and
26+
mid = notZeroedPriorToErrnoSet(fc) and
27+
// stop recursion when `errno` is set to zero
28+
not result instanceof ErrnoZeroed and
29+
not result = any(ErrnoGuard g).getZeroedSuccessor()
30+
)
31+
}
32+
33+
from InBandErrnoSettingFunctionCall fc, ControlFlowNode cause
34+
where
35+
not isExcluded(cause, Contracts4Package::errnoNotSetToZeroQuery()) and
36+
cause = notZeroedPriorToErrnoSet(fc) and
37+
(
38+
// `errno` is not reset anywhere in the function
39+
cause = fc.getEnclosingFunction().getBlock()
40+
or
41+
// `errno` is not reset after a call to an errno-setting function
42+
cause = any(InBandErrnoSettingFunctionCall ec | ec != fc)
43+
or
44+
// `errno` is not reset after a call to a function
45+
cause = any(FunctionCall fc2 | fc2 != fc)
46+
or
47+
// `errno` value is known to be != 0
48+
cause = any(ErrnoGuard g).getNonZeroedSuccessor()
49+
)
50+
select fc, "The value of `errno` may be different than `0` when this function is called."

c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.md

Lines changed: 263 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @id c/cert/errno-read-before-return
3+
* @name ERR30-C: Do not check errno before the function return value
4+
* @description Do not check errno before the function return value. Failing to do so might
5+
* invalidate the error detection.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/err30-c
10+
* correctness
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.c.Errno
17+
18+
/**
19+
* A call to an `OutOfBandErrnoSettingFunction`
20+
*/
21+
class OutOfBandErrnoSettingFunctionCertCall extends FunctionCall {
22+
OutOfBandErrnoSettingFunctionCertCall() {
23+
this.getTarget() instanceof OutOfBandErrnoSettingFunctionCert
24+
}
25+
}
26+
27+
/**
28+
* A successor of an ErrnoSettingFunctionCertCall appearing
29+
* before a check of the return value
30+
*/
31+
ControlFlowNode returnNotCheckedAfter(OutOfBandErrnoSettingFunctionCertCall errnoSet) {
32+
result = errnoSet
33+
or
34+
exists(ControlFlowNode mid |
35+
result = mid.getASuccessor() and
36+
mid = returnNotCheckedAfter(errnoSet) and
37+
// stop recursion on a return value check
38+
not (
39+
any(ControlStructure cs).getControllingExpr() = result and
40+
DataFlow::localExprFlow(errnoSet, result.(Operation).getAnOperand*())
41+
) and
42+
// stop recursion on a following errno setting function call
43+
not result instanceof OutOfBandErrnoSettingFunctionCertCall
44+
)
45+
}
46+
47+
from OutOfBandErrnoSettingFunctionCertCall errnoSet, ErrnoRead check
48+
where
49+
not isExcluded(check, Contracts4Package::errnoReadBeforeReturnQuery()) and
50+
check = returnNotCheckedAfter(errnoSet)
51+
select check, "Do not read `errno` before checking the return value of function $@.", errnoSet,
52+
errnoSet.toString()

c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.md

Lines changed: 263 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @id c/cert/function-call-before-errno-check
3+
* @name ERR30-C: Do not call a function before checking errno
4+
* @description After calling an errno-setting function, check errno before calling any other
5+
* function. Failing to do so might end in errno being overwritten.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/err30-c
10+
* correctness
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import codingstandards.c.Errno
17+
import semmle.code.cpp.dataflow.DataFlow
18+
19+
/**
20+
* A call to an `OutOfBandErrnoSettingFunction`
21+
*/
22+
class ErrnoSettingFunctionCall extends FunctionCall {
23+
ErrnoSettingFunctionCall() { this.getTarget() instanceof InBandErrnoSettingFunction }
24+
}
25+
26+
class ErrnoCheck extends Expr {
27+
ErrnoCheck() {
28+
this = any(MacroInvocation ma | ma.getMacroName() = "errno").getAnExpandedElement()
29+
or
30+
this.(FunctionCall).getTarget().hasName(["perror", "strerror"])
31+
}
32+
}
33+
34+
/**
35+
* A successor of an ErrnoSettingFunctionCall appearing
36+
* before a check of errno
37+
*/
38+
ControlFlowNode errnoNotCheckedAfter(ErrnoSettingFunctionCall errnoSet) {
39+
result = errnoSet
40+
or
41+
exists(ControlFlowNode mid |
42+
result = mid.getASuccessor() and
43+
mid = errnoNotCheckedAfter(errnoSet) and
44+
// stop recursion on an error check
45+
not result instanceof ErrnoCheck
46+
)
47+
}
48+
49+
from ErrnoSettingFunctionCall errnoSet, FunctionCall fc
50+
where
51+
not isExcluded(fc, Contracts4Package::functionCallBeforeErrnoCheckQuery()) and
52+
fc != errnoSet and
53+
fc = errnoNotCheckedAfter(errnoSet)
54+
select errnoSet,
55+
"The value of `errno` is not checked after this call to `" + errnoSet.getTarget().getName() + "`."

0 commit comments

Comments
 (0)