Skip to content

Commit 0aad1c6

Browse files
committed
Model getchar, Finalize query
1 parent 9c1b343 commit 0aad1c6

File tree

3 files changed

+22
-31
lines changed

3 files changed

+22
-31
lines changed

c/misra/src/rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,22 @@ import codingstandards.c.misra
1515
import codingstandards.cpp.ReadErrorsAndEOF
1616
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
1717

18-
//import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
1918
class CtypeFunction extends Function {
2019
CtypeFunction() { this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "ctype.h" }
2120
}
2221

23-
/* TODO Under construction */
2422
from FunctionCall ctypeCall
2523
where
2624
not isExcluded(ctypeCall,
27-
StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery())
28-
// and
29-
// not exists(CtypeFunction ctype, Expr ctypeCallArgument |
30-
// ctype = ctypeCall.getTarget() and
31-
// ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted()
32-
// |
33-
// /* Case 1: The argument's value should be in the `unsigned char` range. */
34-
// // Use `.getExplicitlyConverted` to consider inline argument casts.
35-
// -1 <= lowerBound(ctypeCallArgument) and
36-
// upperBound(ctypeCallArgument) <= 255
37-
// or
38-
// /* Case 2: EOF flows to this argument without modifications. */
39-
// exists(EOFInvocation eof |
40-
// DataFlow::localFlow(DataFlow::exprNode(eof.getExpr()), DataFlow::exprNode(ctypeCallArgument))
41-
// )
42-
// )
43-
select ctypeCall.getAnArgument(), lowerBound(ctypeCall.getAnArgument()),
44-
upperBound(ctypeCall.getAnArgument())
45-
// select ctypeCall,
46-
// "The <ctype.h> function " + ctypeCall + " accepts an argument " +
47-
// ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF."
25+
StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and
26+
not exists(CtypeFunction ctype, Expr ctypeCallArgument |
27+
ctype = ctypeCall.getTarget() and
28+
ctypeCallArgument = ctypeCall.getAnArgument().getExplicitlyConverted()
29+
|
30+
/* The argument's value should be in the EOF + `unsigned char` range. */
31+
-1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255
32+
) and
33+
ctypeCall.getBasicBlock().isReachable()
34+
select ctypeCall,
35+
"The <ctype.h> function " + ctypeCall + " accepts an argument " +
36+
ctypeCall.getAnArgument().toString() + " that is not an unsigned char nor an EOF."

c/misra/test/rules/RULE-21-13/test.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,35 @@ void sample() {
55
unsigned char c1 = 'c';
66
int r1 = isalnum(
77
c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255]
8-
int r2 = isdigit(EOF); // COMPLIANT: EOF (-1)
8+
int r2 = isalnum(EOF); // COMPLIANT: EOF (-1)
99

1010
int x3 = 256;
1111
int x4 = x3;
1212
int c3 = x4;
1313
int r3 =
14-
islower(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
14+
isalnum(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
1515

1616
unsigned char x5 = EOF;
1717
unsigned char x6 = x5;
1818
int c4 = x6 + 10000;
1919
int r4 =
20-
isdigit(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
20+
isalnum(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
2121

2222
int c5 = getchar();
23-
int r5 = isdigit(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like
23+
int r5 = isalnum(c5); // COMPLIANT[FALSE_POSITIVE]: library functions like
2424
// getchar needs to be modelled
2525

26-
unsigned char x7 = 1;
27-
char c6;
26+
unsigned char x7;
27+
int c6;
2828
if (x7 == 1) {
2929
c6 = EOF;
3030
} else {
3131
c6 = 'c';
3232
}
3333
int r6 =
34-
isdigit(c6); // COMPLIANT: either control branch make this call compliant.
34+
isalnum(c6); // COMPLIANT: either control branch make this call compliant
35+
36+
int r7 = isalnum(EOF); // COMPLIANT: EOF (-1)
3537
}
3638

3739
int main() { return 0; }

cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast
159159
*/
160160
private class CtypeGetcharFunctionsRange extends SimpleRangeAnalysisExpr, FunctionCall {
161161
CtypeGetcharFunctionsRange() {
162-
this.getFile().(HeaderFile).getBaseName() = "stdio.h" and
162+
this.getTarget().getFile().(HeaderFile).getBaseName() = "stdio.h" and
163163
this.getTarget().getName().regexpMatch("(fgetc|getc|getchar|)")
164164
}
165165

0 commit comments

Comments
 (0)