Skip to content

Commit 9668fb3

Browse files
committed
SizeOfConstIntMacro qhelp, ql, examples and related qll.
1 parent ad626ac commit 9668fb3

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>If the argument for a <code>sizeof</code> call is a macro that expands to a constant integer type, it is a likely indication that the macro operation may be misused or that the argument was selected by mistake (i.e. typo).</p>
7+
<p>This query detects if the argument for <code>sizeof</code> is a macro that expands to a constant integer value.</p>
8+
<p>NOTE: This rule will ignore multicharacter literal values that are exactly 4 bytes long as it matches the length of <code>int</code> and may be expected.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>Any findings from this rule may indicate that the <code>sizeof</code> is being used incorrectly.</p>
13+
<p>Review the logic of the call.</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>The following example shows a case where <code>sizeof</code> a constant was used instead of the <code>sizeof</code> of a structure by mistake as the names are similar.</p>
18+
<sample src="SizeOfConstIntMacroBad.c" />
19+
20+
<p>In this example, the fix is to replace the argument for <code>sizeof</code> with the structure name.</p>
21+
22+
<sample src="SizeOfConstIntMacroGood.c" />
23+
24+
</example>
25+
26+
</qhelp>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @id cpp/sizeof/const-int-argument
3+
* @name Passing a constant integer macro to sizeof
4+
* @description The expression passed to sizeof is a macro that expands to an integer constant. A data type was likely intended instead.
5+
* @kind problem
6+
* @problem.severity error
7+
* @precision high
8+
* @tags security
9+
*/
10+
11+
import cpp
12+
import SizeOfTypeUtils
13+
14+
predicate isExprAConstInteger(Expr e, MacroInvocation mi) {
15+
exists(Type type |
16+
type = e.getExplicitlyConverted().getType() and
17+
isTypeDangerousForSizeof(type) and
18+
// Special case for wide-char literals when the compiler doesn't recognize wchar_t (i.e. L'\\', L'\0')
19+
// Accounting for parenthesis "()" around the value
20+
not exists(Macro m | m = mi.getMacro() |
21+
m.getBody().toString().regexpMatch("^[\\s(]*L'.+'[\\s)]*$")
22+
) and
23+
// Special case for token pasting operator
24+
not exists(Macro m | m = mi.getMacro() | m.getBody().toString().regexpMatch("^.*\\s*##\\s*.*$")) and
25+
// Special case for multichar literal integers that are exactly 4 character long (i.e. 'val1')
26+
not exists(Macro m | m = mi.getMacro() |
27+
e.getType().toString() = "int" and
28+
m.getBody().toString().regexpMatch("^'.{4}'$")
29+
) and
30+
e.isConstant()
31+
)
32+
}
33+
34+
int countMacros(Expr e) { result = count(MacroInvocation mi | mi.getExpr() = e | mi) }
35+
36+
predicate isSizeOfExprOperandMacroInvocationAConstInteger(
37+
SizeofExprOperator sizeofExpr, MacroInvocation mi
38+
) {
39+
exists(Expr e |
40+
e = mi.getExpr() and
41+
e = sizeofExpr.getExprOperand() and
42+
isExprAConstInteger(e, mi) and
43+
// Special case for FPs that involve an inner macro that resolves to 0 such as _T('\0')
44+
not exists(int macroCount | macroCount = countMacros(e) |
45+
macroCount > 1 and e.(Literal).getValue().toInt() = 0
46+
)
47+
)
48+
}
49+
50+
from SizeofExprOperator sizeofExpr, MacroInvocation mi
51+
where isSizeOfExprOperandMacroInvocationAConstInteger(sizeofExpr, mi)
52+
select sizeofExpr,
53+
"$@: sizeof of integer macro $@ will always return the size of the underlying integer type.",
54+
sizeofExpr, sizeofExpr.getEnclosingFunction().getName(), mi.getMacro(), mi.getMacro().getName()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#define SOMESTRUCT_ERRNO_THAT_MATTERS 0x8000000d
2+
3+
typedef struct {
4+
int a;
5+
bool b;
6+
} SOMESTRUCT_THAT_MATTERS;
7+
8+
//bug, the code is using SOMESTRUCT_ERRNO_THAT_MATTERS by mistake instead of SOMESTRUCT_THAT_MATTERS
9+
if (somedata.length >= sizeof(SOMESTRUCT_ERRNO_THAT_MATTERS))
10+
{
11+
/// Do something
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#define SOMESTRUCT_ERRNO_THAT_MATTERS 0x8000000d
2+
3+
typedef struct {
4+
int a;
5+
bool b;
6+
} SOMESTRUCT_THAT_MATTERS;
7+
8+
if (somedata.length >= sizeof(SOMESTRUCT_THAT_MATTERS))
9+
{
10+
/// Do something
11+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import cpp
2+
3+
/**
4+
* Holds if `type` is a `Type` that typically should not be used for `sizeof` in macros or function return values.
5+
*/
6+
predicate isTypeDangerousForSizeof(Type type) {
7+
(
8+
type instanceof IntegralOrEnumType and
9+
// ignore string literals
10+
not type instanceof WideCharType and
11+
not type instanceof CharType
12+
)
13+
}
14+
15+
/**
16+
* Holds if `type` is a `Type` that typically should not be used for `sizeof` in macros or function return values.
17+
* This predicate extends the types detected in exchange of precision.
18+
* For higher precision, please use `isTypeDangerousForSizeof`
19+
*/
20+
predicate isTypeDangerousForSizeofLowPrecision(Type type) {
21+
(
22+
// UINT8/BYTE are typedefs to char, so we treat them separately.
23+
// WCHAR is sometimes a typedef to UINT16, so we treat it separately too.
24+
type.getName() = "UINT8"
25+
or
26+
type.getName() = "BYTE"
27+
or
28+
not type.getName() = "WCHAR" and
29+
exists(Type ut |
30+
ut = type.getUnderlyingType() and
31+
ut instanceof IntegralOrEnumType and
32+
not ut instanceof WideCharType and
33+
not ut instanceof CharType
34+
)
35+
)
36+
}
37+
38+
/**
39+
* Holds if the `Function` return type is dangerous as input for `sizeof`.
40+
*/
41+
class FunctionWithTypeDangerousForSizeofLowPrecision extends Function {
42+
FunctionWithTypeDangerousForSizeofLowPrecision() {
43+
exists(Type type | type = this.getType() | isTypeDangerousForSizeofLowPrecision(type))
44+
}
45+
}

0 commit comments

Comments
 (0)