Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9439df

Browse files
committed
C++: Added query that detects implicit function declarations
1 parent 06d812a commit c9439df

6 files changed

Lines changed: 200 additions & 7 deletions

File tree

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/**
2+
* @name Implicit function declaration
3+
* @description An implicitly declared function is assumed to take no
4+
* arguments and return an integer. If this assumption does not hold, it
5+
* may lead to unpredictable behavior.
6+
* @kind problem
7+
* @problem.severity warning
8+
* @precision medium
9+
* @id cpp/implicit-function-declaration
10+
* @tags correctness
11+
* maintainability
12+
*/
13+
14+
import cpp
15+
16+
pragma[inline]
17+
predicate arithTypesMatch(Type arg, Type parm) {
18+
arg = parm
19+
or
20+
arg.getSize() = parm.getSize() and
21+
(
22+
arg instanceof IntegralOrEnumType and
23+
parm instanceof IntegralOrEnumType
24+
or
25+
arg instanceof FloatingPointType and
26+
parm instanceof FloatingPointType
27+
)
28+
}
29+
30+
pragma[inline]
31+
predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
32+
// arithmetic types
33+
arithTypesMatch(arg, parm)
34+
or
35+
// conversion to/from pointers to void is allowed
36+
arg instanceof VoidType
37+
or
38+
parm instanceof VoidType
39+
}
40+
41+
pragma[inline]
42+
predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
43+
nestedPointerArgTypeMayBeUsed(arg, parm)
44+
or
45+
// nested pointers
46+
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
47+
parm.(PointerType).getBaseType().getUnspecifiedType())
48+
or
49+
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
50+
parm.(PointerType).getBaseType().getUnspecifiedType())
51+
}
52+
53+
pragma[inline]
54+
predicate argTypeMayBeUsed(Type arg, Type parm) {
55+
// arithmetic types
56+
arithTypesMatch(arg, parm)
57+
or
58+
// pointers to compatible types
59+
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
60+
parm.(PointerType).getBaseType().getUnspecifiedType())
61+
or
62+
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
63+
parm.(PointerType).getBaseType().getUnspecifiedType())
64+
or
65+
// C11 arrays
66+
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
67+
parm.(ArrayType).getBaseType().getUnspecifiedType())
68+
or
69+
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
70+
parm.(ArrayType).getBaseType().getUnspecifiedType())
71+
}
72+
73+
// This predicate holds whenever expression `arg` may be used to initialize
74+
// function parameter `parm` without need for run-time conversion.
75+
pragma[inline]
76+
predicate argMayBeUsed(Expr arg, ParameterDeclarationEntry pde) {
77+
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), pde.getUnspecifiedType())
78+
}
79+
80+
// True if this file (or header) was compiled as a C file
81+
predicate isCompiledAsC(File f) {
82+
f.compiledAsC()
83+
or
84+
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
85+
}
86+
87+
// True if function was ()-declared, but not (void)-declared or K&R-defined
88+
// or implicitly declared (i.e., lacking a prototype)
89+
predicate hasZeroParamDeclTooMany(Function f) {
90+
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
91+
not fde.isImplicit() and
92+
not fde.hasVoidParamList() and
93+
fde.getNumberOfParameters() = 0 and
94+
not fde.isDefinition()
95+
)
96+
}
97+
98+
// True if function was ()-declared, but not (void)-declared or K&R-defined
99+
predicate hasZeroParamDecl(Function f) {
100+
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
101+
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
102+
)
103+
}
104+
105+
bindingset[name]
106+
predicate notAlreadyReported(string name, FunctionCall fc) {
107+
forall(FunctionDeclarationEntry fdeEx |
108+
fdeEx.getName() = name and
109+
not fdeEx.isImplicit()
110+
|
111+
// only report if not reported by cpp/futile-params
112+
(
113+
fdeEx.getNumberOfParameters() >= fc.getNumberOfArguments()
114+
or
115+
exists(Function f |
116+
f = fc.getTarget() and
117+
not exists(f.getBlock())
118+
or
119+
not hasZeroParamDeclTooMany(f)
120+
)
121+
) and
122+
// only report if not reported by cpp/too-few-arguments
123+
(
124+
fdeEx.getNumberOfParameters() <= fc.getNumberOfArguments()
125+
or
126+
exists(Function f |
127+
f.isVarargs() or
128+
f instanceof BuiltInFunction or
129+
not hasZeroParamDecl(f)
130+
)
131+
) and
132+
// only report if not reported by cpp/mistyped-function-arguments
133+
(
134+
not hasZeroParamDecl(fc.getTarget())
135+
or
136+
forall(ParameterDeclarationEntry pde |
137+
pde = fdeEx.getAParameterDeclarationEntry() and
138+
pde.getIndex() < fc.getNumberOfArguments()
139+
|
140+
argMayBeUsed(fc.getArgument(pde.getIndex()), pde)
141+
)
142+
)
143+
)
144+
}
145+
146+
predicate sameLocation(Location loc1, Location loc2) {
147+
loc1.getFile() = loc2.getFile() and
148+
loc1.getStartLine() = loc2.getStartLine() and
149+
loc1.getStartColumn() = loc2.getStartColumn()
150+
}
151+
152+
from FunctionDeclarationEntry fdeIm, FunctionCall fc
153+
where
154+
isCompiledAsC(fdeIm.getFile()) and
155+
fdeIm.isImplicit() and
156+
sameLocation(fdeIm.getLocation(), fc.getLocation()) and
157+
notAlreadyReported(fdeIm.getName(), fc)
158+
select fc, "Function call implicitly declares $@", fc, fc.toString()
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| test.c:28:3:28:12 | call to undeclared | Function call implicitly declares $@ | test.c:28:3:28:12 | call to undeclared | call to undeclared |
2+
| test.c:31:3:31:19 | call to not_yet_declared1 | Function call implicitly declares $@ | test.c:31:3:31:19 | call to not_yet_declared1 | call to not_yet_declared1 |
3+
| test.c:32:3:32:19 | call to not_yet_declared2 | Function call implicitly declares $@ | test.c:32:3:32:19 | call to not_yet_declared2 | call to not_yet_declared2 |
4+
| test.c:43:3:43:27 | call to not_declared_defined_with | Function call implicitly declares $@ | test.c:43:3:43:27 | call to not_declared_defined_with | call to not_declared_defined_with |
5+
| test.c:54:3:54:21 | call to defined_with_double | Function call implicitly declares $@ | test.c:54:3:54:21 | call to defined_with_double | call to defined_with_double |
6+
| test.c:66:3:66:22 | call to defined_with_ptr_ptr | Function call implicitly declares $@ | test.c:66:3:66:22 | call to defined_with_ptr_ptr | call to defined_with_ptr_ptr |
7+
| test.c:68:3:68:22 | call to defined_with_ptr_arr | Function call implicitly declares $@ | test.c:68:3:68:22 | call to defined_with_ptr_arr | call to defined_with_ptr_arr |
8+
| test.c:132:3:132:22 | call to implicit_declaration | Function call implicitly declares $@ | test.c:132:3:132:22 | call to implicit_declaration | call to implicit_declaration |
9+
| test.c:133:3:133:30 | call to implicit_declaration_k_and_r | Function call implicitly declares $@ | test.c:133:3:133:30 | call to implicit_declaration_k_and_r | call to implicit_declaration_k_and_r |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Likely Bugs/Underspecified Functions/ImplicitFunctionDeclaration.ql

cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818
| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll |
1919
| test.c:60:3:60:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:60:23:60:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:99:35:99:35 | d | double d |
2020
| test.c:61:3:61:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:61:26:61:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:103:44:103:45 | ll | long long ll |
21+
| test.c:137:3:137:27 | call to implicit_declaration_good | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test2.c:8:6:8:30 | implicit_declaration_good | implicit_declaration_good | test.c:137:35:137:38 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test2.c:8:52:8:52 | f | float f |

cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ void test(int *argv[]) {
2525
declared_void(); // GOOD
2626
declared_with(1); // GOOD
2727

28-
undeclared(); // GOOD
28+
undeclared(); // BAD (GOOD for everything except cpp/implicit-function-declaration)
2929
undeclared(1); // GOOD
3030

31-
not_yet_declared1(1); // GOOD
32-
not_yet_declared2(1); // GOOD
31+
not_yet_declared1(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
32+
not_yet_declared2(1); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
3333
not_yet_declared2(ca); // BAD
3434
not_yet_declared2(); // BAD
3535

@@ -40,7 +40,7 @@ void test(int *argv[]) {
4040
declared_empty_defined_with(&x); // BAD
4141
declared_empty_defined_with(3, &x); // BAD
4242

43-
not_declared_defined_with(-1, 0, 2U); // GOOD
43+
not_declared_defined_with(-1, 0, 2U); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
4444
not_declared_defined_with(4LL, 0, 2.5e9f); // BAD
4545

4646
declared_with_pointers(pv, ca); // GOOD
@@ -51,7 +51,7 @@ void test(int *argv[]) {
5151
defined_with_float(2.f); // BAD
5252
defined_with_float(2.0); // BAD
5353

54-
defined_with_double(2.f); // GOOD
54+
defined_with_double(2.f); // BAD (GOOD for everything except for cpp/implicit-function-declaration)
5555
defined_with_double('c'); // BAD
5656

5757
defined_with_long_long('c'); // BAD
@@ -63,9 +63,9 @@ void test(int *argv[]) {
6363
k_and_r_func(2.5, &s); // GOOD
6464

6565
int (*parameterName)[2];
66-
defined_with_ptr_ptr(parameterName); // GOOD
66+
defined_with_ptr_ptr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
6767
defined_with_ptr_ptr(argv); // GOOD
68-
defined_with_ptr_arr(parameterName); // GOOD
68+
defined_with_ptr_arr(parameterName); // // BAD (GOOD for everything except for cpp/implicit-function-declaration)
6969
defined_with_ptr_arr(argv); // GOOD
7070

7171
declared_and_defined_empty(); // GOOD
@@ -124,3 +124,17 @@ int call_k_and_r(int i) {
124124
int will_be_k_and_r(val)
125125
int val;
126126
{ return val + 1; }
127+
128+
extern int extern_definition(double, double*);
129+
130+
void test_implicit_function_declaration(int x, double d) {
131+
int y;
132+
implicit_declaration(1, 2); // BAD
133+
implicit_declaration_k_and_r(1, 2); // BAD
134+
135+
implicit_declaration(1, 2); // GOOD (no longer an implicit declaration)
136+
137+
implicit_declaration_good(1, x, 2.0f); // BAD
138+
139+
y = extern_definition(3.0f, &d); // GOOD
140+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
void implicit_declaration(int x) {}
2+
3+
int implicit_declaration_k_and_r(x) int x;
4+
{
5+
return x;
6+
}
7+
8+
void implicit_declaration_good(int x, int y, float f)
9+
{
10+
}

0 commit comments

Comments
 (0)