[Lldb-commits] [lldb] 00764c3 - [lldb] Add support for evaluating expressions in static member functions

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Thu Apr 22 03:14:53 PDT 2021


Author: Raphael Isemann
Date: 2021-04-22T12:14:31+02:00
New Revision: 00764c36edf88ae9806e8d57a6addb782e6ceae8

URL: https://github.com/llvm/llvm-project/commit/00764c36edf88ae9806e8d57a6addb782e6ceae8
DIFF: https://github.com/llvm/llvm-project/commit/00764c36edf88ae9806e8d57a6addb782e6ceae8.diff

LOG: [lldb] Add support for evaluating expressions in static member functions

At the moment the expression parser doesn't support evaluating expressions in
static member functions and just pretends the expression is evaluated within a
non-member function. This causes that all static members are inaccessible when
doing unqualified name lookup.

This patch adds support for evaluating in static member functions. It
essentially just does the same setup as what LLDB is already doing for
non-static member functions (i.e., wrapping the expression in a fake member
function) with the difference that we now mark the wrapping function as static
(to prevent access to non-static members).

Reviewed By: shafik, jarin

Differential Revision: https://reviews.llvm.org/D81550

Added: 
    lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
    lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
    lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp

Modified: 
    lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
    lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
    lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
    lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
    lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
    lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index 0c943bbb0b46..bfcfa0b90b15 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -810,7 +810,7 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
     LLDB_LOG(log, "  CEDM::FEVD Adding type for $__lldb_class: {1}",
              class_qual_type.getAsString());
 
-    AddContextClassType(context, class_user_type);
+    AddContextClassType(context, class_user_type, method_decl);
 
     if (method_decl->isInstance()) {
       // self is a pointer to the object
@@ -1889,8 +1889,9 @@ void ClangExpressionDeclMap::AddOneFunction(NameSearchContext &context,
   }
 }
 
