diff options
author | Bill Wendling <5993918+bwendling@users.noreply.github.com> | 2024-01-10 15:21:10 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-10 15:21:10 -0800 |
commit | fefdef808c230c79dca2eb504490ad0f17a765a5 (patch) | |
tree | 16ecc9f63f624704bb18dabed96c6a90c17bf799 /clang/lib/CodeGen/CodeGenFunction.h | |
parent | f65265ab779f5c6c571ff702aae5670722765ae0 (diff) | |
download | llvm-fefdef808c230c79dca2eb504490ad0f17a765a5.zip llvm-fefdef808c230c79dca2eb504490ad0f17a765a5.tar.gz llvm-fefdef808c230c79dca2eb504490ad0f17a765a5.tar.bz2 |
[Clang] Implement the 'counted_by' attribute (#76348)
The 'counted_by' attribute is used on flexible array members. The
argument for the attribute is the name of the field member holding the
count of elements in the flexible array. This information is used to
improve the results of the array bound sanitizer and the
'__builtin_dynamic_object_size' builtin. The 'count' field member must
be within the same non-anonymous, enclosing struct as the flexible array
member. For example:
```
struct bar;
struct foo {
int count;
struct inner {
struct {
int count; /* The 'count' referenced by 'counted_by' */
};
struct {
/* ... */
struct bar *array[] __attribute__((counted_by(count)));
};
} baz;
};
```
This example specifies that the flexible array member 'array' has the
number of elements allocated for it in 'count':
```
struct bar;
struct foo {
size_t count;
/* ... */
struct bar *array[] __attribute__((counted_by(count)));
};
```
This establishes a relationship between 'array' and 'count';
specifically that 'p->array' must have *at least* 'p->count' number of
elements available. It's the user's responsibility to ensure that this
relationship is maintained throughout changes to the structure.
In the following, the allocated array erroneously has fewer elements
than what's specified by 'p->count'. This would result in an
out-of-bounds access not not being detected:
```
struct foo *p;
void foo_alloc(size_t count) {
p = malloc(MAX(sizeof(struct foo),
offsetof(struct foo, array[0]) + count *
sizeof(struct bar *)));
p->count = count + 42;
}
```
The next example updates 'p->count', breaking the relationship
requirement that 'p->array' must have at least 'p->count' number of
elements available:
```
void use_foo(int index, int val) {
p->count += 42;
p->array[index] = val; /* The sanitizer can't properly check this access */
}
```
In this example, an update to 'p->count' maintains the relationship
requirement:
```
void use_foo(int index, int val) {
if (p->count == 0)
return;
--p->count;
p->array[index] = val;
}
```
Diffstat (limited to 'clang/lib/CodeGen/CodeGenFunction.h')
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 07c7678..143ad64 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3073,6 +3073,25 @@ public: /// this expression is used as an lvalue, for instance in "&Arr[Idx]". void EmitBoundsCheck(const Expr *E, const Expr *Base, llvm::Value *Index, QualType IndexType, bool Accessed); + void EmitBoundsCheckImpl(const Expr *E, llvm::Value *Bound, + llvm::Value *Index, QualType IndexType, + QualType IndexedType, bool Accessed); + + // Find a struct's flexible array member. It may be embedded inside multiple + // sub-structs, but must still be the last field. + const FieldDecl *FindFlexibleArrayMemberField(ASTContext &Ctx, + const RecordDecl *RD, + StringRef Name, + uint64_t &Offset); + + /// Find the FieldDecl specified in a FAM's "counted_by" attribute. Returns + /// \p nullptr if either the attribute or the field doesn't exist. + const FieldDecl *FindCountedByField(const FieldDecl *FD); + + /// Build an expression accessing the "counted_by" field. + llvm::Value *EmitCountedByFieldExpr(const Expr *Base, + const FieldDecl *FAMDecl, + const FieldDecl *CountDecl); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); @@ -4873,6 +4892,9 @@ private: llvm::Value *EmittedE, bool IsDynamic); + llvm::Value *emitFlexibleArrayMemberSize(const Expr *E, unsigned Type, + llvm::IntegerType *ResType); + void emitZeroOrPatternForAutoVarInit(QualType type, const VarDecl &D, Address Loc); |