Skip to content

Commit 889fdb3

Browse files
Checks: Added new MISRA04_17.4: Array indexing shall be the only allowed form of pointer arithmetic [autosync]
1 parent 328ebe6 commit 889fdb3

5 files changed

Lines changed: 123 additions & 10 deletions

File tree

CodeCheck/Published Standards/MISRA C 2023/MISRA23_18.4/check.upy

Lines changed: 75 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import re
66

77
ERR1 = "The %1 operator was applied to an expression of pointer type"
8+
# Strict mode (MISRA C 2004 17.4): indexing only allowed on array-typed objects
9+
ERR2 = "Array indexing was applied to %1, which is not defined as an array type"
810

911
# The ID for the check
1012
def ids():
1113
return ('MISRA23_18.4', 'MISRA12_18.4', 'CPP_P062',
12-
'MISRA25_18.4'
14+
'MISRA25_18.4', 'MISRA04_17.4'
1315
)
1416

1517
# The short name of the check
@@ -24,6 +26,8 @@ All Checks/Language Specific/C and C++/Pointers/
2426
The +, -, += and -= operators should not be applied to an expression of pointer
2527
type""",
2628
'MISRA25_18.4': 'Published Standards/MISRA C 2025/18.4 The +, -, += and -= operators should not be applied to an expression of pointer type',
29+
'MISRA04_17.4': 'Published Standards/MISRA-C 2004/' + """\
30+
17.4 Array indexing shall be the only allowed form of pointer arithmetic""",
2731
}[id]
2832

2933

@@ -56,6 +60,12 @@ def tags(id):
5660
'Category: Advisory',
5761
'Pointers',
5862
],
63+
'MISRA04_17.4': [
64+
'Language: C',
65+
'Standard: MISRA C 2004',
66+
'Category: Required',
67+
'Pointers',
68+
],
5969
}.get(id)
6070

6171
# The long description of the check
@@ -201,6 +211,42 @@ void fn4 ( void )
201211
fn3 ( a1, a2 );
202212
fn3 ( &data, &a2[ 4 ] );
203213
}</code></pre>
214+
""",
215+
216+
'MISRA04_17.4': """\
217+
<p>Array indexing is the only acceptable form of pointer arithmetic, because it
218+
is clearer and hence less error prone than pointer manipulation. This rule bans
219+
the explicit calculation of pointer values. Array indexing shall only be applied
220+
to objects defined as an array type. Any explicitly calculated pointer value has
221+
the potential to access unintended or invalid memory addresses. Pointers may go
222+
out of bounds of arrays or structures, or may even point to effectively
223+
arbitrary locations. See also Rule 21.1.</p>
224+
<pre><code language="C++">void my_fn(uint8_t * p1, uint8_t p2[])
225+
{
226+
uint8_t index = 0U;
227+
uint8_t * p3;
228+
uint8_t * p4;
229+
*p1 = 0U;
230+
p1 ++; /* not compliant - pointer increment */
231+
p1 = p1 + 5; /* not compliant - pointer increment */
232+
p1[5] = 0U; /* not compliant - p1 was not declared as an array */
233+
p3 = &amp;p1[5]; /* not compliant - p1 was not declared as an array */
234+
p2[0] = 0U;
235+
index ++;
236+
index = index + 5U;
237+
p2[index] = 0U; /* compliant */
238+
p4 = &amp;p2[5]; /* compliant */
239+
}
240+
241+
uint8_t a1[16];
242+
uint8_t a2[16];
243+
my_fn(a1, a2);
244+
my_fn(&amp;a1[4], &amp;a2[4]);
245+
uint8_t a[10];
246+
uint8_t * p;
247+
p = a;
248+
*(p+5) = 0U; /* not compliant */
249+
p[5] = 0U; /* not compliant */</code></pre>
204250
""",
205251
}[id]
206252

@@ -210,11 +256,27 @@ def test_entity(file):
210256
def test_language(language):
211257
return language == 'C++'
212258

259+
def define_options(check):
260+
# MISRA C 2004 17.4 is stricter than 18.4: it also bans pointer ++/-- and
261+
# indexing applied to objects not defined as an array type. Default on only
262+
# for MISRA04_17.4.
263+
strict = check.id() == 'MISRA04_17.4'
264+
check.option().checkbox('strict',
265+
'Also flag pointer ++/-- and array indexing on objects not defined as '
266+
'an array type (MISRA C 2004 Rule 17.4)',
267+
strict)
268+
213269
def check(check, file):
214270
lexer = None
215271
lexers = {}
272+
strict = check.option().lookup('strict')
216273
# Operators to check around pointer usage
217274
operators = ['+', '-', '+=', '-=']
275+
# In strict mode also flag ++/--; these appear as Modify references
276+
useKinds = 'Deref Setby, Useby'
277+
if strict:
278+
operators = operators + ['++', '--']
279+
useKinds = useKinds + ', Modifyby'
218280