-void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
-                                                 const TypeFromUser &ut) {
+void ClangExpressionDeclMap::AddContextClassType(
+    NameSearchContext &context, const TypeFromUser &ut,
+    CXXMethodDecl *context_method) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
@@ -1912,7 +1913,12 @@ void ClangExpressionDeclMap::AddContextClassType(NameSearchContext &context,
         void_clang_type, &void_ptr_clang_type, 1, false, 0);
 
     const bool is_virtual = false;
-    const bool is_static = false;
+    // If we evaluate an expression inside a static method, we also need to
+    // make our lldb_expr method static so that Clang denies access to
+    // non-static members.
+    // If we don't have a context_method we are evaluating within a context
+    // object and we can allow access to non-static members.
+    const bool is_static = context_method ? context_method->isStatic() : false;
     const bool is_inline = false;
     const bool is_explicit = false;
     const bool is_attr_used = true;

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index a9cd5d166b9d..f1a0e21452d9 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -608,8 +608,13 @@ class ClangExpressionDeclMap : public ClangASTSource {
   ///
   /// \param[in] type
   ///     The type of the class that serves as the evaluation context.
-  void AddContextClassType(NameSearchContext &context,
-                           const TypeFromUser &type);
+  ///
+  /// \param[in] context_method
+  ///     The member function declaration in which the expression is being
+  ///     evaluated or null if the expression is not evaluated in the context
+  ///     of a member function.
+  void AddContextClassType(NameSearchContext &context, const TypeFromUser &type,
+                           clang::CXXMethodDecl *context_method = nullptr);
 
   /// Move a type out of the current ASTContext into another, but make sure to
   /// export all components of the type also.

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
index 59a2e8795260..837e212b4984 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
@@ -419,6 +419,7 @@ bool ClangExpressionSourceCode::GetText(
                          module_imports.c_str(), m_name.c_str(),
                          lldb_local_var_decls.GetData(), tagged_body.c_str());
       break;
+    case WrapKind::CppStaticMemberFunction:
     case WrapKind::CppMemberFunction:
       wrap_stream.Printf("%s"
                          "void                                   \n"

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
index 54ae837fb30f..509cab98c875 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
@@ -33,12 +33,13 @@ class ClangExpressionSourceCode : public ExpressionSourceCode {
   enum class WrapKind {
     /// Wrapped in a non-static member function of a C++ class.
     CppMemberFunction,
+    /// Wrapped in a static member function of a C++ class.
+    CppStaticMemberFunction,
     /// Wrapped in an instance Objective-C method.
     ObjCInstanceMethod,
     /// Wrapped in a static Objective-C method.
     ObjCStaticMethod,
     /// Wrapped in a non-member function.
-    /// Note that this is also used for static member functions of a C++ class.
     Function
   };
 

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
index 9be294750fa0..9c01d2c5edc7 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -155,32 +155,35 @@ void ClangUserExpression::ScanContext(ExecutionContext &exe_ctx, Status &err) {
     m_needs_object_ptr = true;
   } else if (clang::CXXMethodDecl *method_decl =
           TypeSystemClang::DeclContextGetAsCXXMethodDecl(decl_context)) {
-    if (m_allow_cxx && method_decl->isInstance()) {
-      if (m_enforce_valid_object) {
-        lldb::VariableListSP variable_list_sp(
-            function_block->GetBlockVariableList(true));
+    if (m_allow_cxx) {
+      if (method_decl->isInstance()) {
+        if (m_enforce_valid_object) {
+          lldb::VariableListSP variable_list_sp(
+              function_block->GetBlockVariableList(true));
 
-        const char *thisErrorString = "Stopped in a C++ method, but 'this' "
-                                      "isn't available; pretending we are in a "
-                                      "generic context";
+          const char *thisErrorString =
+              "Stopped in a C++ method, but 'this' "
+              "isn't available; pretending we are in a "
+              "generic context";
 
-        if (!variable_list_sp) {
-          err.SetErrorString(thisErrorString);
-          return;
-        }
+          if (!variable_list_sp) {
+            err.SetErrorString(thisErrorString);
+            return;
+          }
 
-        lldb::VariableSP this_var_sp(
-            variable_list_sp->FindVariable(ConstString("this")));
+          lldb::VariableSP this_var_sp(
+              variable_list_sp->FindVariable(ConstString("this")));
 
-        if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
-            !this_var_sp->LocationIsValidForFrame(frame)) {
-          err.SetErrorString(thisErrorString);
-          return;
+          if (!this_var_sp || !this_var_sp->IsInScope(frame) ||
+              !this_var_sp->LocationIsValidForFrame(frame)) {
+            err.SetErrorString(thisErrorString);
+            return;
+          }
         }
+        m_needs_object_ptr = true;
       }
-
       m_in_cplusplus_method = true;
-      m_needs_object_ptr = true;
+      m_in_static_method = !method_decl->isInstance();
     }
   } else if (clang::ObjCMethodDecl *method_decl =
                  TypeSystemClang::DeclContextGetAsObjCMethodDecl(
@@ -401,9 +404,11 @@ ClangExpressionSourceCode::WrapKind ClangUserExpression::GetWrapKind() const {
   assert(m_options.GetExecutionPolicy() != eExecutionPolicyTopLevel &&
          "Top level expressions aren't wrapped.");
   using Kind = ClangExpressionSourceCode::WrapKind;
-  if (m_in_cplusplus_method)
+  if (m_in_cplusplus_method) {
+    if (m_in_static_method)
+      return Kind::CppStaticMemberFunction;
     return Kind::CppMemberFunction;
-  else if (m_in_objectivec_method) {
+  } else if (m_in_objectivec_method) {
     if (m_in_static_method)
       return Kind::ObjCStaticMethod;
     return Kind::ObjCInstanceMethod;

diff  --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
index b628f6debf66..5f6db2f80978 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -254,7 +254,7 @@ class ClangUserExpression : public LLVMUserExpression {
   bool m_in_objectivec_method = false;
   /// True if the expression is compiled as a static (or class) method
   /// (currently true if it was parsed when exe_ctx was in an Objective-C class
-  /// method).
+  /// method or static C++ member function).
   bool m_in_static_method = false;
   /// True if "this" or "self" must be looked up and passed in.  False if the
   /// expression doesn't really use them and they can be NULL.

diff  --git a/lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile b/lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
new file mode 100644
index 000000000000..99998b20bcb0
--- /dev/null
+++ b/lldb/test/API/lang/cpp/stopped_in_static_member_function/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules

diff  --git a/lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py b/lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
new file mode 100644
index 000000000000..e1cfa12305cc
--- /dev/null
+++ b/lldb/test/API/lang/cpp/stopped_in_static_member_function/TestStoppedInStaticMemberFunction.py
@@ -0,0 +1,38 @@
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @no_debug_info_test
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "// break in static member function", lldb.SBFileSpec("main.cpp"))
+
+        # Evaluate a static member and call a static member function.
+        self.expect_expr("static_member_var", result_type="int", result_value="2")
+        self.expect_expr("static_const_member_var", result_type="const int", result_value="3")
+        self.expect_expr("static_constexpr_member_var", result_type="const int", result_value="4")
+        self.expect_expr("static_func()", result_type="int", result_value="6")
+
+        # Check that accessing non-static members just reports a diagnostic.
+        self.expect("expr member_var", error=True,
+                    substrs=["invalid use of member 'member_var' in static member function"])
+        self.expect("expr member_func()", error=True,
+                    substrs=["call to non-static member function without an object argument"])
+        self.expect("expr this", error=True,
+                    substrs=["invalid use of 'this' outside of a non-static member function"])
+
+        # Continue to a non-static member function of the same class and make
+        # sure that evaluating non-static members now works.
+        breakpoint = self.target().BreakpointCreateBySourceRegex(
+            "// break in member function", lldb.SBFileSpec("main.cpp"))
+        self.assertNotEqual(breakpoint.GetNumResolvedLocations(), 0)
+        stopped_threads = lldbutil.continue_to_breakpoint(self.process(), breakpoint)
+
+        self.expect_expr("member_var", result_type="int", result_value="1")
+        self.expect_expr("member_func()", result_type="int", result_value="5")

diff  --git a/lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp b/lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp
new file mode 100644
index 000000000000..8c8b7c183903
--- /dev/null
+++ b/lldb/test/API/lang/cpp/stopped_in_static_member_function/main.cpp
@@ -0,0 +1,31 @@
+struct A {
+  int member_var = 1;
+  static int static_member_var;
+  static const int static_const_member_var;
+  static constexpr int static_constexpr_member_var = 4;
+  int member_func() { return 5; }
+  static int static_func() { return 6; }
+
+  static int context_static_func() {
+    int i = static_member_var;
+    i += static_func();
+    return i; // break in static member function
+  }
+
+  int context_member_func() {
+    int i = member_var;
+    i += member_func();
+    return i; // break in member function
+  }
+};
+
+int A::static_member_var = 2;
+const int A::static_const_member_var = 3;
+constexpr int A::static_constexpr_member_var;
+
+int main() {
+  int i = A::context_static_func();
+  A a;
+  a.context_member_func();
+  return i;
+}


        


More information about the lldb-commits mailing list