Skip to content

Commit 9dc3c2a

Browse files
Use range analysis to detect realloc() where size may be zero, vs, is exactly zero.
1 parent 46b272a commit 9dc3c2a

16 files changed

+113
-36
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* @id c/misra/call-to-realloc-with-size-zero
3-
* @name RULE-1-5: Disallowed size argument value equal to zero in call to realloc
2+
* @id c/misra/size-in-realloc-call-is-zero
3+
* @name RULE-1-5: Size argument value in realloc call is equal zero
44
* @description Invoking realloc with a size argument set to zero is implementation-defined behavior
55
* and declared as an obsolete feature in C18.
66
* @kind problem
@@ -15,11 +15,12 @@
1515
import cpp
1616
import codingstandards.c.misra
1717
import semmle.code.cpp.rangeanalysis.new.RangeAnalysis
18+
import codingstandards.cpp.Realloc
1819

19-
from FunctionCall call, Expr arg
20+
from ReallocCall call
2021
where
21-
not isExcluded(call, Language4Package::callToReallocWithSizeZeroQuery()) and
22-
call.getTarget().hasGlobalOrStdName("realloc") and
23-
arg = call.getArgument(1) and
24-
upperBound(arg) = 0
25-
select arg, "Calling realloc with size zero results in implementation-defined behavior."
22+
not isExcluded(call, Language4Package::sizeInReallocCallIsZeroQuery()) and
23+
call.sizeIsExactlyZero()
24+
select call,
25+
"Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.",
26+
call.getSizeArgument(), call.getSizeArgument().toString()
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @id c/misra/size-in-realloc-call-may-be-zero
3+
* @name RULE-1-5: Size argument value in realloc call may equal zero
4+
* @description Invoking realloc with a size argument set to zero is implementation-defined behavior
5+
* and declared as an obsolete feature in C18.
6+
* @kind problem
7+
* @precision medium
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-1-5
10+
* correctness
11+
* external/misra/c/2012/amendment3
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.cpp.Realloc
18+
19+
from ReallocCall call
20+
where
21+
not isExcluded(call, Language4Package::sizeInReallocCallMayBeZeroQuery()) and
22+
call.sizeMayBeZero() and
23+
not call.sizeIsExactlyZero()
24+
select call,
25+
"Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.",
26+
call.getSizeArgument(), call.getSizeArgument().toString()
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| test.c:36:3:36:6 | call to gets | Call to obsolescent function 'gets'. |
1+
| test.c:37:3:37:6 | call to gets | Call to obsolescent function 'gets'. |

c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected

Lines changed: 0 additions & 1 deletion
This file was deleted.

c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
| test.c:21:1:21:14 | #define true 3 | Invalid define of boolean standard macro 'true'. |
2-
| test.c:22:1:22:15 | #define false 3 | Invalid define of boolean standard macro 'false'. |
3-
| test.c:23:1:23:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. |
4-
| test.c:24:1:24:11 | #undef true | Invalid undefine of boolean standard macro 'true'. |
5-
| test.c:25:1:25:12 | #undef false | Invalid undefine of boolean standard macro 'false'. |
6-
| test.c:26:1:26:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. |
1+
| test.c:22:1:22:14 | #define true 3 | Invalid define of boolean standard macro 'true'. |
2+
| test.c:23:1:23:15 | #define false 3 | Invalid define of boolean standard macro 'false'. |
3+
| test.c:24:1:24:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. |
4+
| test.c:25:1:25:11 | #undef true | Invalid undefine of boolean standard macro 'true'. |
5+
| test.c:26:1:26:12 | #undef false | Invalid undefine of boolean standard macro 'false'. |
6+
| test.c:27:1:27:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test.c:14:3:14:9 | call to realloc | Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:14:14:14:14 | 0 | 0 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-1-5/SizeInReallocCallIsZero.ql
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test.c:15:3:15:9 | call to realloc | Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:15:14:15:15 | p0 | p0 |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-1-5/SizeInReallocCallMayBeZero.ql
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
edges
2-
| test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection |
2+
| test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection |
33
nodes
4-
| test.c:38:16:38:20 | call to fopen indirection | semmle.label | call to fopen indirection |
5-
| test.c:40:15:40:18 | file indirection | semmle.label | file indirection |
4+
| test.c:39:16:39:20 | call to fopen indirection | semmle.label | call to fopen indirection |
5+
| test.c:41:15:41:18 | file indirection | semmle.label | file indirection |
66
subpaths
77
#select
8-
| test.c:40:15:40:18 | file indirection | test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:38:16:38:20 | call to fopen indirection | call to fopen indirection |
8+
| test.c:41:15:41:18 | file indirection | test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:39:16:39:20 | call to fopen indirection | call to fopen indirection |
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| test.c:28:18:28:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. |
1+
| test.c:29:18:29:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. |

c/misra/test/rules/RULE-1-5/test.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
#include "stdio.h"
44
#include "stdlib.h"
55

