misra.py: Fix Rule 4.1 (#2216)
* misra.py: Use standard string module * misra.py: Fixup R4.1 References: * https://trac.cppcheck.net/ticket/9370 * https://sourceforge.net/p/cppcheck/discussion/development/thread/7274ed3842/?limit=25#799a * Add more examples from @matzeschmid PR * Add more out-of-bounds tests * Fix R4.1. * Compress hex condition * Add more test cases * Fix python3 zip import
This commit is contained in:
parent
3f587bef65
commit
846f356db4
110
addons/misra.py
110
addons/misra.py
|
@ -21,6 +21,17 @@ import re
|
||||||
import os
|
import os
|
||||||
import argparse
|
import argparse
|
||||||
import codecs
|
import codecs
|
||||||
|
import string
|
||||||
|
|
||||||
|
try:
|
||||||
|
from itertools import izip as zip
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def grouped(iterable, n):
|
||||||
|
"s -> (s0,s1,s2,...sn-1), (sn,sn+1,sn+2,...s2n-1), (s2n,s2n+1,s2n+2,...s3n-1), ..."
|
||||||
|
return zip(*[iter(iterable)]*n)
|
||||||
|
|
||||||
|
|
||||||
typeBits = {
|
typeBits = {
|
||||||
|
@ -456,15 +467,52 @@ def getArguments(ftok):
|
||||||
|
|
||||||
|
|
||||||
def isalnum(c):
|
def isalnum(c):
|
||||||
return (c >= '0' and c <= '9') or (c >= 'a' and c <= 'z') or (c >= 'A' and c <= 'Z')
|
return c in string.digits or c in string.ascii_letters
|
||||||
|
|
||||||
|
|
||||||
def isHexDigit(c):
|
def isHexEscapeSequence(symbols):
|
||||||
return (c >= '0' and c <= '9') or (c >= 'a' and c <= 'f') or (c >= 'A' and c <= 'F')
|
"""Checks that given symbols are valid hex escape sequence.
|
||||||
|
|
||||||
|
hexademical-escape-sequence:
|
||||||
|
\\x hexademical-digit
|
||||||
|
hexademical-escape-sequence hexademical-digit
|
||||||
|
|
||||||
|
Reference: n1570 6.4.4.4"""
|
||||||
|
if len(symbols) < 3 or symbols[:2] != '\\x':
|
||||||
|
return False
|
||||||
|
return all([s in string.hexdigits for s in symbols[2:]])
|
||||||
|
|
||||||
|
|
||||||
def isOctalDigit(c):
|
def isOctalEscapeSequence(symbols):
|
||||||
return c >= '0' and c <= '7'
|
"""Checks that given symbols are valid octal escape sequence:
|
||||||
|
|
||||||
|
octal-escape-sequence:
|
||||||
|
\ octal-digit
|
||||||
|
\ octal-digit octal-digit
|
||||||
|
\ octal-digit octal-digit octal-digit
|
||||||
|
|
||||||
|
Reference: n1570 6.4.4.4"""
|
||||||
|
if len(symbols) not in range(2, 5) or symbols[0] != '\\':
|
||||||
|
return False
|
||||||
|
return all([s in string.octdigits for s in symbols[1:]])
|
||||||
|
|
||||||
|
|
||||||
|
def isSimpleEscapeSequence(symbols):
|
||||||
|
"""Checks that given symbols are simple escape sequence.
|
||||||
|
Reference: n1570 6.4.4.4"""
|
||||||
|
if len(symbols) != 2 or symbols[0] != '\\':
|
||||||
|
return False
|
||||||
|
return symbols[1] in ("'", '"', '?', '\\', 'a', 'b', 'f', 'n', 'r', 't', 'v')
|
||||||
|
|
||||||
|
|
||||||
|
def hasNumericEscapeSequence(symbols):
|
||||||
|
"""Check that given string contains octal or hexademical escape sequences."""
|
||||||
|
if '\\' not in symbols:
|
||||||
|
return False
|
||||||
|
for c, cn in grouped(symbols, 2):
|
||||||
|
if c == '\\' and cn in ('x' + string.octdigits):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def isNoReturnScope(tok):
|
def isNoReturnScope(tok):
|
||||||
|
@ -700,38 +748,34 @@ class MisraChecker:
|
||||||
|
|
||||||
def misra_4_1(self, rawTokens):
|
def misra_4_1(self, rawTokens):
|
||||||
for token in rawTokens:
|
for token in rawTokens:
|
||||||
if ((token.str[0] != '"') and (token.str[0] != '\'')):
|
if (token.str[0] != '"') and (token.str[0] != '\''):
|
||||||
|
continue
|
||||||
|
if len(token.str) < 3:
|
||||||
continue
|
continue
|
||||||
pos = 1
|
|
||||||
while pos < len(token.str) - 2:
|
|
||||||
pos1 = pos
|
|
||||||
pos = pos + 1
|
|
||||||
if token.str[pos1] != '\\':
|
|
||||||
continue
|
|
||||||
if token.str[pos1 + 1] == '\\':
|
|
||||||
pos = pos1 + 2
|
|
||||||
continue
|
|
||||||
if token.str[pos1 + 1] == 'x':
|
|
||||||
if not isHexDigit(token.str[pos1 + 2]):
|
|
||||||
self.reportError(token, 4, 1)
|
|
||||||
continue
|
|
||||||
if not isHexDigit(token.str[pos1 + 3]):
|
|
||||||
self.reportError(token, 4, 1)
|
|
||||||
continue
|
|
||||||
elif isOctalDigit(token.str[pos1 + 1]):
|
|
||||||
if not isOctalDigit(token.str[pos1 + 2]):
|
|
||||||
self.reportError(token, 4, 1)
|
|
||||||
continue
|
|
||||||
if not isOctalDigit(token.str[pos1 + 2]):
|
|
||||||
self.reportError(token, 4, 1)
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
c = token.str[pos1 + 4]
|
delimiter = token.str[0]
|
||||||
if c != '"' and c != '\\':
|
symbols = token.str[1:-1]
|
||||||
|
|
||||||
|
# No closing delimiter. This will not compile.
|
||||||
|
if token.str[-1] != delimiter:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if len(symbols) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if not hasNumericEscapeSequence(symbols):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# String literals that contains one or more escape sequences. All of them should be
|
||||||
|
# terminated.
|
||||||
|
for sequence in ['\\' + t for t in symbols.split('\\')][1:]:
|
||||||
|
if (isHexEscapeSequence(sequence) or isOctalEscapeSequence(sequence) or
|
||||||
|
isSimpleEscapeSequence(sequence)):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
self.reportError(token, 4, 1)
|
self.reportError(token, 4, 1)
|
||||||
|
|
||||||
|
|
||||||
def misra_5_1(self, data):
|
def misra_5_1(self, data):
|
||||||
long_vars = {}
|
long_vars = {}
|
||||||
for var in data.variables:
|
for var in data.variables:
|
||||||
|
|
|
@ -68,9 +68,35 @@ int misra_5_2_field_hides_field1_31y;//5.2
|
||||||
};
|
};
|
||||||
const char *s41_1 = "\x41g"; // 4.1
|
const char *s41_1 = "\x41g"; // 4.1
|
||||||
const char *s41_2 = "\x41\x42";
|
const char *s41_2 = "\x41\x42";
|
||||||
const char *s41_3 = "\x41" "g";
|
const char *s41_3 = "\x41" "\x42";
|
||||||
|
const char *s41_4 = "\x41" "g";
|
||||||
|
const char *s41_5 = "\x41\xA";
|
||||||
|
const char *s41_6 = "\xA\x41";
|
||||||
|
const char *s41_7 = "\xAA\xg\x41"; // 4.1
|
||||||
|
const char *s41_8 = "\xAA\x\x41"; // 4.1
|
||||||
|
const char *s41_9 = "unknown\gsequence";
|
||||||
|
const char *s41_10 = "simple\nsequence";
|
||||||
|
const char *s41_11 = "string";
|
||||||
int c41_3 = '\141t'; // 4.1
|
int c41_3 = '\141t'; // 4.1
|
||||||
int c41_4 = '\141\t';
|
int c41_4 = '\141\t';
|
||||||
|
int c41_5 = '\0';
|
||||||
|
int c41_6 = '\0\t';
|
||||||
|
int c41_7 = '\12\t';
|
||||||
|
int c41_8 = '\0t'; // 4.1
|
||||||
|
int c41_9 = '\12';
|
||||||
|
int c41_10 = '\12\n';
|
||||||
|
int c41_11 = '\12n'; // 4.1
|
||||||
|
int c41_12 = '\12323'; // 4.1
|
||||||
|
int c41_13 = '\123\3';
|
||||||
|
int c41_14 = '\777\777';
|
||||||
|
int c41_15 = 'a';
|
||||||
|
|
||||||
|
void misra_4_1()
|
||||||
|
{
|
||||||
|
(void)printf("\x41g"); // 4.1
|
||||||
|
(void)printf("\x41\x42");
|
||||||
|
(void)printf("\x41" "g");
|
||||||
|
}
|
||||||
|
|
||||||
extern int misra_5_3_var_hides_var______31x;
|
extern int misra_5_3_var_hides_var______31x;
|
||||||
void misra_5_3_var_hides_function_31x (void) {}
|
void misra_5_3_var_hides_function_31x (void) {}
|
||||||
|
|
Loading…
Reference in New Issue