brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.1 KiB · 2bb3917 Raw
146 lines · cpp
1//=== StoreToImmutableChecker.cpp - Store to immutable memory ---*- 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// This file defines StoreToImmutableChecker, a checker that detects writes10// to immutable memory regions. This implements part of SEI CERT Rule ENV30-C.11//12//===----------------------------------------------------------------------===//13 14#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"15#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"16#include "clang/StaticAnalyzer/Core/Checker.h"17#include "clang/StaticAnalyzer/Core/CheckerManager.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"20 21using namespace clang;22using namespace ento;23 24namespace {25class StoreToImmutableChecker : public Checker<check::Bind> {26  const BugType BT{this, "Write to immutable memory", "CERT Environment (ENV)"};27 28public:29  void checkBind(SVal Loc, SVal Val, const Stmt *S, bool AtDeclInit,30                 CheckerContext &C) const;31};32} // end anonymous namespace33 34static bool isEffectivelyConstRegion(const MemRegion *MR, CheckerContext &C) {35  if (isa<GlobalImmutableSpaceRegion>(MR))36    return true;37 38  // Check if this is a TypedRegion with a const-qualified type39  if (const auto *TR = dyn_cast<TypedRegion>(MR)) {40    QualType LocationType = TR->getDesugaredLocationType(C.getASTContext());41    if (LocationType->isPointerOrReferenceType())42      LocationType = LocationType->getPointeeType();43    if (LocationType.isConstQualified())44      return true;45  }46 47  // Check if this is a SymbolicRegion with a const-qualified pointee type48  if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {49    QualType PointeeType = SR->getPointeeStaticType();50    if (PointeeType.isConstQualified())51      return true;52  }53 54  // NOTE: The above branches do not cover AllocaRegion. We do not need to check55  // AllocaRegion, as it models untyped memory, that is allocated on the stack.56 57  return false;58}59 60static const MemRegion *getInnermostConstRegion(const MemRegion *MR,61                                                CheckerContext &C) {62  while (true) {63    if (isEffectivelyConstRegion(MR, C))64      return MR;65    if (auto *SR = dyn_cast<SubRegion>(MR))66      MR = SR->getSuperRegion();67    else68      return nullptr;69  }70}71 72static const DeclRegion *73getInnermostEnclosingConstDeclRegion(const MemRegion *MR, CheckerContext &C) {74  while (true) {75    if (const auto *DR = dyn_cast<DeclRegion>(MR)) {76      const ValueDecl *D = DR->getDecl();77      QualType DeclaredType = D->getType();78      if (DeclaredType.isConstQualified())79        return DR;80    }81    if (auto *SR = dyn_cast<SubRegion>(MR))82      MR = SR->getSuperRegion();83    else84      return nullptr;85  }86}87 88void StoreToImmutableChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,89                                        bool AtDeclInit,90                                        CheckerContext &C) const {91  // We are only interested in stores to memory regions92  const MemRegion *MR = Loc.getAsRegion();93  if (!MR)94    return;95 96  // Skip variable declarations and initializations - we only want to catch97  // actual writes98  if (AtDeclInit)99    return;100 101  // Check if the region is in the global immutable space102  const MemSpaceRegion *MS = MR->getMemorySpace(C.getState());103  const bool IsGlobalImmutableSpace = isa<GlobalImmutableSpaceRegion>(MS);104  // Check if the region corresponds to a const variable105  const MemRegion *InnermostConstRegion = getInnermostConstRegion(MR, C);106  if (!IsGlobalImmutableSpace && !InnermostConstRegion)107    return;108 109  SmallString<64> WarningMessage{"Trying to write to immutable memory"};110  if (IsGlobalImmutableSpace)111    WarningMessage += " in global read-only storage";112 113  // Generate the bug report114  ExplodedNode *N = C.generateNonFatalErrorNode();115  if (!N)116    return;117 118  auto R = std::make_unique<PathSensitiveBugReport>(BT, WarningMessage, N);119  R->addRange(S->getSourceRange());120 121  // Generate a note if the location that is being written to has a122  // declaration or if it is a subregion of a const region with a declaration.123  const DeclRegion *DR =124      getInnermostEnclosingConstDeclRegion(InnermostConstRegion, C);125  if (DR) {126    const char *NoteMessage =127        (DR != MR) ? "Enclosing memory region is declared as immutable here"128                   : "Memory region is declared as immutable here";129    R->addNote(NoteMessage, PathDiagnosticLocation::create(130                                DR->getDecl(), C.getSourceManager()));131  }132 133  // For this checker, we are only interested in the value being written, no134  // need to mark the value being assigned interesting.135 136  C.emitReport(std::move(R));137}138 139void ento::registerStoreToImmutableChecker(CheckerManager &mgr) {140  mgr.registerChecker<StoreToImmutableChecker>();141}142 143bool ento::shouldRegisterStoreToImmutableChecker(const CheckerManager &mgr) {144  return true;145}146