1313import cpp
1414import codingstandards.c.cert
1515import codingstandards.c.Errno
16+ import semmle.code.cpp.controlflow.Guards
1617
1718class SignalCall extends FunctionCall {
1819 SignalCall ( ) { this .getTarget ( ) .hasGlobalName ( "signal" ) }
1920}
2021
2122/**
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
2345 */
2446class SignalCallingHandler extends Function {
2547 SignalCall sh ;
2648
2749 SignalCallingHandler ( ) {
2850 // is a signal handler
2951 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+ )
3264 }
3365
3466 SignalCall getHandler ( ) { result = sh }
@@ -37,14 +69,12 @@ class SignalCallingHandler extends Function {
3769from ErrnoRead errno , SignalCall h
3870where
3971 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
4277 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
4979 )
5080select errno , "`errno` has indeterminate value after this $@." , h , h .toString ( )
0 commit comments