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