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 16 DynamicAllocator::~DynamicAllocator() { cleanup(); } 17 18 void DynamicAllocator::cleanup() { 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 42 Block *DynamicAllocator::allocate(const Expr *Source, PrimType T, 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 54 Block *DynamicAllocator::allocate(const Descriptor *ElementDesc, 55 size_t NumElements, unsigned EvalID, 56 Form AllocForm) { 57 assert(ElementDesc->getMetadataSize() == 0); 58 // Create a new descriptor for an array of the specified size and 59 // element type. 60 // FIXME: Pass proper element type. 61 const Descriptor *D = allocateDescriptor( 62 ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD, 63 NumElements, 64 /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false); 65 return allocate(D, EvalID, AllocForm); 66 } 67 68 Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID, 69 Form AllocForm) { 70 assert(D); 71 assert(D->asExpr()); 72 73 auto Memory = 74 std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize()); 75 auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false); 76 B->invokeCtor(); 77 78 assert(D->getMetadataSize() == sizeof(InlineDescriptor)); 79 InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData()); 80 ID->Desc = D; 81 ID->IsActive = true; 82 ID->Offset = sizeof(InlineDescriptor); 83 ID->IsBase = false; 84 ID->IsFieldMutable = false; 85 ID->IsConst = false; 86 ID->IsInitialized = false; 87 ID->IsVolatile = false; 88 89 if (D->isCompositeArray()) 90 ID->LifeState = Lifetime::Started; 91 else 92 ID->LifeState = 93 AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started; 94 95 B->IsDynamic = true; 96 97 if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end()) 98 It->second.Allocations.emplace_back(std::move(Memory)); 99 else 100 AllocationSites.insert( 101 {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)}); 102 return B; 103 } 104 105 bool DynamicAllocator::deallocate(const Expr *Source, 106 const Block *BlockToDelete, InterpState &S) { 107 auto It = AllocationSites.find(Source); 108 if (It == AllocationSites.end()) 109 return false; 110 111 auto &Site = It->second; 112 assert(Site.size() > 0); 113 114 // Find the Block to delete. 115 auto AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) { 116 const Block *B = reinterpret_cast<const Block *>(A.Memory.get()); 117 return BlockToDelete == B; 118 }); 119 120 assert(AllocIt != Site.Allocations.end()); 121 122 Block *B = reinterpret_cast<Block *>(AllocIt->Memory.get()); 123 B->invokeDtor(); 124 125 S.deallocate(B); 126 Site.Allocations.erase(AllocIt); 127 128 if (Site.size() == 0) 129 AllocationSites.erase(It); 130 131 return true; 132 } 133