C++: Add support for more clang builtins

This commit is contained in:
Jeroen Ketema
2024-08-27 13:53:06 +02:00
parent 7f8e6bf574
commit 9e861ce717
18 changed files with 9938 additions and 432 deletions

View File

@@ -0,0 +1,17 @@
class Expr extends @expr {
string toString() { none() }
}
class Location extends @location_expr {
string toString() { none() }
}
predicate isExprWithNewBuiltin(Expr expr) {
exists(int kind | exprs(expr, kind, _) | 385 <= kind and kind <= 388)
}
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind
select expr, kind_new, location

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
class Expr extends @expr {
string toString() { none() }
}
class Type extends @type {
string toString() { none() }
}
from Expr expr, Type type, int kind
where
sizeof_bind(expr, type) and
exprs(expr, kind, _) and
(kind = 93 or kind = 94)
select expr, type

View File

@@ -0,0 +1,4 @@
description: Add new builtin operations
compatibility: partial
exprs.rel: run exprs.qlo
sizeof_bind.rel: run sizeof_bind.qlo

View File

@@ -1885,3 +1885,59 @@ class BuiltInOperationIsWinInterface extends BuiltInOperation, @iswininterface {
override string getAPrimaryQlClass() { result = "BuiltInOperationIsWinInterface" }
}
/**
* A C++ `__is_trivially_equality_comparable` built-in operation.
*
* Returns `true` if comparing two objects of type `_Tp` is equivalent to
* comparing their object representations.
*
* ```
* template<typename _Tp>
* struct is_trivially_equality_comparable
* : public integral_constant<bool, __is_trivially_equality_comparable(_Tp)>
* {};
* ```
*/
class BuiltInOperationIsTriviallyEqualityComparable extends BuiltInOperation,
@istriviallyequalitycomparable
{
override string toString() { result = "__is_trivially_equality_comparable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyEqualityComparable" }
}
/**
* A C++ `__is_scoped_enum` built-in operation (used by some implementations
* of the `<type_traits>` header).
*
* Returns `true` if a type is a scoped enum.
* ```
* template<typename _Tp>
* constexpr bool is_scoped_enum = __is_scoped_enum(_Tp);
* ```
*/
class BuiltInOperationIsScopedEnum extends BuiltInOperation, @isscopedenum {
override string toString() { result = "__is_scoped_enum" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsScopedEnum" }
}
/**
* A C++ `__is_trivially_relocatable` built-in operation.
*
* Returns `true` if moving an object of type `_Tp` is equivalent to
* copying the underlying bytes.
*
* ```
* template<typename _Tp>
* struct is_trivially_relocatable
* : public integral_constant<bool, __is_trivially_relocatable(_Tp)>
* {};
* ```
*/
class BuiltInOperationIsTriviallyRelocatable extends BuiltInOperation, @istriviallyrelocatable {
override string toString() { result = "__is_trivially_relocatable" }
override string getAPrimaryQlClass() { result = "BuiltInOperationIsTriviallyRelocatable" }
}

View File

@@ -791,6 +791,53 @@ class AlignofTypeOperator extends AlignofOperator {
override string toString() { result = "alignof(" + this.getTypeOperand().getName() + ")" }
}
/**
* A C++ `__datasizeof` expression (used by some implementations
* of the `<type_traits>` header).
*
* The `__datasizeof` expression behaves identical to `sizeof` except
* that the result ignores tail padding.
*/
class DatasizeofOperator extends Expr, @datasizeof {
override int getPrecedence() { result = 16 }
}
/**
* A C++ `__datasizeof` expression whose operand is an expression.
*/
class DatasizeofExprOperator extends DatasizeofOperator {
DatasizeofExprOperator() { exists(this.getChild(0)) }
override string getAPrimaryQlClass() { result = "DatasizeofExprOperator" }
/** Gets the contained expression. */
Expr getExprOperand() { result = this.getChild(0) }
override string toString() { result = "sizeof(<expr>)" }
override predicate mayBeImpure() { this.getExprOperand().mayBeImpure() }
override predicate mayBeGloballyImpure() { this.getExprOperand().mayBeGloballyImpure() }
}
/**
* A C++ `__datasizeof` expression whose operand is a type name.
*/
class DatasizeofTypeOperator extends DatasizeofOperator {
DatasizeofTypeOperator() { sizeof_bind(underlyingElement(this), _) }
override string getAPrimaryQlClass() { result = "DatasizeofTypeOperator" }
/** Gets the contained type. */
Type getTypeOperand() { sizeof_bind(underlyingElement(this), unresolveElement(result)) }
override string toString() { result = "sizeof(" + this.getTypeOperand().getName() + ")" }
override predicate mayBeImpure() { none() }
override predicate mayBeGloballyImpure() { none() }
}
/**
* A C/C++ array to pointer conversion.
*

View File

@@ -304,6 +304,8 @@ class Expr extends StmtParent, @expr {
e instanceof NoExceptExpr
or
e instanceof AlignofOperator
or
e instanceof DatasizeofOperator
)
or
exists(Decltype d | d.getExpr() = this.getParentWithConversions*())

View File

@@ -1788,6 +1788,10 @@ case @expr.kind of
| 382 = @isvalidwinrttype
| 383 = @iswinclass
| 384 = @iswininterface
| 385 = @istriviallyequalitycomparable
| 386 = @isscopedenum
| 387 = @istriviallyrelocatable
| 388 = @datasizeof
;
@var_args_expr = @vastartexpr
@@ -1901,6 +1905,9 @@ case @expr.kind of
| @isvalidwinrttype
| @iswinclass
| @iswininterface
| @istriviallyequalitycomparable
| @isscopedenum
| @istriviallyrelocatable
;
new_allocated_type(
@@ -1961,7 +1968,7 @@ uuidof_bind(
int type_id: @type ref
);
@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof;
@runtime_sizeof_or_alignof = @runtime_sizeof | @runtime_alignof | @datasizeof;
sizeof_bind(
unique int expr: @runtime_sizeof_or_alignof ref,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Add new builtin operations
compatibility: backwards

View File

@@ -1,4 +1,4 @@
// semmle-extractor-options: --clang --clang_version 180000
// semmle-extractor-options: --clang --edg --clang_version --edg 190000
struct S {
void f() {}
@@ -108,3 +108,16 @@ bool b_is_unbounded_array2 = __is_unbounded_array(int[42]);
bool b_is_referenceable1 = __is_referenceable(int);
bool b_is_referenceable2 = __is_referenceable(void);
bool b_is_trivially_equality_comparable1 = __is_trivially_equality_comparable(int);
bool b_is_trivially_equality_comparable2 = __is_trivially_equality_comparable(void);
enum class E {
a, b
};
bool b_is_scoped_enum1 = __is_scoped_enum(E);
bool b_is_scoped_enum2 = __is_scoped_enum(int);
bool b_is_trivially_relocatable1 = __is_trivially_relocatable(int);
bool b_is_trivially_relocatable2 = __is_trivially_relocatable(void);

View File

@@ -153,7 +153,21 @@
| clang.cpp:109:28:109:50 | int | | <none> |
| clang.cpp:110:28:110:51 | __is_referenceable | void | 0 |
| clang.cpp:110:28:110:51 | void | | <none> |
| clang.cpp:112:44:112:82 | __is_trivially_equality_comparable | int | 1 |
| clang.cpp:112:44:112:82 | int | | <none> |
| clang.cpp:113:44:113:83 | __is_trivially_equality_comparable | void | 0 |
| clang.cpp:113:44:113:83 | void | | <none> |
| clang.cpp:119:26:119:44 | E | | <none> |
| clang.cpp:119:26:119:44 | __is_scoped_enum | E | 1 |
| clang.cpp:120:26:120:46 | __is_scoped_enum | int | 0 |
| clang.cpp:120:26:120:46 | int | | <none> |
| clang.cpp:122:36:122:66 | __is_trivially_relocatable | int | 1 |
| clang.cpp:122:36:122:66 | int | | <none> |
| clang.cpp:123:36:123:67 | __is_trivially_relocatable | void | 0 |
| clang.cpp:123:36:123:67 | void | | <none> |
| file://:0:0:0:0 | 0 | | 0 |
| file://:0:0:0:0 | 0 | | 0 |
| file://:0:0:0:0 | 1 | | 1 |
| file://:0:0:0:0 | 1 | | 1 |
| file://:0:0:0:0 | 2 | | 2 |
| gcc.cpp:3:25:3:25 | 8 | | 8 |

View File

@@ -0,0 +1,30 @@
// semmle-extractor-options: --clang --edg --clang_version --edg 190000
typedef unsigned int size_t;
class MyClass
{
public:
int x;
int *ptr;
char c;
};
void func() {
int i;
char c;
int * ptr;
MyClass mc;
int arr[10];
size_t sz1 = __datasizeof(int);
size_t sz2 = __datasizeof(char);
size_t sz3 = __datasizeof(int *);
size_t sz4 = __datasizeof(MyClass);
size_t sz5 = __datasizeof(i);
size_t sz6 = __datasizeof(c);
size_t sz7 = __datasizeof(ptr);
size_t sz8 = __datasizeof(mc);
size_t sz9 = __datasizeof(arr);
size_t sz10 = __datasizeof(arr[4]);
}

View File

@@ -0,0 +1,10 @@
| datasizeof.cpp:20:15:20:31 | sizeof(int) | DatasizeofTypeOperator.getTypeOperand() | file://:0:0:0:0 | int |
| datasizeof.cpp:21:15:21:32 | sizeof(char) | DatasizeofTypeOperator.getTypeOperand() | file://:0:0:0:0 | char |
| datasizeof.cpp:22:15:22:33 | sizeof(int *) | DatasizeofTypeOperator.getTypeOperand() | file://:0:0:0:0 | int * |
| datasizeof.cpp:23:15:23:35 | sizeof(MyClass) | DatasizeofTypeOperator.getTypeOperand() | datasizeof.cpp:5:7:5:13 | MyClass |
| datasizeof.cpp:24:15:24:29 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:24:28:24:28 | i |
| datasizeof.cpp:25:15:25:29 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:25:28:25:28 | c |
| datasizeof.cpp:26:15:26:31 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:26:28:26:30 | ptr |
| datasizeof.cpp:27:15:27:30 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:27:28:27:29 | mc |
| datasizeof.cpp:28:15:28:31 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:28:28:28:30 | arr |
| datasizeof.cpp:29:16:29:35 | sizeof(<expr>) | DatasizeofExprOperator.getExprOperand() | datasizeof.cpp:29:29:29:34 | access to array |

View File

@@ -0,0 +1,10 @@
import cpp
from DatasizeofOperator sto, string elemDesc, Element e
where
elemDesc = "DatasizeofTypeOperator.getTypeOperand()" and
e = sto.(DatasizeofTypeOperator).getTypeOperand()
or
elemDesc = "DatasizeofExprOperator.getExprOperand()" and
e = sto.(DatasizeofExprOperator).getExprOperand()
select sto, elemDesc, e