13
13
import cpp
14
14
import codingstandards.c.cert
15
15
import codingstandards.c.Errno
16
+ import semmle.code.cpp.controlflow.Guards
16
17
17
18
class SignalCall extends FunctionCall {
18
19
SignalCall ( ) { this .getTarget ( ) .hasGlobalName ( "signal" ) }
19
20
}
20
21
21
22
/**
22
- * Models signal handlers that call signal()
23
+ * A check on `signal` call return value
24
+ * `if (signal(SIGINT, handler) == SIG_ERR)`
25
+ */
26
+ class SignalCheckOperation extends EqualityOperation , GuardCondition {
27
+ ControlFlowNode errorSuccessor ;
28
+
29
+ SignalCheckOperation ( ) {
30
+ this .getAnOperand ( ) = any ( MacroInvocation m | m .getMacroName ( ) = "SIG_ERR" ) .getExpr ( ) and
31
+ (
32
+ this .getOperator ( ) = "==" and
33
+ this .controls ( errorSuccessor , true )
34
+ or
35
+ this .getOperator ( ) = "!=" and
36
+ this .controls ( errorSuccessor , false )
37
+ )
38
+ }
39
+
40
+ ControlFlowNode getErrorSuccessor ( ) { result = errorSuccessor }
41
+ }
42
+
43
+ /**
44
+ * Models signal handlers that call signal() and return
23
45
*/
24
46
class SignalCallingHandler extends Function {
25
47
SignalCall sh ;
26
48
27
49
SignalCallingHandler ( ) {
28
50
// is a signal handler
29
51
this = sh .getArgument ( 1 ) .( FunctionAccess ) .getTarget ( ) and
30
- // calls signal()
31
- this .calls * ( any ( SignalCall c ) .getTarget ( ) )
52
+ // calls signal() on the handled signal
53
+ exists ( SignalCall sCall |
54
+ sCall .getEnclosingFunction ( ) = this and
55
+ DataFlow:: localFlow ( DataFlow:: parameterNode ( this .getParameter ( 0 ) ) ,
56
+ DataFlow:: exprNode ( sCall .getArgument ( 0 ) ) ) and
57
+ // does not abort on error
58
+ not exists ( SignalCheckOperation sCheck , FunctionCall abort |
59
+ DataFlow:: localExprFlow ( sCall , sCheck .getAnOperand ( ) ) and
60
+ abort .getTarget ( ) .hasGlobalName ( [ "abort" , "_Exit" ] ) and
61
+ abort .getEnclosingElement * ( ) = sCheck .getErrorSuccessor ( )
62
+ )
63
+ )
32
64
}
33
65
34
66
SignalCall getHandler ( ) { result = sh }
@@ -37,14 +69,12 @@ class SignalCallingHandler extends Function {
37
69
from ErrnoRead errno , SignalCall h
38
70
where
39
71
not isExcluded ( errno , Contracts5Package:: doNotRelyOnIndeterminateValuesOfErrnoQuery ( ) ) and
40
- // errno read in the handler
41
- exists ( SignalCallingHandler sc |
72
+ exists ( SignalCallingHandler sc | sc .getHandler ( ) = h |
73
+ // errno read in the handler
74
+ sc .calls * ( errno .getEnclosingFunction ( ) )
75
+ or
76
+ // errno is read after the handle returns
42
77
sc .getHandler ( ) = h and
43
- (
44
- sc .calls * ( errno .getEnclosingFunction ( ) )
45
- or
46
- // errno is read after the handle
47
- errno .( ControlFlowNode ) .getAPredecessor + ( ) = sc .getHandler ( )
48
- )
78
+ errno .getAPredecessor + ( ) = h
49
79
)
50
80
select errno , "`errno` has indeterminate value after this $@." , h , h .toString ( )
0 commit comments