Skip to content

Commit 15ed053

Browse files
Merge pull request #190 from github/jeongsoolee09/MISRA_21-13_and-21-15
Implement MISRA RULE-21-13 and RULE-21-15
2 parents d4c68f6 + 7dba082 commit 15ed053

17 files changed

+261
-3
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**
2+
* @id c/misra/ctype-function-arg-not-unsigned-char-or-eof
3+
* @name RULE-21-13: <ctype.h> function arguments shall be represented as unsigned char
4+
* @description Passing arguments to <ctype.h> functions outside the range of unsigned char or EOF
5+
* causes undefined behavior.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-21-13
10+
* external/misra/obligation/mandatory
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.misra
15+
import codingstandards.cpp.CharFunctions
16+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
17+
18+
from UseOfToOrIsChar ctypeCall
19+
where
20+
not isExcluded(ctypeCall,
21+
StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery()) and
22+
not exists(Expr ctypeCallArgument | ctypeCallArgument = ctypeCall.getConvertedArgument() |
23+
/* The argument's value should be in the EOF + `unsigned char` range. */
24+
-1 <= lowerBound(ctypeCallArgument) and upperBound(ctypeCallArgument) <= 255
25+
)
26+
select ctypeCall,
27+
"The <ctype.h> function " + ctypeCall + " accepts an argument " + ctypeCall.getConvertedArgument()
28+
+ " that is not an unsigned char nor an EOF."
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/**
2+
* @id c/misra/memcpy-memmove-memcmp-arg-not-pointers-to-compatible-types
3+
* @name RULE-21-15: The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers
4+
* @description Passing pointers to incompatible types as arguments to memcpy, memmove and memcmp
5+
* indicates programmers' confusion.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-21-15
10+
* external/misra/obligation/required
11+
*/
12+
13+
import cpp
14+
import codingstandards.c.misra
15+
import codingstandards.c.Pointers
16+
17+
class MemCmpMoveCpy extends Function {
18+
// Couldn't extend BuiltInFunction because it misses `memcmp`
19+
MemCmpMoveCpy() {
20+
this.getName().regexpMatch("mem(cmp|cpy|move)") and
21+
this.getADeclaration().getAFile().(HeaderFile).getBaseName() = "string.h"
22+
}
23+
}
24+
25+
from FunctionCall fc
26+
where
27+
not isExcluded(fc,
28+
StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()) and
29+
exists(MemCmpMoveCpy memfun, Type dstType, Type srcType | fc.getTarget() = memfun |
30+
dstType = fc.getArgument(0).getUnspecifiedType() and
31+
srcType = fc.getArgument(1).getUnspecifiedType() and
32+
(
33+
/* Case 1: dst and src are pointer types */
34+
dstType instanceof PointerType and
35+
srcType instanceof PointerType
36+
or
37+
/* Case 2: dst and src are array types */
38+
dstType instanceof ArrayType and
39+
srcType instanceof ArrayType
40+
) and
41+
not dstType = srcType
42+
)
43+
select fc,
44+
"The dest type " + fc.getArgument(0).getUnspecifiedType() + " and src type " +
45+
fc.getArgument(1).getUnspecifiedType() + " of function " + fc.getTarget() +
46+
" are not compatible."
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:14:7:14:13 | call to isalnum | The <ctype.h> function call to isalnum accepts an argument c3 that is not an unsigned char nor an EOF. |
2+
| test.c:20:7:20:13 | call to isalnum | The <ctype.h> function call to isalnum accepts an argument c4 that is not an unsigned char nor an EOF. |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:14:7:14:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
2+
| test.c:20:7:20:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:14:7:14:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
2+
| test.c:20:7:20:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:14:7:14:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
2+
| test.c:20:7:20:17 | isalnum(c) | The <ctype.h> function isalnum(c) accepts an argument (...) that is not an unsigned char nor an EOF. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-21-13/CtypeFunctionArgNotUnsignedCharOrEof.ql

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include <ctype.h>
2+
#include <stdio.h>
3+
4+
void sample() {
5+
unsigned char c1 = 'c';
6+
int r1 = isalnum(
7+
c1); // COMPLIANT: ASCII 99 is within unsigned char range of [0, 255]
8+
int r2 = isalnum(EOF); // COMPLIANT: EOF (-1)
9+
10+
int x3 = 256;
11+
int x4 = x3;
12+
int c3 = x4;
13+
int r3 =
14+
isalnum(c3); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
15+
16+
unsigned char x5 = EOF;
17+
unsigned char x6 = x5;
18+
int c4 = x6 + 10000;
19+
int r4 =
20+
isalnum(c4); // NON_COMPLIANT: is outside unsigned char range of [0, 255]
21+
22+
int c5 = getchar();
23+
int r5 = isalnum(
24+
c5); // COMPLIANT: <stdio.h> source functions like getchar are modelled
25+
26+
unsigned char x7;
27+
int c6;
28+
if (x7 == 1) {
29+
c6 = EOF;
30+
} else {
31+
c6 = 'c';
32+
}
33+
int r6 =
34+
isalnum(c6); // COMPLIANT: either control branch make this call compliant
35+
36+
int r7 = isalnum(EOF); // COMPLIANT: EOF (-1)
37+
}
38+
39+
int main() { return 0; }
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:6:3:6:8 | call to memcpy | The dest type int * and src type char * of function memcpy are not compatible. |
2+
| test.c:18:3:18:9 | call to memmove | The dest type char[9] and src type int[2] of function memmove are not compatible. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <string.h>
2+
3+
void sample() {
4+
int from1 = 1000000;
5+
char to1;
6+
memcpy(&from1, &to1, 1); // NON_COMPLIANT, the types are not compatible
7+
8+
int from2 = 1000000;
9+
int to2;
10+
memcpy(&from2, &to2, 2); // COMPLIANT
11+
12+
char from3[] = "string";
13+
char to3[7];
14+
memmove(from3, to3, 7); // COMPLIANT
15+
16+
char from4[] = "sstringg";
17+
int to4[2];
18+
memmove(from4, to4, 8); // NON_COMPLIANT, despite being equal in byte counts
19+
20+
char from5[] = "STRING";
21+
char to5[] = "string";
22+
memcmp(from5, to5, 2); // COMPLIANT
23+
}
24+
25+
int main() { return 0; }

