misra.py: Handle stdint.h essential types (#2555)

Add stdint.h essential types to misra.py checks. This will fix false
negatives for rules 10.6 and 10.8.
This commit is contained in:
Georgy Komarov 2020-02-27 13:28:48 +03:00 committed by GitHub
parent baa4cee70c
commit 4e5a8fac4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 33 deletions

View File

@ -36,6 +36,14 @@ def grouped(iterable, n):
return zip(*[iter(iterable)] * n) return zip(*[iter(iterable)] * n)
INT_TYPES = ['bool', 'char', 'short', 'int', 'long', 'long long']
STDINT_TYPES = ['%s%d_t' % (n, v) for n, v in itertools.product(
['int', 'uint', 'int_least', 'uint_least', 'int_fast', 'uint_fast'],
[8, 16, 32, 64])]
typeBits = { typeBits = {
'CHAR': None, 'CHAR': None,
'SHORT': None, 'SHORT': None,
@ -46,6 +54,10 @@ typeBits = {
} }
def isUnsignedType(ty):
return ty == 'unsigned' or ty.startswith('uint')
def simpleMatch(token, pattern): def simpleMatch(token, pattern):
for p in pattern.split(' '): for p in pattern.split(' '):
if not token or token.str != p: if not token or token.str != p:
@ -274,9 +286,7 @@ C99_STDLIB_IDENTIFIERS = {
'UINTMAX_MAX', 'PTRDIFF_MIN', 'PTRDIFF_MAX', 'SIG_ATOMIC_MIN', 'UINTMAX_MAX', 'PTRDIFF_MIN', 'PTRDIFF_MAX', 'SIG_ATOMIC_MIN',
'SIG_ATOMIC_MAX', 'SIZE_MAX', 'WCHAR_MIN', 'WCHAR_MAX', 'WINT_MIN', 'SIG_ATOMIC_MAX', 'SIZE_MAX', 'WCHAR_MIN', 'WCHAR_MAX', 'WINT_MIN',
'WINT_MAX', 'INTN_C', 'UINTN_C', 'INTMAX_C', 'UINTMAX_C', 'WINT_MAX', 'INTN_C', 'UINTN_C', 'INTMAX_C', 'UINTMAX_C',
] + ['%s%d_t' % (n, v) for n,v in itertools.product( ] + STDINT_TYPES,
['int', 'uint', 'int_least', 'uint_least', 'int_fast', 'uint_fast'],
[8, 16,32,64])],
# B.18 Input/output # B.18 Input/output
'stdio.h': C90_STDLIB_IDENTIFIERS['stdio.h'] + [ 'stdio.h': C90_STDLIB_IDENTIFIERS['stdio.h'] + [
'mode', 'restrict', 'snprintf', 'vfscanf', 'vscanf', 'mode', 'restrict', 'snprintf', 'vfscanf', 'vscanf',
@ -417,7 +427,7 @@ def getEssentialType(expr):
if expr.variable: if expr.variable:
typeToken = expr.variable.typeStartToken typeToken = expr.variable.typeStartToken
while typeToken and typeToken.isName: while typeToken and typeToken.isName:
if typeToken.str in ('char', 'short', 'int', 'long', 'float', 'double'): if typeToken.str in INT_TYPES + STDINT_TYPES + ['float', 'double']:
return typeToken.str return typeToken.str
typeToken = typeToken.next typeToken = typeToken.next
@ -431,15 +441,10 @@ def getEssentialType(expr):
e2 = getEssentialType(expr.astOperand2) e2 = getEssentialType(expr.astOperand2)
if not e1 or not e2: if not e1 or not e2:
return None return None
types = ['bool', 'char', 'short', 'int', 'long', 'long long'] if bitsOfEssentialType(e2) >= bitsOfEssentialType(e1):
try: return e2
i1 = types.index(e1) else:
i2 = types.index(e2) return e1
if i2 >= i1:
return types[i2]
return types[i1]
except ValueError:
return None
elif expr.str == "~": elif expr.str == "~":
e1 = getEssentialType(expr.astOperand1) e1 = getEssentialType(expr.astOperand1)
return e1 return e1
@ -447,20 +452,22 @@ def getEssentialType(expr):
return None return None
def bitsOfEssentialType(expr): def bitsOfEssentialType(ty):
type = getEssentialType(expr) if ty is None:
if type is None:
return 0 return 0
if type == 'char': if ty == 'char':
return typeBits['CHAR'] return typeBits['CHAR']
if type == 'short': if ty == 'short':
return typeBits['SHORT'] return typeBits['SHORT']
if type == 'int': if ty == 'int':
return typeBits['INT'] return typeBits['INT']
if type == 'long': if ty == 'long':
return typeBits['LONG'] return typeBits['LONG']
if type == 'long long': if ty == 'long long':
return typeBits['LONG_LONG'] return typeBits['LONG_LONG']
for sty in STDINT_TYPES:
if ty == sty:
return int(''.join(filter(str.isdigit, sty)))
return 0 return 0
@ -1335,9 +1342,9 @@ class MisraChecker:
if not e1 or not e2: if not e1 or not e2:
continue continue
if token.str in ('<<', '>>'): if token.str in ('<<', '>>'):
if e1 != 'unsigned': if not isUnsignedType(e1):
self.reportError(token, 10, 1) self.reportError(token, 10, 1)
elif e2 != 'unsigned' and not token.astOperand2.isNumber: elif not isUnsignedType(e2) and not token.astOperand2.isNumber:
self.reportError(token, 10, 1) self.reportError(token, 10, 1)
elif token.str in ('~', '&', '|', '^'): elif token.str in ('~', '&', '|', '^'):
e1_et = getEssentialType(token.astOperand1) e1_et = getEssentialType(token.astOperand1)
@ -1392,16 +1399,13 @@ class MisraChecker:
if not vt2 or vt2.pointer > 0: if not vt2 or vt2.pointer > 0:
continue continue
try: try:
intTypes = ['char', 'short', 'int', 'long', 'long long']
index1 = intTypes.index(vt1.type)
if isCast(token.astOperand2): if isCast(token.astOperand2):
e = vt2.type e = vt2.type
else: else:
e = getEssentialType(token.astOperand2) e = getEssentialType(token.astOperand2)
if not e: if not e:
continue continue
index2 = intTypes.index(e) if bitsOfEssentialType(vt1.type) > bitsOfEssentialType(e):
if index1 > index2:
self.reportError(token, 10, 6) self.reportError(token, 10, 6)
except ValueError: except ValueError:
pass pass
@ -1431,13 +1435,10 @@ class MisraChecker:
self.reportError(token, 10, 8) self.reportError(token, 10, 8)
else: else:
try: try:
intTypes = ['char', 'short', 'int', 'long', 'long long']
index1 = intTypes.index(token.valueType.type)
e = getEssentialType(token.astOperand1) e = getEssentialType(token.astOperand1)
if not e: if not e:
continue continue
index2 = intTypes.index(e) if bitsOfEssentialType(token.valueType.type) > bitsOfEssentialType(e):
if index1 > index2:
self.reportError(token, 10, 8) self.reportError(token, 10, 8)
except ValueError: except ValueError:
pass pass
@ -1625,7 +1626,7 @@ class MisraChecker:
maxval = val.intvalue maxval = val.intvalue
if maxval == 0: if maxval == 0:
continue continue
sz = bitsOfEssentialType(token.astOperand1) sz = bitsOfEssentialType(getEssentialType(token.astOperand1))
if sz <= 0: if sz <= 0:
continue continue
if maxval >= sz: if maxval >= sz:

View File

@ -267,7 +267,7 @@ void misra_10_1_ternary()
int8_t i8; int8_t i8;
int16_t i16; int16_t i16;
a = ui16 << ui16; a = ui16 << ui16; // 10.6
a = ui16 << (get_bool(42) ? ui16 : ui16); a = ui16 << (get_bool(42) ? ui16 : ui16);
a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); // 10.4 a = ui16 << (get_bool(42) ? ui16 : (get_bool(34) ? ui16 : ui16)); // 10.4
a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); // 10.4 a = ui16 << (get_bool(42) ? (get_bool(34) ? ui16 : ui16) : ui16); // 10.4
@ -305,6 +305,10 @@ void misra_10_6(u8 x, u32 a, u32 b, char c1, char c2) {
u32 c = ( u16) ( u32 a + u32 b ); //10.6 u32 c = ( u16) ( u32 a + u32 b ); //10.6
s32 i = c1 - c2; // FIXME: False positive for 10.6 (this is compliant). Trac #9488 s32 i = c1 - c2; // FIXME: False positive for 10.6 (this is compliant). Trac #9488
} }
void misra_10_6_1(uint32_t *a, uint16_t b, uint16_t c)
{
*a = b + c ; // 10.6
}
void misra_10_8(u8 x, s32 a, s32 b) { void misra_10_8(u8 x, s32 a, s32 b) {
y = (u16)x; y = (u16)x;