From fd11b390f3ea0223d272b71bde67b3727ccf1cd5 Mon Sep 17 00:00:00 2001
From: Axel Naumann <Axel.Naumann@cern.ch>
Date: Sat, 23 Jun 2018 11:12:19 +0200
Subject: [PATCH] [cling] Only check pointers for Decls from writable dirs
 (ROOT-9377).

---
 .../NullDerefProtectionTransformer.cpp        | 42 ++++++++++++++++++-
 .../NullDerefProtectionTransformer.h          | 10 +++++
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp
index 22257513699..0305f37ac67 100644
--- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp
+++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.cpp
@@ -18,15 +18,17 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Sema/Lookup.h"
 
 #include <bitset>
-#include <map>
 
 using namespace clang;
 
 namespace {
+using namespace cling;
+
 class PointerCheckInjector : public RecursiveASTVisitor<PointerCheckInjector> {
   private:
     Interpreter& m_Interp;
@@ -226,9 +228,45 @@ namespace cling {
   NullDerefProtectionTransformer::~NullDerefProtectionTransformer()
   { }
 
+  bool NullDerefProtectionTransformer::shouldTransform(const clang::Decl* D) {
+    if (D->isFromASTFile())
+      return false;
+    if (D->isTemplateDecl())
+      return false;
+
+    auto Loc = D->getLocation();
+    if (Loc.isInvalid())
+      return false;
+
+    SourceManager& SM = m_Interp->getSema().getSourceManager();
+    auto FID = SM.getFileID(Loc);
+    if (FID.isInvalid())
+      return false;
+
+    auto FE = SM.getFileEntryForID(FID);
+    if (!FE)
+      return false;
+
+    auto Dir = FE->getDir();
+    if (!Dir)
+      return false;
+
+    auto IterAndInserted = m_ShouldVisitDir.try_emplace(Dir, true);
+    if (IterAndInserted.second == false)
+      return IterAndInserted.first->second;
+
+    if (llvm::sys::fs::can_write(Dir->getName()))
+      return true; // `true` is already emplaced above.
+
+    // Remember that this dir is not writable and should not be visited.
+    IterAndInserted.first->second = false;
+    return false;
+  }
+
+
   ASTTransformer::Result
   NullDerefProtectionTransformer::Transform(clang::Decl* D) {
-    if (getCompilationOpts().CheckPointerValidity) {
+    if (getCompilationOpts().CheckPointerValidity && shouldTransform(D)) {
       PointerCheckInjector injector(*m_Interp);
       injector.TraverseDecl(D);
     }
diff --git a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h
index a7b679fe9fc..72fd608869e 100644
--- a/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h
+++ b/interpreter/cling/lib/Interpreter/NullDerefProtectionTransformer.h
@@ -13,8 +13,11 @@
 
 #include "ASTTransformer.h"
 
+#include "llvm/ADT/DenseMap.h"
+
 namespace clang {
   class Decl;
+  class DirectoryEntry;
 }
 namespace cling {
   class Interpreter;
@@ -24,6 +27,13 @@ namespace cling {
 
   class NullDerefProtectionTransformer : public ASTTransformer {
     cling::Interpreter* m_Interp;
+
+    /// Whether to visit a Decl coming from a file in a given directory.
+    llvm::DenseMap<const clang::DirectoryEntry*, bool> m_ShouldVisitDir;
+
+    /// Whether the declaration should be visited and possibly transformed.
+    bool shouldTransform(const clang::Decl* D);
+
   public:
     ///\ brief Constructs the NullDeref AST Transformer.
     ///
-- 
GitLab