cpp/common/src/codingstandards/cpp/CharFunctions.qll

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ private string getCToOrIsName() {
1818
* the structure of the macro, or
1919
*/
2020
abstract class UseOfToOrIsChar extends Element {
21-
/** */
2221
abstract Expr getConvertedArgument();
2322
}
2423

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,28 @@ private class CastEnumToIntegerSimpleRange extends SimpleRangeAnalysisExpr, Cast
151151
override predicate dependsOnChild(Expr child) { child = getExpr() }
152152
}
153153

154+
/**
155+
* <stdio.h> functions that read a character from the STDIN,
156+
* or return EOF if it fails to do so.
157+
* Their return type is `int` by their signatures, but
158+
* they actually return either an unsigned char or an EOF.
159+
*/
160+
private class CtypeGetcharFunctionsRange extends SimpleRangeAnalysisExpr, FunctionCall {
161+
CtypeGetcharFunctionsRange() {
162+
this.getTarget().getFile().(HeaderFile).getBaseName() = "stdio.h" and
163+
this.getTarget().getName().regexpMatch("(fgetc|getc|getchar|)")
164+
}
165+
166+
/* It can return an EOF, which is -1 on most implementations. */
167+
override float getLowerBounds() { result = -1 }
168+
169+
/* Otherwise, it can return any unsigned char. */
170+
override float getUpperBounds() { result = 255 }
171+
172+
/* No, its call does not depend on any of its child. */
173+
override predicate dependsOnChild(Expr expr) { none() }
174+
}
175+
154176
/**
155177
* Gets the value of the expression `e`, if it is a constant.
156178
*

cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import Preprocessor6
4949
import SideEffects1
5050
import SideEffects2
5151
import SignalHandlers
52+
import StandardLibraryFunctionTypes
5253
import Strings1
5354
import Strings2
5455
import Strings3
@@ -103,6 +104,7 @@ newtype TCQuery =
103104
TSideEffects1PackageQuery(SideEffects1Query q) or
104105
TSideEffects2PackageQuery(SideEffects2Query q) or
105106
TSignalHandlersPackageQuery(SignalHandlersQuery q) or
107+
TStandardLibraryFunctionTypesPackageQuery(StandardLibraryFunctionTypesQuery q) or
106108
TStrings1PackageQuery(Strings1Query q) or
107109
TStrings2PackageQuery(Strings2Query q) or
108110
TStrings3PackageQuery(Strings3Query q) or
@@ -157,6 +159,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
157159
isSideEffects1QueryMetadata(query, queryId, ruleId, category) or
158160
isSideEffects2QueryMetadata(query, queryId, ruleId, category) or
159161
isSignalHandlersQueryMetadata(query, queryId, ruleId, category) or
162+
isStandardLibraryFunctionTypesQueryMetadata(query, queryId, ruleId, category) or
160163
isStrings1QueryMetadata(query, queryId, ruleId, category) or
161164
isStrings2QueryMetadata(query, queryId, ruleId, category) or
162165
isStrings3QueryMetadata(query, queryId, ruleId, category) or
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype StandardLibraryFunctionTypesQuery =
7+
TCtypeFunctionArgNotUnsignedCharOrEofQuery() or
8+
TMemcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()
9+
10+
predicate isStandardLibraryFunctionTypesQueryMetadata(
11+
Query query, string queryId, string ruleId, string category
12+
) {
13+
query =
14+
// `Query` instance for the `ctypeFunctionArgNotUnsignedCharOrEof` query
15+
StandardLibraryFunctionTypesPackage::ctypeFunctionArgNotUnsignedCharOrEofQuery() and
16+
queryId =
17+
// `@id` for the `ctypeFunctionArgNotUnsignedCharOrEof` query
18+
"c/misra/ctype-function-arg-not-unsigned-char-or-eof" and
19+
ruleId = "RULE-21-13" and
20+
category = "mandatory"
21+
or
22+
query =
23+
// `Query` instance for the `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query
24+
StandardLibraryFunctionTypesPackage::memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery() and
25+
queryId =
26+
// `@id` for the `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query
27+
"c/misra/memcpy-memmove-memcmp-arg-not-pointers-to-compatible-types" and
28+
ruleId = "RULE-21-15" and
29+
category = "required"
30+
}
31+
32+
module StandardLibraryFunctionTypesPackage {
33+
Query ctypeFunctionArgNotUnsignedCharOrEofQuery() {
34+
//autogenerate `Query` type
35+
result =
36+
// `Query` type for `ctypeFunctionArgNotUnsignedCharOrEof` query
37+
TQueryC(TStandardLibraryFunctionTypesPackageQuery(TCtypeFunctionArgNotUnsignedCharOrEofQuery()))
38+
}
39+
40+
Query memcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery() {
41+
//autogenerate `Query` type
42+
result =
43+
// `Query` type for `memcpyMemmoveMemcmpArgNotPointersToCompatibleTypes` query
44+
TQueryC(TStandardLibraryFunctionTypesPackageQuery(TMemcpyMemmoveMemcmpArgNotPointersToCompatibleTypesQuery()))
45+
}
46+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"MISRA-C-2012": {
3+
"RULE-21-13": {
4+
"properties": {
5+
"obligation": "mandatory"
6+
},
7+
"queries": [
8+
{
9+
"description": "Passing arguments to <ctype.h> functions outside the range of unsigned char or EOF causes undefined behavior.",
10+
"kind": "problem",
11+
"name": "<ctype.h> function arguments shall be represented as unsigned char",
12+
"precision": "very-high",
13+
"severity": "error",
14+
"short_name": "CtypeFunctionArgNotUnsignedCharOrEof",
15+
"tags": []
16+
}
17+
],
18+
"title": "Any value passed to a function in <ctype.h> shall be representable as an unsigned char or be the value EOF"
19+
},
20+
"RULE-21-15": {
21+
"properties": {
22+
"obligation": "required"
23+
},
24+
"queries": [
25+
{
26+
"description": "Passing pointers to incompatible types as arguments to memcpy, memmove and memcmp indicates programmers' confusion.",
27+
"kind": "problem",
28+
"name": "The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers",
29+
"precision": "very-high",
30+
"severity": "error",
31+
"short_name": "MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes",
32+
"tags": []
33+
}
34+
],
35+
"title": "The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types"
36+
}
37+
}
38+
}

rules.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -755,9 +755,9 @@ c,MISRA-C-2012,RULE-21-9,Yes,Required,,,The Standard Library functions bsearch a
755755
c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date functions shall not be used,,Banned,Easy,
756756
c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file <tgmath.h> shall not be used,,Banned,Easy,
757757
c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of <fenv.h> should not be used,,Banned,Easy,
758-
c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in <ctype.h> shall be representable as an unsigned char or be the value EOF,,Types,Medium,
758+
c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in <ctype.h> shall be representable as an unsigned char or be the value EOF,,StandardLibraryFunctionTypes,Medium,
759759
c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard,
760-
c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,Types,Medium,
760+
c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,StandardLibraryFunctionTypes,Medium,
761761
c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,EssentialTypes,Medium,
762762
c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from <string.h> shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory2,Hard,
763763
c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any function in <string.h> shall have an appropriate value,,OutOfBounds,Hard,

0 commit comments

Comments
 (0)