Skip to content

Commit 7617acc

Browse files
committed
Reinforce 7-4 to consider wchar_t
1 parent 0f532e3 commit 7617acc

File tree

3 files changed

+95
-20
lines changed

3 files changed

+95
-20
lines changed

c/misra/src/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.ql

Lines changed: 45 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,32 @@
1313
import cpp
1414
import codingstandards.c.misra
1515

16+
/** Pointer to Wide character type, i.e. `wchar_t*`. */
17+
class WideCharPointerType extends PointerType {
18+
WideCharPointerType() { this.getBaseType() instanceof Wchar_t }
19+
20+
override string getAPrimaryQlClass() { result = "WideCharPointerType" }
21+
}
22+
23+
class GenericCharPointerType extends PointerType {
24+
GenericCharPointerType() {
25+
/* This type resolves to wchar_t* (which is in turn a typedef depending on its implementation) */
26+
this.resolveTypedefs*() instanceof WideCharPointerType
27+
or
28+
/* This type eventually resolves to char* */
29+
this.resolveTypedefs*() instanceof CharPointerType
30+
}
31+
32+
predicate isWideCharPointerType() { this.resolveTypedefs*() instanceof WideCharPointerType }
33+
34+
override string toString() {
35+
if this.isWideCharPointerType() then result = "wchar_t*" else result = "char*"
36+
}
37+
}
38+
1639
class NonConstCharStarType extends Type {
1740
NonConstCharStarType() {
18-
this instanceof CharPointerType and
41+
this instanceof GenericCharPointerType and
1942
not this.isDeeplyConstBelow()
2043
}
2144
}
@@ -24,40 +47,48 @@ class NonConstCharStarType extends Type {
2447
predicate declaringNonConstCharVar(Variable decl, string message) {
2548
not decl instanceof Parameter and // exclude parameters
2649
/* It should be declaring a char* type variable */
27-
decl.getUnspecifiedType() instanceof CharPointerType and
28-
not decl.getUnderlyingType().isDeeplyConstBelow() and
29-
/* But it's declared to hold a string literal. */
50+
decl.getType() instanceof GenericCharPointerType and
51+
not decl.getType().isDeeplyConstBelow() and
52+
/* But it's declared to hold a string literal. */
3053
decl.getInitializer().getExpr() instanceof StringLiteral and
31-
message = "char* variable " + decl + " is declared with a string literal."
54+
message =
55+
decl.getType().(GenericCharPointerType) + " variable " + decl +
56+
" is declared with a string literal."
3257
}
3358

3459
/* String literal being assigned to a non-const-char* variable */
3560
predicate assignmentToNonConstCharVar(Assignment assign, string message) {
3661
/* The variable being assigned is char* */
37-
assign.getLValue().getUnderlyingType() instanceof NonConstCharStarType and
62+
assign.getLValue().getType() instanceof NonConstCharStarType and
3863
/* But the rvalue is a string literal */
39-
exists(Expr rvalue | rvalue = assign.getRValue() | rvalue instanceof StringLiteral) and
40-
message = "char* variable " + assign.getLValue() + " is assigned a string literal. "
64+
assign.getRValue() instanceof StringLiteral and
65+
message =
66+
assign.getLValue().getType().(GenericCharPointerType) + " variable " + assign.getLValue() +
67+
" is assigned a string literal. "
4168
}
4269

4370
/* String literal being passed to a non-const-char* parameter */
4471
predicate assignmentToNonConstCharParam(FunctionCall call, string message) {
4572
exists(int index |
4673
/* Param at index is a char* */
47-
call.getTarget().getParameter(index).getUnderlyingType() instanceof NonConstCharStarType and
74+
call.getTarget().getParameter(index).getType() instanceof NonConstCharStarType and
4875
/* But a string literal is passed */
49-
call.getArgument(index) instanceof StringLiteral
50-
) and
51-
message = "char* parameter of " + call.getTarget() + " is passed a string literal."
76+
call.getArgument(index) instanceof StringLiteral and
77+
message =
78+
call.getTarget().getParameter(index).getType().(GenericCharPointerType) + " parameter of " +
79+
call.getTarget() + " is passed a string literal."
80+
)
5281
}
5382

5483
/* String literal being returned by a non-const-char* function */
5584
predicate returningNonConstCharVar(ReturnStmt return, string message) {
5685
/* The function is declared to return a char* */
57-
return.getEnclosingFunction().getType().resolveTypedefs() instanceof NonConstCharStarType and
86+
return.getEnclosingFunction().getType() instanceof NonConstCharStarType and
5887
/* But in reality it returns a string literal */
5988
return.getExpr() instanceof StringLiteral and
60-
message = "char* function " + return.getEnclosingFunction() + " is returning a string literal."
89+
message =
90+
return.getEnclosingFunction().getType().(GenericCharPointerType) + " function " +
91+
return.getEnclosingFunction() + " is returning a string literal."
6192
}
6293

