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 
13 using namespace clang;
14 using 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  // Create a new descriptor for an array of the specified size and
45  // element type.
46  const Descriptor *D = allocateDescriptor(
47  Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
48  /*IsTemporary=*/false, /*IsMutable=*/false);
49 
50  return allocate(D, EvalID);
51 }
52 
54  size_t NumElements, unsigned EvalID) {
55  // Create a new descriptor for an array of the specified size and
56  // element type.
57  const Descriptor *D = allocateDescriptor(
58  ElementDesc->asExpr(), ElementDesc, Descriptor::InlineDescMD, NumElements,
59  /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
60  return allocate(D, EvalID);
61 }
62 
63 Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID) {
64  assert(D);
65  assert(D->asExpr());
66 
67  auto Memory =
68  std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
69  auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
70  B->invokeCtor();
71 
72  InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
73  ID->Desc = D;
74  ID->IsActive = true;
75  ID->Offset = sizeof(InlineDescriptor);
76  ID->IsBase = false;
77  ID->IsFieldMutable = false;
78  ID->IsConst = false;
79  ID->IsInitialized = false;
80 
81  B->IsDynamic = true;
82 
83  if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
84  It->second.Allocations.emplace_back(std::move(Memory));
85  else
86  AllocationSites.insert(
87  {D->asExpr(), AllocationSite(std::move(Memory), D->isArray())});
88  return B;
89 }
90 
92  const Block *BlockToDelete, InterpState &S) {
93  auto It = AllocationSites.find(Source);
94  if (It == AllocationSites.end())
95  return false;
96 
97  auto &Site = It->second;
98  assert(Site.size() > 0);
99 
100  // Find the Block to delete.
101  auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
102  const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
103  return BlockToDelete == B;
104  });
105 
106  assert(AllocIt != Site.Allocations.end());
107 
108  Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
109  B->invokeDtor();
110 
111  S.deallocate(B);
112  Site.Allocations.erase(AllocIt);
113 
114  if (Site.size() == 0)
115  AllocationSites.erase(It);
116 
117  return true;
118 }
static char ID
Definition: Arena.cpp:183
const Decl * D
unsigned Iter
Definition: HTMLLogger.cpp:154
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:121
void invokeCtor()
Invokes the constructor.
Definition: InterpBlock.h:110
bool hasPointers() const
Checks if the block has any live pointers.
Definition: InterpBlock.h:69
bool deallocate(const Expr *Source, const Block *BlockToDelete, InterpState &S)
Deallocate the given source+block combination.
Block * allocate(const Descriptor *D, unsigned EvalID)
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:82
BlockPointer BS
Definition: Pointer.h:732
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:33
bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc)
Definition: Interp.h:2934
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:111
const Expr * asExpr() const
Definition: Descriptor.h:199
static constexpr MetadataSize InlineDescMD
Definition: Descriptor.h:132
Inline descriptor embedded in structures and arrays.
Definition: Descriptor.h:69