Skip to content

Commit 16fe159

Browse files
committed
Draft of 7-4
1 parent 2ebcf85 commit 16fe159

File tree

2 files changed

+99
-15
lines changed

2 files changed

+99
-15
lines changed

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

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,88 @@
1313
import cpp
1414
import codingstandards.c.misra
1515

16-
from
16+
class NonConstCharStarType extends Type {
17+
NonConstCharStarType() {
18+
this instanceof CharPointerType and
19+
not this.isDeeplyConstBelow()
20+
}
21+
}
22+
23+
/* A non-const-char* variable declared with a string literal */
24+
predicate declaringNonConstCharVar(Variable decl) {
25+
not decl instanceof Parameter and // exclude parameters
26+
/* 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. */
30+
decl.getInitializer().getExpr() instanceof StringLiteral
31+
}
32+
33+
/* String literal being assigned to a non-const-char* variable */
34+
predicate assignmentToNonConstCharVar(Assignment assign) {
35+
/* The variable being assigned is char* */
36+
assign.getLValue().getUnderlyingType() instanceof NonConstCharStarType and
37+
/* But the rvalue is a string literal */
38+
exists(Expr rvalue | rvalue = assign.getRValue() | rvalue instanceof StringLiteral)
39+
}
40+
41+
/* String literal being passed to a non-const-char* parameter */
42+
predicate assignmentToNonConstCharParam(FunctionCall call) {
43+
exists(int index |
44+
/* Param at index is a char* */
45+
call.getTarget().getParameter(index).getUnderlyingType() instanceof NonConstCharStarType and
46+
/* But a string literal is passed */
47+
call.getArgument(index) instanceof StringLiteral
48+
)
49+
}
50+
51+
/* String literal being returned by a non-const-char* function */
52+
predicate returningNonConstCharVar(ReturnStmt return) {
53+
/* The function is declared to return a char* */
54+
return.getEnclosingFunction().getType().resolveTypedefs() instanceof NonConstCharStarType and
55+
/* But in reality it returns a string literal */
56+
return.getExpr() instanceof StringLiteral
57+
}
58+
59+
// newtype TProblematicElem =
60+
// TVar(Variable decl) or
61+
// TAssign(Assignment assign) or
62+
// TFunCall(FunctionCall call) or
63+
// TReturnStmt(ReturnStmt return)
64+
// class ProblematicElem extends TProblematicElem {
65+
// Variable getVariable() { this = TVar(result) }
66+
// Assignment getAssign() { this = TAssign(result) }
67+
// FunctionCall getFunCall() { this = TFunCall(result) }
68+
// ReturnStmt getReturnStmt() { this = TReturnStmt(result) }
69+
// override string toString() {
70+
// this instanceof TVar and result = this.getVariable().toString()
71+
// or
72+
// this instanceof TAssign and result = this.getAssign().toString()
73+
// or
74+
// this instanceof TFunCall and result = this.getFunCall().toString()
75+
// or
76+
// this instanceof TReturnStmt and result = this.getReturnStmt().toString()
77+
// }
78+
// }
79+
// class ProblematicElem = Variable or Assignment or FunctionCall or ReturnStmt;
80+
// ^ Nope!
81+
from Variable decl, Assignment assign, FunctionCall call, ReturnStmt return, string message
1782
where
18-
not isExcluded(x, TypesPackage::stringLiteralAssignedToNonConstCharQuery()) and
19-
select
83+
not isExcluded(decl, TypesPackage::stringLiteralAssignedToNonConstCharQuery()) and
84+
not isExcluded(assign, TypesPackage::stringLiteralAssignedToNonConstCharQuery()) and
85+
not isExcluded(call, TypesPackage::stringLiteralAssignedToNonConstCharQuery()) and
86+
not isExcluded(return, TypesPackage::stringLiteralAssignedToNonConstCharQuery()) and
87+
(
88+
declaringNonConstCharVar(decl) and
89+
message = "char* variable " + decl + " is declared with a string literal."
90+
or
91+
assignmentToNonConstCharVar(assign) and
92+
message = "char* variable " + assign.getLValue() + " is assigned a string literal. "
93+
or
94+
assignmentToNonConstCharParam(call) and
95+
message = "char* parameter of " + call.getTarget() + " is passed a string literal."
96+
or
97+
returningNonConstCharVar(return) and
98+
message = "char* function " + return.getEnclosingFunction() + " is returning a string literal."
99+
)
100+
select message

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

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,29 @@
22

33
void sample1() {
44
const char *s1 =
5-
"string"; // COMPLIANT: string literal assigned to a const char* variable
5+
"string1"; // COMPLIANT: string literal assigned to a const char* variable
66
const register volatile char *s2 =
7-
"string"; // COMPLIANT: string literal assigned to a const char* variable,
8-
// don't care about the qualifiers
9-
char *s3 = "string"; // NON_COMPLIANT: char* variable declared to hold a
10-
// string literal
7+
"string2"; // COMPLIANT: string literal assigned to a const char*
8+
// variable, don't care about the qualifiers
9+
char *s3 = "string3"; // NON_COMPLIANT: char* variable declared to hold a
10+
// string literal
11+
s3 =
12+
"string4"; // NON_COMPLIANT: char* variable assigned a string literal
13+
// (not likely to be seen in production, since there is strcpy)
1114
}
1215

1316
const char *sample2(int x) {
1417
if (x == 1)
15-
return "string"; // COMPLIANT: can return a string literal with return type
16-
// being const char* being const char*
18+
return "string5"; // COMPLIANT: can return a string literal with return type
19+
// being const char* being const char*
1720
else
1821
return NULL;
1922
}
2023

2124
char *sample3(int x) {
2225
if (x == 1)
23-
return "string"; // NON_COMPLIANT: can return a string literal with return
24-
// type being char*
26+
return "string6"; // NON_COMPLIANT: can return a string literal with return
27+
// type being char*
2528
else
2629
return NULL;
2730
}
@@ -31,9 +34,9 @@ void sample4(char *string) {}
3134
void sample5(const char *string) {}
3235

3336
void call45() {
34-
const char *literal = "string";
35-
sample4("string"); // NON_COMPLIANT: can't pass string literal to char*
36-
sample5("string"); // COMPLIANT: passing string literal to const char*
37+
const char *literal = "string7";
38+
sample4("string8"); // NON_COMPLIANT: can't pass string literal to char*
39+
sample5("string9"); // COMPLIANT: passing string literal to const char*
3740
}
3841

3942
int main() { return 0; }

0 commit comments

Comments
 (0)