From 9fa429e50534770c239790e7071c4165c7822373 Mon Sep 17 00:00:00 2001 From: Med Ismail Bennani Date: Mon, 1 Dec 2025 12:47:00 -0800 Subject: [PATCH] [lldb] Handle staticmethod/classmethod descriptors in ScriptedPythonInterface Extract `__func__` attribute from staticmethod/classmethod descriptors before treating them as callables. Python's @staticmethod and @classmethod decorators wrap methods in descriptor objects that are not directly usable as PythonCallable, when calling PyCallable_Check. The actual callable function is stored in the `__func__` attribute of these descriptors, so we need to unwrap them to properly validate and invoke the decorated methods in scripted interfaces. Signed-off-by: Med Ismail Bennani --- .../Python/Interfaces/ScriptedPythonInterface.h | 3 ++- .../ScriptInterpreter/Python/PythonDataObjects.cpp | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h index cdda66abc562b..5f5665c495770 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h +++ b/lldb/source/Plugins/ScriptInterpreter/Python/Interfaces/ScriptedPythonInterface.h @@ -74,7 +74,8 @@ class ScriptedPythonInterface : virtual public ScriptedInterface { if (!class_dict.HasKey(method_name)) SET_CASE_AND_CONTINUE(method_name, AbstractMethodCheckerCases::eNotImplemented) - auto callable_or_err = class_dict.GetItem(method_name); + llvm::Expected callable_or_err = + class_dict.GetItem(method_name); if (!callable_or_err) { llvm::consumeError(callable_or_err.takeError()); SET_CASE_AND_CONTINUE(method_name, diff --git a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp index a2a287a6714db..d2f795cb5a20a 100644 --- a/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp +++ b/lldb/source/Plugins/ScriptInterpreter/Python/PythonDataObjects.cpp @@ -810,6 +810,17 @@ bool PythonCallable::Check(PyObject *py_obj) { if (!py_obj) return false; + PythonObject python_obj(PyRefType::Borrowed, py_obj); + + // Handle staticmethod/classmethod descriptors by extracting the + // `__func__` attribute. + if (python_obj.HasAttribute("__func__")) { + PythonObject function_obj = python_obj.GetAttributeValue("__func__"); + if (!function_obj.IsAllocated()) + return false; + return PyCallable_Check(function_obj.release()); + } + return PyCallable_Check(py_obj); }