brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 4fedac6 Raw
162 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "DynamicAllocator.h"10#include "InterpBlock.h"11#include "InterpState.h"12 13using namespace clang;14using namespace clang::interp;15 16DynamicAllocator::~DynamicAllocator() { cleanup(); }17 18void 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 necessary22  // 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 = Alloc.block();27      assert(!B->isDead());28      assert(B->isInitialized());29      B->invokeDtor();30 31      if (B->hasPointers()) {32        while (B->Pointers) {33          Pointer *Next = B->Pointers->asBlockPointer().Next;34          B->Pointers->BS.Pointee = nullptr;35          B->Pointers = Next;36        }37        B->Pointers = nullptr;38      }39    }40  }41 42  AllocationSites.clear();43}44 45Block *DynamicAllocator::allocate(const Expr *Source, PrimType T,46                                  size_t NumElements, unsigned EvalID,47                                  Form AllocForm) {48  // Create a new descriptor for an array of the specified size and49  // element type.50  const Descriptor *D = allocateDescriptor(51      Source, T, Descriptor::InlineDescMD, NumElements, /*IsConst=*/false,52      /*IsTemporary=*/false, /*IsMutable=*/false);53 54  return allocate(D, EvalID, AllocForm);55}56 57Block *DynamicAllocator::allocate(const Descriptor *ElementDesc,58                                  size_t NumElements, unsigned EvalID,59                                  Form AllocForm) {60  assert(ElementDesc->getMetadataSize() == 0);61  // Create a new descriptor for an array of the specified size and62  // element type.63  // FIXME: Pass proper element type.64  const Descriptor *D = allocateDescriptor(65      ElementDesc->asExpr(), nullptr, ElementDesc, Descriptor::InlineDescMD,66      NumElements,67      /*IsConst=*/false, /*IsTemporary=*/false, /*IsMutable=*/false);68  return allocate(D, EvalID, AllocForm);69}70 71Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,72                                  Form AllocForm) {73  assert(D);74  assert(D->asExpr());75 76  // Garbage collection. Remove all dead allocations that don't have pointers to77  // them anymore.78  llvm::erase_if(DeadAllocations, [](Allocation &Alloc) -> bool {79    return !Alloc.block()->hasPointers();80  });81 82  auto Memory =83      std::make_unique<std::byte[]>(sizeof(Block) + D->getAllocSize());84  auto *B = new (Memory.get()) Block(EvalID, D, /*isStatic=*/false);85  B->invokeCtor();86 87  assert(D->getMetadataSize() == sizeof(InlineDescriptor));88  InlineDescriptor *ID = reinterpret_cast<InlineDescriptor *>(B->rawData());89  ID->Desc = D;90  ID->IsActive = true;91  ID->Offset = sizeof(InlineDescriptor);92  ID->IsBase = false;93  ID->IsFieldMutable = false;94  ID->IsConst = false;95  ID->IsInitialized = false;96  ID->IsVolatile = false;97 98  if (D->isCompositeArray())99    ID->LifeState = Lifetime::Started;100  else101    ID->LifeState =102        AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;103 104  if (auto It = AllocationSites.find(D->asExpr());105      It != AllocationSites.end()) {106    It->second.Allocations.emplace_back(std::move(Memory));107    B->setDynAllocId(It->second.NumAllocs);108    ++It->second.NumAllocs;109  } else {110    AllocationSites.insert(111        {D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});112    B->setDynAllocId(0);113  }114  assert(B->isDynamic());115  return B;116}117 118bool DynamicAllocator::deallocate(const Expr *Source,119                                  const Block *BlockToDelete, InterpState &S) {120  auto It = AllocationSites.find(Source);121  if (It == AllocationSites.end())122    return false;123 124  auto &Site = It->second;125  assert(!Site.empty());126 127  // Find the Block to delete.128  auto *AllocIt = llvm::find_if(Site.Allocations, [&](const Allocation &A) {129    return BlockToDelete == A.block();130  });131 132  assert(AllocIt != Site.Allocations.end());133 134  Block *B = AllocIt->block();135  assert(B->isInitialized());136  assert(!B->isDead());137  B->invokeDtor();138 139  // Almost all our dynamic allocations have a pointer pointing to them140  // when we deallocate them, since otherwise we can't call delete() at all.141  // This means that we would usually need to create DeadBlocks for all of them.142  // To work around that, we instead mark them as dead without moving the data143  // over to a DeadBlock and simply keep the block in a separate DeadAllocations144  // list.145  if (B->hasPointers()) {146    B->AccessFlags |= Block::DeadFlag;147    DeadAllocations.push_back(std::move(*AllocIt));148    Site.Allocations.erase(AllocIt);149 150    if (Site.size() == 0)151      AllocationSites.erase(It);152    return true;153  }154 155  // Get rid of the allocation altogether.156  Site.Allocations.erase(AllocIt);157  if (Site.empty())158    AllocationSites.erase(It);159 160  return true;161}162