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