6-
void f1(void) {
6+
void f1(int p0) {
77
// malloc() is not obsolete, though it is banned by Rule 21.3
88
int *t = malloc(10); // COMPLIANT
99

10-
// Obsolete usage of realloc.
11-
realloc(t, 0); // NON-COMPLIANT
12-
1310
// Valid usage of realloc, but all use of realloc is banned by Rule 21.3
1411
realloc(t, 20); // NON-COMPLIANT
12+
13+
// Obsolete usage of realloc.
14+
realloc(t, 0); // NON-COMPLIANT
15+
realloc(t, p0); // NON-COMPLIANT
1516
}
1617

1718
extern const int g1; // COMPLIANT
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import cpp
2+
import codingstandards.cpp.CodingStandards
3+
4+
class ReallocCall extends FunctionCall {
5+
ReallocCall() { getTarget().hasGlobalOrStdName("realloc") }
6+
7+
Expr getSizeArgument() { result = getArgument(1) }
8+
9+
predicate sizeIsExactlyZero() {
10+
upperBound(getSizeArgument().getConversion()) = 0 and
11+
lowerBound(getSizeArgument().getConversion()) = 0
12+
}
13+
14+
predicate sizeMayBeZero() {
15+
upperBound(getSizeArgument().getConversion()) >= 0 and
16+
lowerBound(getSizeArgument().getConversion()) <= 0
17+
}
18+
}

cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ newtype Language4Query =
1111
TInvalidDefineOrUndefOfStdBoolMacroQuery() or
1212
TCallToObsolescentFunctionGetsQuery() or
1313
TUngetcCallOnStreamPositionZeroQuery() or
14-
TCallToReallocWithSizeZeroQuery()
14+
TSizeInReallocCallMayBeZeroQuery() or
15+
TSizeInReallocCallIsZeroQuery()
1516

1617
predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, string category) {
1718
query =
@@ -78,11 +79,20 @@ predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, s
7879
category = "required"
7980
or
8081
query =
81-
// `Query` instance for the `callToReallocWithSizeZero` query
82-
Language4Package::callToReallocWithSizeZeroQuery() and
82+
// `Query` instance for the `sizeInReallocCallMayBeZero` query
83+
Language4Package::sizeInReallocCallMayBeZeroQuery() and
8384
queryId =
84-
// `@id` for the `callToReallocWithSizeZero` query
85-
"c/misra/call-to-realloc-with-size-zero" and
85+
// `@id` for the `sizeInReallocCallMayBeZero` query
86+
"c/misra/size-in-realloc-call-may-be-zero" and
87+
ruleId = "RULE-1-5" and
88+
category = "required"
89+
or
90+
query =
91+
// `Query` instance for the `sizeInReallocCallIsZero` query
92+
Language4Package::sizeInReallocCallIsZeroQuery() and
93+
queryId =
94+
// `@id` for the `sizeInReallocCallIsZero` query
95+
"c/misra/size-in-realloc-call-is-zero" and
8696
ruleId = "RULE-1-5" and
8797
category = "required"
8898
}
@@ -137,10 +147,17 @@ module Language4Package {
137147
TQueryC(TLanguage4PackageQuery(TUngetcCallOnStreamPositionZeroQuery()))
138148
}
139149

140-
Query callToReallocWithSizeZeroQuery() {
150+
Query sizeInReallocCallMayBeZeroQuery() {
151+
//autogenerate `Query` type
152+
result =
153+
// `Query` type for `sizeInReallocCallMayBeZero` query
154+
TQueryC(TLanguage4PackageQuery(TSizeInReallocCallMayBeZeroQuery()))
155+
}
156+
157+
Query sizeInReallocCallIsZeroQuery() {
141158
//autogenerate `Query` type
142159
result =
143-
// `Query` type for `callToReallocWithSizeZero` query
144-
TQueryC(TLanguage4PackageQuery(TCallToReallocWithSizeZeroQuery()))
160+
// `Query` type for `sizeInReallocCallIsZero` query
161+
TQueryC(TLanguage4PackageQuery(TSizeInReallocCallIsZeroQuery()))
145162
}
146163
}

rule_packages/c/Language4.json

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,22 @@
102102
{
103103
"description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.",
104104
"kind": "problem",
105-
"name": "Disallowed size argument value equal to zero in call to realloc",
105+
"name": "Size argument value in realloc call may equal zero",
106+
"precision": "medium",
107+
"severity": "error",
108+
"short_name": "SizeInReallocCallMayBeZero",
109+
"tags": [
110+
"correctness",
111+
"external/misra/c/2012/amendment3"
112+
]
113+
},
114+
{
115+
"description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.",
116+
"kind": "problem",
117+
"name": "Size argument value in realloc call is equal zero",
106118
"precision": "very-high",
107119
"severity": "error",
108-
"short_name": "CallToReallocWithSizeZero",
120+
"short_name": "SizeInReallocCallIsZero",
109121
"tags": [
110122
"correctness",
111123
"external/misra/c/2012/amendment3"

0 commit comments

Comments
 (0)