From 27b7ae88d4351594823d8632802489a864f3b746 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Thu, 14 Jul 2022 00:45:26 +0300 Subject: [PATCH 1/3] Avoid access violation in TPythonModule.GetVarAsVariant (see https://en.delphipraxis.net/topic/7085-returning-lists-from-python-to-delphi/) --- Source/PythonEngine.pas | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index 13527c0b..d924c8a5 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -7311,11 +7311,12 @@ function TPythonModule.GetVarAsVariant( const varName : AnsiString ) : Variant; with Engine do begin obj := GetVar( varName ); - try - Result := PyObjectAsVariant( obj ); - finally - Py_XDecRef(obj); - end; + if Assigned(obj) then + try + Result := PyObjectAsVariant( obj ); + finally + Py_XDecRef(obj); + end; end; end; From cd5fbbbd8d70353e9123e741989c57f336da5239 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 16 Jul 2022 18:39:24 +0300 Subject: [PATCH 2/3] Minor fixes --- Source/WrapDelphiWindows.pas | 2 +- Source/vcl/WrapVclForms.pas | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/WrapDelphiWindows.pas b/Source/WrapDelphiWindows.pas index 9601f057..d0bc0aa9 100644 --- a/Source/WrapDelphiWindows.pas +++ b/Source/WrapDelphiWindows.pas @@ -185,7 +185,7 @@ class function TWindowsRegistration.SetProcessDpiAwareness_Wrapper(PySelf, {$ENDIF DELPHI11_OR_HIGHER} initialization - RegisteredUnits.Add( TWindowsRegistration.Create ); + RegisteredUnits.Add(TWindowsRegistration.Create); {$IFDEF MSWINDOWS} {$IFDEF DELPHI11_OR_HIGHER} diff --git a/Source/vcl/WrapVclForms.pas b/Source/vcl/WrapVclForms.pas index d0a34631..d40e9ef9 100644 --- a/Source/vcl/WrapVclForms.pas +++ b/Source/vcl/WrapVclForms.pas @@ -591,8 +591,8 @@ function TPyDelphiCustomForm.LoadProps_Wrapper(args: PPyObject): PPyObject; Exit(GetPythonEngine().ReturnFalse); except on E: Exception do - GetPythonEngine().PyErr_SetString(PyExc_RuntimeError^, - PAnsiChar(AnsiString(E.Message))); + with GetPythonEngine() do + PyErr_SetString(PyExc_RuntimeError^, PAnsiChar(AnsiString(E.Message))); end; Result := nil; end; From 556b33e7fc52d7258b5ab2bb1f70408c313c6311 Mon Sep 17 00:00:00 2001 From: pyscripter Date: Sat, 16 Jul 2022 23:55:48 +0300 Subject: [PATCH 3/3] Fix #368 --- Source/PythonEngine.pas | 2 ++ Source/WrapDelphi.pas | 44 +++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/Source/PythonEngine.pas b/Source/PythonEngine.pas index d924c8a5..5e6802ad 100644 --- a/Source/PythonEngine.pas +++ b/Source/PythonEngine.pas @@ -1521,6 +1521,7 @@ TPythonInterface=class(TDynamicDll) PyObject_GetAttrString:function (ob:PPyObject;c:PAnsiChar):PPyObject; cdecl; PyObject_GetItem:function (ob,key:PPyObject):PPyObject; cdecl; PyObject_DelItem:function (ob,key:PPyObject):PPyObject; cdecl; + PyObject_HasAttr:function (ob, attr_name:PPyObject):integer; cdecl; PyObject_HasAttrString:function (ob:PPyObject;key:PAnsiChar):integer; cdecl; PyObject_Hash:function (ob:PPyObject):NativeInt; cdecl; PyObject_IsTrue:function (ob:PPyObject):integer; cdecl; @@ -3711,6 +3712,7 @@ procedure TPythonInterface.MapDll; PyObject_GetAttrString := Import('PyObject_GetAttrString'); PyObject_GetItem := Import('PyObject_GetItem'); PyObject_DelItem := Import('PyObject_DelItem'); + PyObject_HasAttr := Import('PyObject_HasAttr'); PyObject_HasAttrString := Import('PyObject_HasAttrString'); PyObject_Hash := Import('PyObject_Hash'); PyObject_IsTrue := Import('PyObject_IsTrue'); diff --git a/Source/WrapDelphi.pas b/Source/WrapDelphi.pas index c3188749..a9925f5c 100644 --- a/Source/WrapDelphi.pas +++ b/Source/WrapDelphi.pas @@ -2226,9 +2226,10 @@ function TPyDelphiObject.GetAttrO(key: PPyObject): PPyObject; Result := inherited GetAttrO(key); if GetPythonEngine.PyErr_Occurred = nil then Exit; // We found what we wanted - if Assigned(DelphiObject) and GetPythonEngine.PyUnicode_Check(Key) then - KeyName := GetPythonEngine.PyUnicodeAsString(Key) - else + // should not happen + if not (Assigned(DelphiObject) and + CheckStrAttribute(Key, 'GetAttrO key parameter', KeyName)) + then Exit; GetPythonEngine.PyErr_Clear; @@ -2512,11 +2513,15 @@ function TPyDelphiObject.Repr: PPyObject; function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; (* - First look whether the attribute has ben wrapped (RegisterGetSet, RegisterMethod). - This is done by calling the inherited SetAttrO. If this fails then + First look whether the attribute exists., e.g. has been wrapped with + RegisterGetSet, RegisterMethod, etc. + If it does then the inherited generic SetAttrO is called. + If the attribute does not exist or the generic SetAttO fails (unlikely) then - Use Rtti to locate the property in DELPHIXE_OR_HIGHER (EXTENDED_RTTI) or for other versions - Look for published properties + Finally, if all the above fail then you call the inherited generic SetAttrO + which adds a new field in the object dictionary *) function HandleEvent(PropInfo: PPropInfo; out ErrMsg: string) : Integer; @@ -2582,20 +2587,29 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; {$ENDIF} KeyName: string; ErrMsg: string; + PyEngine: TPythonEngine; + PyObj: PPyobject; begin Result := -1; - if Assigned(DelphiObject) and GetPythonEngine.PyUnicode_Check(Key) then - KeyName := GetPythonEngine.PyUnicodeAsString(Key) - else begin + PyEngine := GetPythonEngine; + + // should not happen + if not (Assigned(DelphiObject) and + CheckStrAttribute(Key, 'SetAttrO key parameter', KeyName)) + then Exit; - end; - // Only call the inherited method if the attribute exists - if GetPythonEngine.PyObject_HasAttrString(GetSelf, PAnsiChar(key)) = 1 then + // Only call the inherited method at this stage if the attribute exists + PyObj := PyEngine.PyObject_GenericGetAttr(GetSelf, key); + if Assigned(PyObj) then + begin + PyEngine.Py_DECREF(PyObj); // not needed Result := inherited SetAttrO(key, value); - if Result = 0 then Exit; + if Result = 0 then + Exit; + end; - GetPythonEngine.PyErr_Clear; + PyEngine.PyErr_Clear; {$IFDEF EXTENDED_RTTI} Context := TRttiContext.Create(); try @@ -2623,8 +2637,8 @@ function TPyDelphiObject.SetAttrO(key, value: PPyObject): Integer; if Result <> 0 then Result := inherited SetAttrO(key, value); if Result <> 0 then - with GetPythonEngine do - PyErr_SetObject(PyExc_AttributeError^, PyUnicodeFromString( + with PyEngine do + PyErr_SetObject(PyEngine.PyExc_AttributeError^, PyUnicodeFromString( Format(rs_ErrAttrSetr, [KeyName, ErrMsg]))); end;