tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ScopeChecker.cpp (7183B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "ScopeChecker.h"
      6 #include "CustomMatchers.h"
      7 
      8 void ScopeChecker::registerMatchers(MatchFinder *AstMatcher) {
      9  AstMatcher->addMatcher(varDecl().bind("node"), this);
     10  AstMatcher->addMatcher(cxxNewExpr().bind("node"), this);
     11  AstMatcher->addMatcher(
     12      materializeTemporaryExpr(
     13          unless(hasDescendant(cxxConstructExpr(allowsTemporary()))))
     14          .bind("node"),
     15      this);
     16  AstMatcher->addMatcher(
     17      callExpr(callee(functionDecl(heapAllocator()))).bind("node"), this);
     18 }
     19 
     20 // These enum variants determine whether an allocation has occured in the code.
     21 enum AllocationVariety {
     22  AV_None,
     23  AV_Global,
     24  AV_Automatic,
     25  AV_Temporary,
     26  AV_Heap,
     27 };
     28 
     29 // XXX Currently the Decl* in the AutomaticTemporaryMap is unused, but it
     30 // probably will be used at some point in the future, in order to produce better
     31 // error messages.
     32 typedef DenseMap<const MaterializeTemporaryExpr *, const Decl *>
     33    AutomaticTemporaryMap;
     34 AutomaticTemporaryMap AutomaticTemporaries;
     35 
     36 void ScopeChecker::check(const MatchFinder::MatchResult &Result) {
     37  // There are a variety of different reasons why something could be allocated
     38  AllocationVariety Variety = AV_None;
     39  SourceLocation Loc;
     40  QualType T;
     41  bool IsStaticLocal = false;
     42 
     43  if (const ParmVarDecl *D = Result.Nodes.getNodeAs<ParmVarDecl>("node")) {
     44    if (D->hasUnparsedDefaultArg() || D->hasUninstantiatedDefaultArg()) {
     45      return;
     46    }
     47    if (const Expr *Default = D->getDefaultArg()) {
     48      if (const MaterializeTemporaryExpr *E =
     49              dyn_cast<MaterializeTemporaryExpr>(Default)) {
     50        // We have just found a ParmVarDecl which has, as its default argument,
     51        // a MaterializeTemporaryExpr. We mark that MaterializeTemporaryExpr as
     52        // automatic, by adding it to the AutomaticTemporaryMap.
     53        // Reporting on this type will occur when the MaterializeTemporaryExpr
     54        // is matched against.
     55        AutomaticTemporaries[E] = D;
     56      }
     57    }
     58    return;
     59  }
     60 
     61  // Determine the type of allocation which we detected
     62  if (const VarDecl *D = Result.Nodes.getNodeAs<VarDecl>("node")) {
     63    if (D->hasGlobalStorage()) {
     64      Variety = AV_Global;
     65    } else {
     66      Variety = AV_Automatic;
     67    }
     68    T = D->getType();
     69    Loc = D->getBeginLoc();
     70    IsStaticLocal = D->isStaticLocal();
     71  } else if (const CXXNewExpr *E = Result.Nodes.getNodeAs<CXXNewExpr>("node")) {
     72    // New allocates things on the heap.
     73    // We don't consider placement new to do anything, as it doesn't actually
     74    // allocate the storage, and thus gives us no useful information.
     75    if (!isPlacementNew(E)) {
     76      Variety = AV_Heap;
     77      T = E->getAllocatedType();
     78      Loc = E->getBeginLoc();
     79    }
     80  } else if (const MaterializeTemporaryExpr *E =
     81                 Result.Nodes.getNodeAs<MaterializeTemporaryExpr>("node")) {
     82    // Temporaries can actually have varying storage durations, due to temporary
     83    // lifetime extension. We consider the allocation variety of this temporary
     84    // to be the same as the allocation variety of its lifetime.
     85 
     86    // XXX We maybe should mark these lifetimes as being due to a temporary
     87    // which has had its lifetime extended, to improve the error messages.
     88    switch (E->getStorageDuration()) {
     89    case SD_FullExpression: {
     90      // Check if this temporary is allocated as a default argument!
     91      // if it is, we want to pretend that it is automatic.
     92      AutomaticTemporaryMap::iterator AutomaticTemporary =
     93          AutomaticTemporaries.find(E);
     94      if (AutomaticTemporary != AutomaticTemporaries.end()) {
     95        Variety = AV_Automatic;
     96      } else {
     97        Variety = AV_Temporary;
     98      }
     99    } break;
    100    case SD_Automatic:
    101      Variety = AV_Automatic;
    102      break;
    103    case SD_Thread:
    104    case SD_Static:
    105      Variety = AV_Global;
    106      break;
    107    case SD_Dynamic:
    108      assert(false && "I don't think that this ever should occur...");
    109      Variety = AV_Heap;
    110      break;
    111    }
    112    T = E->getType().getUnqualifiedType();
    113    Loc = E->getBeginLoc();
    114  } else if (const CallExpr *E = Result.Nodes.getNodeAs<CallExpr>("node")) {
    115    T = E->getType()->getPointeeType();
    116    if (!T.isNull()) {
    117      // This will always allocate on the heap, as the heapAllocator() check
    118      // was made in the matcher
    119      Variety = AV_Heap;
    120      Loc = E->getBeginLoc();
    121    }
    122  }
    123 
    124  // Error messages for incorrect allocations.
    125  const char *Stack = "variable of type %0 only valid on the stack";
    126  const char *Global = "variable of type %0 only valid as global";
    127  const char *Heap = "variable of type %0 only valid on the heap";
    128  const char *NonHeap = "variable of type %0 is not valid on the heap";
    129  const char *NonTemporary = "variable of type %0 is not valid in a temporary";
    130  const char *Temporary = "variable of type %0 is only valid as a temporary";
    131  const char *StaticLocal = "variable of type %0 is only valid as a static "
    132                            "local";
    133 
    134  const char *StackNote =
    135      "value incorrectly allocated in an automatic variable";
    136  const char *GlobalNote = "value incorrectly allocated in a global variable";
    137  const char *HeapNote = "value incorrectly allocated on the heap";
    138  const char *TemporaryNote = "value incorrectly allocated in a temporary";
    139 
    140  // Report errors depending on the annotations on the input types.
    141  switch (Variety) {
    142  case AV_None:
    143    return;
    144 
    145  case AV_Global:
    146    StackClass.reportErrorIfPresent(*this, T, Loc, Stack, GlobalNote);
    147    HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, GlobalNote);
    148    TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, GlobalNote);
    149    if (!IsStaticLocal) {
    150      StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
    151                                            GlobalNote);
    152    }
    153    break;
    154 
    155  case AV_Automatic:
    156    GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, StackNote);
    157    HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, StackNote);
    158    TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, StackNote);
    159    StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
    160                                          StackNote);
    161    break;
    162 
    163  case AV_Temporary:
    164    GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, TemporaryNote);
    165    HeapClass.reportErrorIfPresent(*this, T, Loc, Heap, TemporaryNote);
    166    NonTemporaryClass.reportErrorIfPresent(*this, T, Loc, NonTemporary,
    167                                           TemporaryNote);
    168    StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal,
    169                                          TemporaryNote);
    170    break;
    171 
    172  case AV_Heap:
    173    GlobalClass.reportErrorIfPresent(*this, T, Loc, Global, HeapNote);
    174    StackClass.reportErrorIfPresent(*this, T, Loc, Stack, HeapNote);
    175    NonHeapClass.reportErrorIfPresent(*this, T, Loc, NonHeap, HeapNote);
    176    TemporaryClass.reportErrorIfPresent(*this, T, Loc, Temporary, HeapNote);
    177    StaticLocalClass.reportErrorIfPresent(*this, T, Loc, StaticLocal, HeapNote);
    178    break;
    179  }
    180 }