tor-browser

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

MemMoveAnnotation.h (3062B)


      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 #ifndef MemMoveAnnotation_h__
      6 #define MemMoveAnnotation_h__
      7 
      8 #include "CustomMatchers.h"
      9 #include "CustomTypeAnnotation.h"
     10 #include "Utils.h"
     11 
     12 
     13 class MemMoveAnnotation final : public CustomTypeAnnotation {
     14 public:
     15  MemMoveAnnotation()
     16      : CustomTypeAnnotation(moz_non_memmovable, "non-memmove()able") {}
     17 
     18  virtual ~MemMoveAnnotation() {}
     19 
     20 protected:
     21  static bool is_trivially_relocatable(const TagDecl *D) {
     22    if (auto RD = dyn_cast<CXXRecordDecl>(D)) {
     23      // Trivially relocatable trait
     24      if (RD->isCompleteDefinition() &&
     25          (RD->hasTrivialMoveConstructor() ||
     26           (!RD->hasMoveConstructor() && RD->hasTrivialCopyConstructor())) &&
     27          RD->hasTrivialDestructor()) {
     28        return true;
     29      }
     30      // Extension for std::unique_ptr
     31      if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
     32        if (getDeclarationNamespace(D) == "std" &&
     33            (getNameChecked(D) == "unique_ptr")) {
     34          unsigned ParameterIndex = 0;
     35          const auto &TArgs = Spec->getTemplateArgs();
     36          if (TArgs.size() != 2) {
     37            return false; // should not happen
     38          }
     39          // Skip the first parameter, it's used to store the pointer and
     40          // doesn't force any requirement on the unique_ptr
     41          const auto &Deleter = TArgs[1];
     42          if (Deleter.getKind() != TemplateArgument::Type)
     43            return false;
     44          QualType DeleterTy = Deleter.getAsType();
     45          if (const auto *TD = DeleterTy->getAsTagDecl()) {
     46            return is_trivially_relocatable(TD);
     47          } else {
     48            return false; // should not happen
     49          }
     50        }
     51      }
     52    }
     53    return false;
     54  }
     55 
     56  std::string getImplicitReason(const TagDecl *D,
     57                                VisitFlags &ToVisit) const override {
     58    // Annotate everything in ::std, with a few exceptions; see bug
     59    // 1201314 for discussion.
     60    if (getDeclarationNamespace(D) != "std") {
     61      return "";
     62    }
     63 
     64    StringRef Name = getNameChecked(D);
     65 
     66    // If the type has a trivial move constructor and destructor, it is safe to
     67    // memmove, and we don't need to visit any fields.
     68    if (is_trivially_relocatable(D)) {
     69      ToVisit = VISIT_NONE;
     70      return "";
     71    }
     72 
     73    // This doesn't check that it's really ::std::pair and not
     74    // ::std::something_else::pair, but should be good enough.
     75    if (isNameExcepted(Name.data())) {
     76      // If we're an excepted name, stop traversing within the type further,
     77      // and only check template arguments for foreign types.
     78      ToVisit = VISIT_TMPL_ARGS;
     79      return "";
     80    }
     81    return "it is an stl-provided type not guaranteed to be memmove-able";
     82  }
     83 
     84 private:
     85  bool isNameExcepted(StringRef Name) const {
     86    return Name == "pair" || Name == "atomic" || Name == "tuple";
     87  }
     88 };
     89 
     90 extern MemMoveAnnotation NonMemMovable;
     91 
     92 #endif