219281
# Get all references to defined objects or parameters in the file
220282
refs = file.filerefs('Define', 'Object, Parameter')
@@ -224,8 +286,12 @@ def check(check, file):
224286
if '*' not in str(ref.ent().freetext("underlyingtype")):
225287
continue
226288

289+
# An object defined as an array type (including a decayed array
290+
# parameter such as p2[]) keeps '[' in its declared type
291+
arrayDeclared = '[' in str(ref.ent().type())
292+
227293
# Get all dereference and usage references of the pointer
228-
useRefs = ref.ent().refs('Deref Setby, Useby')
294+
useRefs = ref.ent().refs(useKinds)
229295

230296
for useRef in useRefs:
231297
# Reuse lexer for each file to avoid reloading
@@ -241,8 +307,14 @@ def check(check, file):
241307
prevLex = lexeme.previous(True, True)
242308
nextLex = lexeme.next(True, True)
243309

244-
# Skip if followed by array indexing
310+
# Handle array indexing
245311
if nextLex and nextLex.text() == '[':
312+
# In strict mode, indexing is only allowed on objects
313+
# defined as an array type
314+
if strict and not arrayDeclared:
315+
check.violation(useRef.ent(), useRef.file(),
316+
useRef.line(), useRef.column(), ERR2,
317+
ref.ent().name())
246318
continue
247319

248320
# Skip if followed by member access (-> or .)

CodeCheck/Published Standards/MISRA C 2023/MISRA23_18.4/test.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ void fn1 ( void )
88
a[ index ] = 0U; /* UndCC_Valid */
99
ptr = &a[ 5 ]; /* UndCC_Valid */
1010
ptr = a;
11-
ptr++; /* UndCC_Valid - increment operator not + */
11+
ptr++; /* UndCC_Violation(strict) - increment operator not + */
1212
*( ptr + 5 ) = 0U; /* UndCC_Violation */
13-
ptr[ 5 ] = 0U; /* UndCC_Valid */
13+
ptr[ 5 ] = 0U; /* UndCC_Violation(strict) - ptr not declared as an array */
1414
}
1515
void fn2 ( void )
1616
{
@@ -23,18 +23,18 @@ void fn2 ( void )
2323
uint8_t *row = array_2_2[ i ];
2424
for ( j = 0U; j < 2U; j++ )
2525
{
26-
sum += row[ j ]; /* UndCC_Valid */
26+
sum += row[ j ]; /* UndCC_Violation(strict) - row not declared as an array */
2727
}
2828
}
2929
}
3030
void fn3 ( uint8_t *p1, uint8_t p2[ ] )
3131
{
32-
p1++; /* UndCC_Valid */
32+
p1++; /* UndCC_Violation(strict) */
3333
p1 = p1 + 5; /* UndCC_Violation */
34-
p1[ 5 ] = 0U; /* UndCC_Valid */
35-
p2++; /* UndCC_Valid */
34+
p1[ 5 ] = 0U; /* UndCC_Violation(strict) - p1 not declared as an array */
35+
p2++; /* UndCC_Violation(strict) */
3636
p2 = p2 + 3; /* UndCC_Violation */
37-
p2[ 3 ] = 0U; /* UndCC_Valid */
37+
p2[ 3 ] = 0U; /* UndCC_Valid - p2 declared as an array */
3838
}
3939
uint8_t a1[ 16 ];
4040
uint8_t a2[ 16 ];
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// MISRA C 2004 Rule 17.4 example (strict mode)
2+
3+
#include <stdint.h>
4+
5+
void my_fn(uint8_t * p1, uint8_t p2[])
6+
{
7+
uint8_t index = 0U;
8+
uint8_t * p3;
9+
uint8_t * p4;
10+
*p1 = 0U;
11+
p1 ++; /* UndCC_Violation(strict) - pointer increment */
12+
p1 = p1 + 5; /* UndCC_Violation - pointer arithmetic */
13+
p1[ 5 ] = 0U; /* UndCC_Violation(strict) - p1 not declared as an array */
14+
p3 = &p1[ 5 ]; /* UndCC_Violation(strict) - p1 not declared as an array */
15+
p2[ 0 ] = 0U; /* UndCC_Valid */
16+
index ++; /* UndCC_Valid - index is not a pointer */
17+
index = index + 5U; /* UndCC_Valid - index is not a pointer */
18+
p2[ index ] = 0U; /* UndCC_Valid */
19+
p4 = &p2[ 5 ]; /* UndCC_Valid */
20+
(void) p3;
21+
(void) p4;
22+
}
23+
24+
void my_caller(void)
25+
{
26+
uint8_t a1[ 16 ];
27+
uint8_t a2[ 16 ];
28+
uint8_t a[ 10 ];
29+
uint8_t * p;
30+
my_fn( a1, a2 );
31+
my_fn( &a1[ 4 ], &a2[ 4 ] );
32+
p = a;
33+
*( p + 5 ) = 0U; /* UndCC_Violation - pointer arithmetic */
34+
p[ 5 ] = 0U; /* UndCC_Violation(strict) - p not declared as an array */
35+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"strict": false
3+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"strict": true
3+
}

0 commit comments

Comments
 (0)