MISRA Rule 7.4 Check if variables assigned as string literals are const (#2866)

This commit is contained in:
Lars Even Almaas 2020-11-04 13:45:02 +01:00 committed by GitHub
parent aad29ddb9a
commit 05b804d126
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 102 additions and 0 deletions

View File

@ -850,6 +850,46 @@ def isNoReturnScope(tok):
return False return False
# Return the token which the value is assigned to
def getAssignedVariableToken(valueToken):
if not valueToken:
return None
if not valueToken.astParent:
return None
operator = valueToken.astParent
if operator.isAssignmentOp:
return operator.astOperand1
if operator.isArithmeticalOp:
return getAssignedVariableToken(operator)
return None
# If the value is used as a return value, return the function definition
def getFunctionUsingReturnValue(valueToken):
if not valueToken:
return None
if not valueToken.astParent:
return None
operator = valueToken.astParent
if operator.str == 'return':
return operator.scope.function
if operator.isArithmeticalOp:
return getFunctionUsingReturnValue(operator)
return None
# Return true if the token follows a specific sequence of token str values
def tokenFollowsSequence(token, sequence):
if not token:
return False
for i in reversed(sequence):
prev = token.previous
if not prev:
return False
if prev.str != i:
return False
token = prev
return True
class Define: class Define:
def __init__(self, directive): def __init__(self, directive):
self.args = [] self.args = []
@ -1353,6 +1393,45 @@ class MisraChecker:
if compiled.match(tok.str): if compiled.match(tok.str):
self.reportError(tok, 7, 3) self.reportError(tok, 7, 3)
def misra_7_4(self, data):
# A string literal shall not be assigned to an object unless the object's type
# is constant.
def reportErrorIfVariableIsNotConst(variable, stringLiteral):
if variable.valueType:
if variable.valueType.constness != 1:
self.reportError(stringLiteral, 7, 4)
for token in data.tokenlist:
if token.isString:
# Check normal variable assignment
variable = getAssignedVariableToken(token)
if variable:
reportErrorIfVariableIsNotConst(variable, token)
# Check use as return value
function = getFunctionUsingReturnValue(token)
if function:
# "Primitive" test since there is no info available on return value type
if not tokenFollowsSequence(function.tokenDef, ['const', 'char', '*']):
self.reportError(token, 7, 4)
# Check use as function parameter
if isFunctionCall(token) and token.astOperand1 and token.astOperand1.function:
functionDeclaration = token.astOperand1.function
parametersUsed = getArguments(token)
if functionDeclaration and functionDeclaration.tokenDef:
if functionDeclaration.tokenDef.Id == token.astOperand1.Id:
# Token is not a function call, but it is the definition of the function
continue
for i in range(len(parametersUsed)):
usedParameter = parametersUsed[i]
parameterDefinition = functionDeclaration.argument.get(i+1)
if usedParameter.isString and parameterDefinition.nameToken:
reportErrorIfVariableIsNotConst(parameterDefinition.nameToken, usedParameter)
def misra_8_11(self, data): def misra_8_11(self, data):
for var in data.variables: for var in data.variables:
if var.isExtern and simpleMatch(var.nameToken.next, '[ ]') and var.nameToken.scope.type == 'Global': if var.isExtern and simpleMatch(var.nameToken.next, '[ ]') and var.nameToken.scope.type == 'Global':
@ -2958,6 +3037,7 @@ class MisraChecker:
if cfgNumber == 0: if cfgNumber == 0:
self.executeCheck(701, self.misra_7_1, data.rawTokens) self.executeCheck(701, self.misra_7_1, data.rawTokens)
self.executeCheck(703, self.misra_7_3, data.rawTokens) self.executeCheck(703, self.misra_7_3, data.rawTokens)
self.executeCheck(704, self.misra_7_4, cfg)
self.executeCheck(811, self.misra_8_11, cfg) self.executeCheck(811, self.misra_8_11, cfg)
self.executeCheck(812, self.misra_8_12, cfg) self.executeCheck(812, self.misra_8_12, cfg)
if cfgNumber == 0: if cfgNumber == 0:

View File

@ -233,6 +233,28 @@ void misra_7_3() {
long double misra_7_3_e = 7.3l; //7.3 long double misra_7_3_e = 7.3l; //7.3
} }
typedef const char* MISRA_7_4_CHAR_CONST;
MISRA_7_4_CHAR_CONST misra_7_4_return_const_type_def (void) { return "return_typedef_const"; }
char *misra_7_4_return_non_const (void) { return 1 + "return_non_const"; } // 7.4 18.4
const char *misra_7_4_return_const (void) { return 1 + "return_const"; } // 18.4
void misra_7_4_const_call(int a, const char* b) { } // 2.7
void misra_7_4_call(int a, char* b) { } // 2.7
void misra_7_4()
{
const char *a = "text a";
char* const b = "text_b"; // 7.4
char *c = "text c"; // 7.4
char *d = 1 + "text d"; // 7.4 18.4
char *e = "text e" + 1 + 2; // 7.4 18.4
char *f = 1 + "text f" + 2; // 7.4 18.4
const wchar_t *g = "text_g";
wchar_t *h = "text_h"; // 7.4
misra_7_4_const_call(1, ("text_const_call"));
misra_7_4_call(1, "text_call"); // 7.4 11.8
}
extern int a811[]; // 8.11 extern int a811[]; // 8.11