clang 22.0.0git
DynamicAllocator.cpp
Go to the documentation of this file.
1//==-------- DynamicAllocator.cpp - Dynamic allocations ----------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "DynamicAllocator.h"
10#include "InterpBlock.h"
11#include "InterpState.h"
12
13using namespace clang;
14using namespace clang::interp;
15
17
19 // Invoke destructors of all the blocks and as a last restort,
20 // reset all the pointers pointing to them to null pointees.
21 // This should never show up in diagnostics, but it's necessary
22 // for us to not cause use-after-free problems.
23 for (auto &Iter : AllocationSites) {
24 auto &AllocSite = Iter.second;
25 for (auto &Alloc : AllocSite.Allocations) {
26 Block *B = Alloc.block();
27 assert(!B->isDead());
28 assert(B->isInitialized());
29 B->invokeDtor();
30
31 if (B->hasPointers()) {
32 while (B->Pointers) {
33 Pointer *Next = B->Pointers->asBlockPointer().Next;
34 B->Pointers->BS.Pointee = nullptr;
35 B->Pointers = Next;
36 }
37 B->Pointers = nullptr;
38 }
39 }
40 }
41
42 AllocationSites.clear();
43}
44
46 size_t NumElements, unsigned EvalID,
47 Form AllocForm) {
48 // Create a new descriptor for an array of the specified size and
49 // element type.
50 const Descriptor *D = allocateDescriptor(
51 Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
52 /*IsTemporary=*/false, /*IsMutable=*/false);
53
54 return allocate(D, EvalID, AllocForm);
55}
56
58 size_t NumElements, unsigned EvalID,
59 Form AllocForm) {
60 assert(ElementDesc->getMetadataSize() == 0);
61 // Create a new descriptor for an array of the specified size and
62 // element type.
63 // FIXME: Pass proper element type.
64 const Descriptor *D = allocateDescriptor(
65 ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD,
66 NumElements,
67 /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
68 return allocate(D, EvalID, AllocForm);
69}
70
72 Form AllocForm) {
73 assert(D);
74 assert(D->asExpr());
75
76 // Garbage collection. Remove all dead allocations that don't have pointers to
77 // them anymore.
78 llvm::erase_if(DeadAllocations, [](Allocation &Alloc) -> bool {
79 return !Alloc.block()->hasPointers();
80 });
81
82 auto Memory =
83 std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
84 auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
85 B->invokeCtor();
86
87 assert(D->getMetadataSize() == sizeof(InlineDescriptor));
88 InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
89 ID->Desc = D;
90 ID->IsActive = true;
91 ID->Offset = sizeof(InlineDescriptor);
92 ID->IsBase = false;
93 ID->IsFieldMutable = false;
94 ID->IsConst = false;
95 ID->IsInitialized = false;
96 ID->IsVolatile = false;
97
98 if (D->isCompositeArray())
99 ID->LifeState = Lifetime::Started;
100 else
101 ID->LifeState =
103
104 if (auto It = AllocationSites.find(D->asExpr());
105 It != AllocationSites.end()) {
106 It->second.Allocations.emplace_back(std::move(Memory));
107 B->setDynAllocId(It->second.NumAllocs);
108 ++It->second.NumAllocs;
109 } else {
110 AllocationSites.insert(
111 {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
112 B->setDynAllocId(0);
113 }
114 assert(B->isDynamic());
115 return B;
116}
117
119 const Block *BlockToDelete, InterpState &S) {
120 auto It = AllocationSites.find(Source);
121 if (It == AllocationSites.end())
122 return false;
123
124 auto &Site = It->second;
125 assert(!Site.empty());
126
127 // Find the Block to delete.
128 auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
129 return BlockToDelete == A.block();
130 });
131
132 assert(AllocIt != Site.Allocations.end());
133
134 Block *B = AllocIt->block();
135 assert(B->isInitialized());
136 assert(!B->isDead());
137 B->invokeDtor();
138
139 // Almost all our dynamic allocations have a pointer pointing to them
140 // when we deallocate them, since otherwise we can't call delete() at all.
141 // This means that we would usually need to create DeadBlocks for all of them.
142 // To work around that, we instead mark them as dead without moving the data
143 // over to a DeadBlock and simply keep the block in a separate DeadAllocations
144 // list.
145 if (B->hasPointers()) {
146 B->AccessFlags |= Block::DeadFlag;
147 DeadAllocations.push_back(std::move(*AllocIt));
148 Site.Allocations.erase(AllocIt);
149
150 if (Site.size() == 0)
151 AllocationSites.erase(It);
152 return true;
153 }
154
155 // Get rid of the allocation altogether.
156 Site.Allocations.erase(AllocIt);
157 if (Site.empty())
158 AllocationSites.erase(It);
159
160 return true;
161}
const Decl * D
unsigned Iter
Definition: HTMLLogger.cpp:153
This represents one expression.
Definition: Expr.h:112
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:44
void invokeDtor()
Invokes the Destructor.
Definition: InterpBlock.h:135
bool isDead() const
Definition: InterpBlock.h:85
void invokeCtor()
Invokes the constructor.
Definition: InterpBlock.h:123
bool isInitialized() const
Returns whether the data of this block has been initialized via invoking the Ctor func.
Definition: InterpBlock.h:92
bool hasPointers() const
Checks if the block has any live pointers.
Definition: InterpBlock.h:75
bool deallocate(const Expr *Source, const Block *BlockToDelete, InterpState &S)
Deallocate the given source+block combination.
Block * allocate(const Descriptor *D, unsigned EvalID, Form AllocForm)
Allocate ONE element of the given descriptor.
Interpreter context.
Definition: InterpState.h:43
A pointer to a memory block, live or dead.
Definition: Pointer.h:90
BlockPointer BS
Definition: Pointer.h:819
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:447
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:34
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:3464
The JSON file list parser is used to communicate input to InstallAPI.
if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))
const FunctionProtoType * T
Pointer * Next
Next link in the pointer chain.
Definition: Pointer.h:43
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:37
Describes a memory block created by an allocation site.
Definition: Descriptor.h:122
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition: Descriptor.h:246
static constexpr MetadataSize InlineDescMD
Definition: Descriptor.h:144
const Expr * asExpr() const
Definition: Descriptor.h:211
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:67