clang 20.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 = reinterpret_cast<Block *>(Alloc.Memory.get());
27 B->invokeDtor();
28 if (B->hasPointers()) {
29 while (B->Pointers) {
30 Pointer *Next = B->Pointers->Next;
31 B->Pointers->PointeeStorage.BS.Pointee = nullptr;
32 B->Pointers = Next;
33 }
34 B->Pointers = nullptr;
35 }
36 }
37 }
38
39 AllocationSites.clear();
40}
41
43 size_t NumElements, unsigned EvalID,
44 Form AllocForm) {
45 // Create a new descriptor for an array of the specified size and
46 // element type.
47 const Descriptor *D = allocateDescriptor(
48 Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
49 /*IsTemporary=*/false, /*IsMutable=*/false);
50
51 return allocate(D, EvalID, AllocForm);
52}
53
55 size_t NumElements, unsigned EvalID,
56 Form AllocForm) {
57 // Create a new descriptor for an array of the specified size and
58 // element type.
59 const Descriptor *D = allocateDescriptor(
60 ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements,
61 /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
62 return allocate(D, EvalID, AllocForm);
63}
64
66 Form AllocForm) {
67 assert(D);
68 assert(D->asExpr());
69
70 auto Memory =
71 std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
72 auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
73 B->invokeCtor();
74
75 InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
76 ID->Desc = D;
77 ID->IsActive = true;
78 ID->Offset = sizeof(InlineDescriptor);
79 ID->IsBase = false;
80 ID->IsFieldMutable = false;
81 ID->IsConst = false;
82 ID->IsInitialized = false;
83
84 B->IsDynamic = true;
85
86 if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
87 It->second.Allocations.emplace_back(std::move(Memory));
88 else
89 AllocationSites.insert(
90 {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
91 return B;
92}
93
95 const Block *BlockToDelete, InterpState &S) {
96 auto It = AllocationSites.find(Source);
97 if (It == AllocationSites.end())
98 return false;
99
100 auto &Site = It->second;
101 assert(Site.size() > 0);
102
103 // Find the Block to delete.
104 auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
105 const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
106 return BlockToDelete == B;
107 });
108
109 assert(AllocIt != Site.Allocations.end());
110
111 Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
112 B->invokeDtor();
113
114 S.deallocate(B);
115 Site.Allocations.erase(AllocIt);
116
117 if (Site.size() == 0)
118 AllocationSites.erase(It);
119
120 return true;
121}
const Decl * D
unsigned Iter
Definition: HTMLLogger.cpp:153
This represents one expression.
Definition: Expr.h:110
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
void invokeDtor()
Invokes the Destructor.
Definition: InterpBlock.h:123
void invokeCtor()
Invokes the constructor.
Definition: InterpBlock.h:112
bool hasPointers() const
Checks if the block has any live pointers.
Definition: InterpBlock.h:70
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:36
A pointer to a memory block, live or dead.
Definition: Pointer.h:83
BlockPointer BS
Definition: Pointer.h:746
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:2938
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:39
Describes a memory block created by an allocation site.
Definition: Descriptor.h:116
static constexpr MetadataSize InlineDescMD
Definition: Descriptor.h:137
const Expr * asExpr() const
Definition: Descriptor.h:205
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:70