1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
//==-------- DynamicAllocator.cpp - Dynamic allocations ----------*- C++ -*-==//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "DynamicAllocator.h"
#include "InterpBlock.h"
#include "InterpState.h"
using namespace clang;
using namespace clang::interp;
DynamicAllocator::~DynamicAllocator() { cleanup(); }
void DynamicAllocator::cleanup() {
// Invoke destructors of all the blocks and as a last restort,
// reset all the pointers pointing to them to null pointees.
// This should never show up in diagnostics, but it's necessary
// for us to not cause use-after-free problems.
for (auto &Iter : AllocationSites) {
auto &AllocSite = Iter.second;
for (auto &Alloc : AllocSite.Allocations) {
Block *B = reinterpret_cast<Block *>(Alloc.Memory.get());
B->invokeDtor();
if (B->hasPointers()) {
while (B->Pointers) {
Pointer *Next = B->Pointers->Next;
B->Pointers->PointeeStorage.BS.Pointee = nullptr;
B->Pointers = Next;
}
B->Pointers = nullptr;
}
}
}
AllocationSites.clear();
}
Block *DynamicAllocator::allocate(const Expr *Source, PrimType T,
size_t NumElements, unsigned EvalID,
Form AllocForm) {
// Create a new descriptor for an array of the specified size and
// element type.
const Descriptor *D = allocateDescriptor(
Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,
/*IsTemporary=*/false, /*IsMutable=*/false);
return allocate(D, EvalID, AllocForm);
}
Block *DynamicAllocator::allocate(const Descriptor *ElementDesc,
size_t NumElements, unsigned EvalID,
Form AllocForm) {
assert(ElementDesc->getMetadataSize() == 0);
// Create a new descriptor for an array of the specified size and
// element type.
// FIXME: Pass proper element type.
const Descriptor *D = allocateDescriptor(
ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD,
NumElements,
/*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);
return allocate(D, EvalID, AllocForm);
}
Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
Form AllocForm) {
assert(D);
assert(D->asExpr());
auto Memory =
std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());
auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);
B->invokeCtor();
assert(D->getMetadataSize() == sizeof(InlineDescriptor));
InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());
ID->Desc = D;
ID->IsActive = true;
ID->Offset = sizeof(InlineDescriptor);
ID->IsBase = false;
ID->IsFieldMutable = false;
ID->IsConst = false;
ID->IsInitialized = false;
ID->IsVolatile = false;
if (D->isCompositeArray())
ID->LifeState = Lifetime::Started;
else
ID->LifeState =
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
B->IsDynamic = true;
if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
It->second.Allocations.emplace_back(std::move(Memory));
else
AllocationSites.insert(
{D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
return B;
}
bool DynamicAllocator::deallocate(const Expr *Source,
const Block *BlockToDelete, InterpState &S) {
auto It = AllocationSites.find(Source);
if (It == AllocationSites.end())
return false;
auto &Site = It->second;
assert(Site.size() > 0);
// Find the Block to delete.
auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {
const Block *B = reinterpret_cast<const Block *>(A.Memory.get());
return BlockToDelete == B;
});
assert(AllocIt != Site.Allocations.end());
Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get());
B->invokeDtor();
S.deallocate(B);
Site.Allocations.erase(AllocIt);
if (Site.size() == 0)
AllocationSites.erase(It);
return true;
}
|