6394
from Element elem, string message
Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
| test.c:9:9:9:10 | s3 | char* variable s3 is declared with a string literal. |
2-
| test.c:11:3:12:15 | ... = ... | char* variable s3 is assigned a string literal. |
3-
| test.c:26:5:26:21 | return ... | char* function sample3 is returning a string literal. |
4-
| test.c:38:3:38:9 | call to sample4 | char* parameter of sample4 is passed a string literal. |
1+
| test.c:11:9:11:10 | s3 | char* variable s3 is declared with a string literal. |
2+
| test.c:13:3:14:15 | ... = ... | char* variable s3 is assigned a string literal. |
3+
| test.c:23:12:23:14 | ws3 | char* variable ws3 is declared with a string literal. |
4+
| test.c:25:3:25:23 | ... = ... | char* variable ws3 is assigned a string literal. |
5+
| test.c:50:5:50:21 | return ... | char* function sample3 is returning a string literal. |
6+
| test.c:58:5:58:22 | return ... | char* function w_sample3 is returning a string literal. |
7+
| test.c:69:3:69:9 | call to sample4 | char* parameter of sample4 is passed a string literal. |
8+
| test.c:78:3:78:11 | call to w_sample4 | char* parameter of w_sample4 is passed a string literal. |

c/misra/test/rules/RULE-7-4/test.c

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
#include <wchar.h>
12
#include <stdio.h>
23

34
void sample1() {
5+
/* Test for plain char type */
46
const char *s1 =
57
"string1"; // COMPLIANT: string literal assigned to a const char* variable
68
const register volatile char *s2 =
@@ -11,8 +13,21 @@ void sample1() {
1113
s3 =
1214
"string4"; // NON_COMPLIANT: char* variable assigned a string literal
1315
// (not likely to be seen in production, since there is strcpy)
16+
17+
/* Test for wide char type */
18+
const wchar_t *ws1 = L"wide string1"; // COMPLIANT: string literal assigned to
19+
// a const char* variable
20+
const register volatile wchar_t *ws2 =
21+
L"wide string2"; // COMPLIANT: string literal assigned to a const char*
22+
// variable, don't care about the qualifiers
23+
wchar_t *ws3 = L"wide string3"; // NON_COMPLIANT: char* variable declared to hold
24+
// a string literal
25+
ws3 = L"wide string4"; // NON_COMPLIANT: char* variable assigned a string
26+
// literal (not likely to be seen in production, since
27+
// there is strcpy)
1428
}
1529

30+
/* Testing returning a plain string literal */
1631
const char *sample2(int x) {
1732
if (x == 1)
1833
return "string5"; // COMPLIANT: can return a string literal with return type
@@ -21,6 +36,15 @@ const char *sample2(int x) {
2136
return NULL;
2237
}
2338

39+
/* Testing returning a wide string literal */
40+
const wchar_t *w_sample2(int x) {
41+
if (x == 1)
42+
return L"string5"; // COMPLIANT: can return a string literal with return type
43+
// being const char* being const char*
44+
else
45+
return NULL;
46+
}
47+
2448
char *sample3(int x) {
2549
if (x == 1)
2650
return "string6"; // NON_COMPLIANT: can return a string literal with return
@@ -29,14 +53,30 @@ char *sample3(int x) {
2953
return NULL;
3054
}
3155

56+
wchar_t *w_sample3(int x) {
57+
if (x == 1)
58+
return L"string6"; // NON_COMPLIANT: can return a string literal with return
59+
// type being char*
60+
else
61+
return NULL;
62+
}
63+
3264
void sample4(char *string) {}
3365

3466
void sample5(const char *string) {}
3567

3668
void call45() {
37-
const char *literal = "string7";
3869
sample4("string8"); // NON_COMPLIANT: can't pass string literal to char*
3970
sample5("string9"); // COMPLIANT: passing string literal to const char*
4071
}
4172

42-
int main() { return 0; }
73+
void w_sample4(wchar_t *string) {}
74+
75+
void w_sample5(const wchar_t *string) {}
76+
77+
void w_call45() {
78+
w_sample4(L"string8"); // NON_COMPLIANT: can't pass string literal to char*
79+
w_sample5(L"string9"); // COMPLIANT: passing string literal to const char*
80+
}
81+
82+
int main() { return 0; }

0 commit comments

Comments
 (0)