clang 24.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
12using namespace clang;
13using namespace clang::interp;
14
16
18 // Invoke destructors of all the blocks and as a last restort,
19 // reset all the pointers pointing to them to null pointees.
20 // This should never show up in diagnostics, but it's necessary
21 // for us to not cause use-after-free problems.
22 for (auto &Iter : AllocationSites) {
23 auto &AllocSite = Iter.second;
24 for (auto &Alloc : AllocSite.Allocations) {
25 Block *B = Alloc.block();
26 assert(!B->isDead());
27 assert(B->isInitialized());
28 B->invokeDtor();
29 B->removePointers();
30 }
31 }
32
33 AllocationSites.clear();
34}
35
37 size_t NumElements, unsigned EvalID,
38 Form AllocForm) {
39 // Create a new descriptor for an array of the specified size and
40 // element type.
41 const Descriptor *D =
42 allocateDescriptor(Source, nullptr, T, Descriptor::InlineDescMD,
43 NumElements, /*IsConst=*/false,
44 /*IsTemporary=*/false, /*IsMutable=*/false,
45 /*IsVolatile=*/false);
46
47 return allocate(D, EvalID, AllocForm);
48}
49
51 size_t NumElements, unsigned EvalID,
52 Form AllocForm) {
53 assert(ElementDesc->getMetadataSize() == 0);
54 // Create a new descriptor for an array of the specified size and
55 // element type.
56 // FIXME: Pass proper element type.
57 const Descriptor *D = allocateDescriptor(
58 ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD,
59 NumElements,
60 /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
61 return allocate(D, EvalID, AllocForm);
62}
63
64Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
65 Form AllocForm) {
66 assert(D);
67 assert(D->asExpr());
68
69 // Garbage collection. Remove all dead allocations that don't have pointers to
70 // them anymore.
71 llvm::erase_if(DeadAllocations, [](Allocation &Alloc) -> bool {
72 return !Alloc.block()->hasPointers();
73 });
74
75 auto Memory =
76 std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
77 auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
78 B->invokeCtorNoMemset();
79
80 assert(D->getMetadataSize() == sizeof(InlineDescriptor));
81 InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
82 ID->Desc = D;
83 ID->IsActive = true;
84 ID->Offset = sizeof(InlineDescriptor);
85 ID->IsBase = false;
86 ID->IsFieldMutable = false;
87 ID->IsConst = false;
88 ID->IsInitialized = false;
89 ID->IsVolatile = false;
90
91 if (D->isCompositeArray())
92 ID->LifeState = Lifetime::Started;
93 else
94 ID->LifeState =
96
97 if (auto It = AllocationSites.find(D->asExpr());
98 It != AllocationSites.end()) {
99 It->second.Allocations.emplace_back(std::move(Memory));
100 B->setDynAllocId(It->second.NumAllocs);
101 ++It->second.NumAllocs;
102 } else {
103 AllocationSites.insert(
104 {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
105 B->setDynAllocId(0);
106 }
107 assert(B->isDynamic());
108 return B;
109}
110
112 const Block *BlockToDelete) {
113 auto It = AllocationSites.find(Source);
114 if (It == AllocationSites.end())
115 return false;
116
117 auto &Site = It->second;
118 assert(!Site.empty());
119
120 // Find the Block to delete.
121 auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
122 return BlockToDelete == A.block();
123 });
124
125 // The allocation site it fine, but this block doesn't belong to it. Must've
126 // already been deleted.
127 if (AllocIt == Site.Allocations.end())
128 return false;
129
130 Block *B = AllocIt->block();
131 assert(B->isInitialized());
132 assert(!B->isDead());
133 B->invokeDtor();
134
135 // Almost all our dynamic allocations have a pointer pointing to them
136 // when we deallocate them, since otherwise we can't call delete() at all.
137 // This means that we would usually need to create DeadBlocks for all of them.
138 // To work around that, we instead mark them as dead without moving the data
139 // over to a DeadBlock and simply keep the block in a separate DeadAllocations
140 // list.
141 if (B->hasPointers()) {
142 B->AccessFlags |= Block::DeadFlag;
143 DeadAllocations.push_back(std::move(*AllocIt));
144 Site.Allocations.erase(AllocIt);
145
146 if (Site.size() == 0)
147 AllocationSites.erase(It);
148 return true;
149 }
150
151 // Get rid of the allocation altogether.
152 Site.Allocations.erase(AllocIt);
153 if (Site.empty())
154 AllocationSites.erase(It);
155
156 return true;
157}
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.
bool isDead() const
Definition InterpBlock.h:85
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
void removePointers()
Make all pointers that currently point to this block point to nullptr.
Block * allocate(const Descriptor *D, unsigned EvalID, Form AllocForm)
Allocate ONE element of the given descriptor.
bool deallocate(const Expr *Source, const Block *BlockToDelete)
Deallocate the given source+block combination.
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:3874
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
const bool IsConst
Flag indicating if the block is mutable.
Definition Descriptor.h:161
unsigned getAllocSize() const
Returns the allocated size, including metadata.
Definition Descriptor.h:246
bool isCompositeArray() const
Checks if the descriptor is of an array of composites.
Definition Descriptor.h:265
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition Descriptor.h:255
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