|
1 | 1 | import cpp |
2 | 2 |
|
3 | 3 | /** |
4 | | - * Holds if `type` is a `Type` that typically should not be used for `sizeof` in macros or function return values. |
| 4 | + * Determines if the sizeOfExpr is ignorable. |
5 | 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 |
| 6 | +predicate ignorableSizeof(SizeofExprOperator sizeofExpr) { |
| 7 | + // a common pattern found is to sizeof a binary operation to check a type |
| 8 | + // to then perfomr an onperaiton for a 32 or 64 bit type. |
| 9 | + // these cases often look like sizeof(x) >=4 |
| 10 | + // more generally we see binary operations frequently used in different type |
| 11 | + // checks, where the sizeof is part of some comparison operation of a switch statement guard. |
| 12 | + // sizeof as an argument is also similarly used, but seemingly less frequently. |
| 13 | + exists(ComparisonOperation comp | comp.getAnOperand() = sizeofExpr) |
| 14 | + or |
| 15 | + exists(ConditionalStmt s | s.getControllingExpr() = sizeofExpr) |
| 16 | + or |
| 17 | + // another common practice is to use bit-wise operations in sizeof to allow the compiler to |
| 18 | + // 'pack' the size appropriate but get the size of the result out of a sizeof operation. |
| 19 | + sizeofExpr.getExprOperand() instanceof BinaryBitwiseOperation |
| 20 | + or |
| 21 | + // Known intentional misuses in corecrt_math.h |
| 22 | + // Windows SDK corecrt_math.h defines a macro _CLASS_ARG that |
| 23 | + // intentionally misuses sizeof to determine the size of a floating point type. |
| 24 | + // Explicitly ignoring any hit in this macro. |
| 25 | + exists(MacroInvocation mi | |
| 26 | + mi.getMacroName() = "_CLASS_ARG" and |
| 27 | + mi.getMacro().getFile().getBaseName() = "corecrt_math.h" and |
| 28 | + mi.getAnExpandedElement() = sizeofExpr |
12 | 29 | ) |
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 | | - ) |
| 30 | + or |
| 31 | + // the linux minmax.h header has macros that intentionally miuse sizeof, |
| 32 | + // for type checking, see __typecheck |
| 33 | + // This code has been observed in kernel.h as well. |
| 34 | + // Ignoring cases in linux build_bug.h and bug.h see BUILD_BUG_ON_INVALID |
| 35 | + // Ignoring cases of uses of FP_XSTATE_MAGIC2_SIZE found in sigcontext.h |
| 36 | + // which uses sizeof a constant as a way to get an architecturally agnostic size by |
| 37 | + // using the special magic number constant already defined |
| 38 | + exists(MacroInvocation mi | |
| 39 | + ( |
| 40 | + // Generally ignore anything from these linux headers |
| 41 | + mi.getMacro().getFile().getBaseName() in [ |
| 42 | + "minmax.h", "build_bug.h", "kernel.h", "bug.h", "sigcontext.h" |
| 43 | + ] and |
| 44 | + mi.getMacro().getFile().getRelativePath().toLowerCase().matches("%linux%") |
| 45 | + or |
| 46 | + // Sometimes the same macros are copied into other files, so also check the macro name |
| 47 | + // this is redundant, but the first check above blocks all macros in these headers |
| 48 | + // while this second check blocks any copies of these specific macros if found elsewhere. |
| 49 | + mi.getMacroName() = "FP_XSTATE_MAGIC2_SIZE" |
| 50 | + or |
| 51 | + mi.getMacroName() = "__typecheck" |
| 52 | + ) and |
| 53 | + mi.getAnExpandedElement() = sizeofExpr |
| 54 | + ) |
| 55 | + or |
| 56 | + // if the operand is a macro invocation of something resembling "null" |
| 57 | + // assume sizeof is intended for strings, and ignore as this is a |
| 58 | + // potential null pointer issue, not a misuse of sizeof. |
| 59 | + exists(MacroInvocation mi | |
| 60 | + mi.getAnExpandedElement() = sizeofExpr.getExprOperand() and |
| 61 | + mi.getMacroName().toLowerCase().matches("%null%") |
| 62 | + ) |
| 63 | + or |
| 64 | + // LLVM has known test cases under gcc-torture, ignore any hits under any matching directory |
| 65 | + // see for example 20020226-1.c |
| 66 | + sizeofExpr.getFile().getRelativePath().toLowerCase().matches("%gcc-%torture%") |
| 67 | + or |
| 68 | + // The user seems to be ignoring the output of the sizeof by casting the sizeof to void |
| 69 | + // this has been observed as a common pattern in assert macros (I believe for disabling asserts in release builds). |
| 70 | + // NOTE: having to check the conversion's type rather than the conversion itself |
| 71 | + // i.e., checking if VoidConversion |
| 72 | + // as nesting in parenthesis creats a ParenConversion |
| 73 | + sizeofExpr.getExplicitlyConverted().getUnspecifiedType() instanceof VoidType |
| 74 | + or |
| 75 | + // A common macro seen that gets size of arguments, considered ignorable |
| 76 | + exists(MacroInvocation mi | |
| 77 | + mi.getMacroName() = "_SDT_ARGSIZE" and mi.getAnExpandedElement() = sizeofExpr |
35 | 78 | ) |
36 | 79 | } |
37 | 80 |
|
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 | | - } |
| 81 | +class CandidateSizeofCall extends SizeofExprOperator { |
| 82 | + CandidateSizeofCall() { not ignorableSizeof(this) } |
45 | 83 | } |
0 commit comments