@@ -126,6 +126,7 @@ TNamedParamDesc = record
126
126
127
127
{ $IFDEF DELPHIXE2_OR_HIGHER}
128
128
{ $DEFINE USESYSTEMDISPINVOKE} // Delphi 2010 DispInvoke is buggy
129
+ { $DEFINE PATCHEDSYSTEMDISPINVOKE} // To correct memory leaks
129
130
{ $ENDIF}
130
131
{ .$IF DEFINED(FPC_FULLVERSION) and (FPC_FULLVERSION >= 20500)}
131
132
{ .$DEFINE USESYSTEMDISPINVOKE}
@@ -944,17 +945,40 @@ procedure TPythonVariantType.DispInvoke(Dest: PVarData;
944
945
var Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
945
946
{ $ENDIF}
946
947
{ $IFDEF USESYSTEMDISPINVOKE}
947
- { $IFDEF DELPHIXE2_OR_HIGHER}
948
- // Modified to correct memory leak QC102387
948
+ { $IFDEF PATCHEDSYSTEMDISPINVOKE}
949
+ // Modified to correct memory leak QC102387 / RSP-23093
950
+ procedure PatchedFinalizeDispatchInvokeArgs (CallDesc: PCallDesc; const Args: TVarDataArray; OrderLTR : Boolean);
951
+ const
952
+ atByRef = $80 ;
953
+ var
954
+ I: Integer;
955
+ ArgType: Byte;
956
+ PVarParm: PVarData;
957
+ VType: TVarType;
958
+ begin
959
+ for I := 0 to CallDesc^.ArgCount-1 do
960
+ begin
961
+ ArgType := CallDesc^.ArgTypes[I];
962
+
963
+ if OrderLTR then
964
+ PVarParm := @Args[I]
965
+ else
966
+ PVarParm := @Args[CallDesc^.ArgCount-I-1 ];
967
+
968
+ VType := PVarParm.VType;
969
+
970
+ // Only ByVal Variant or Array parameters have been copied and need to be released
971
+ // Strings have been released via the use of the TStringRefList parameter to GetDispatchInvokeArgs
972
+ // !!Modified to prevent memory leaks!! RSP-23093
973
+ if ((ArgType and atByRef) <> atByRef) and ((ArgType = varVariant) or ((VType and varArray) = varArray)) then
974
+ VarClear(PVariant(PVarParm)^);
975
+ end ;
976
+ end ;
977
+
949
978
procedure PatchedDispInvoke (Dest: PVarData;
950
979
const Source: TVarData; CallDesc: PCallDesc; Params: Pointer);
951
980
type
952
- PParamRec = ^TParamRec;
953
- TParamRec = array [0 ..3 ] of LongInt;
954
- TStringDesc = record
955
- BStr: WideString;
956
- PStr: PAnsiString;
957
- end ;
981
+ PStringRefList = ^TStringRefList;
958
982
const
959
983
CDoMethod = $01 ;
960
984
CPropertyGet = $02 ;
@@ -964,67 +988,75 @@ TStringDesc = record
964
988
LIdent: string;
965
989
LTemp: TVarData;
966
990
VarParams : TVarDataArray;
967
- Strings: TStringRefList;
991
+ Strings: array of TStringRef;
992
+ PIdent: PByte;
968
993
begin
969
994
// Grab the identifier
970
995
LArgCount := CallDesc^.ArgCount;
971
- LIdent := FixupIdent(string(AnsiString(PAnsiChar(@CallDesc^.ArgTypes[LArgCount]))));
972
-
973
- FillChar(Strings, SizeOf(Strings), 0 );
974
- VarParams := GetDispatchInvokeArgs(CallDesc, Params, Strings, true);
975
-
976
- // What type of invoke is this?
977
- case CallDesc^.CallType of
978
- CDoMethod:
979
- // procedure with N arguments
980
- if Dest = nil then
981
- begin
982
- if not DoProcedure(Source, LIdent, VarParams) then
996
+ PIdent := @CallDesc^.ArgTypes[LArgCount];
997
+ LIdent := FixupIdent( UTF8ToString(MarshaledAString(PIdent)) );
998
+ if LArgCount > 0 then begin
999
+ SetLength(Strings, LArgCount);
1000
+ FillChar(Strings[0 ], SizeOf(TStringRef)*LArgCount, 0 );
1001
+ VarParams := GetDispatchInvokeArgs(CallDesc, Params, PStringRefList(Strings)^, true);
1002
+ end ;
1003
+ try
1004
+ // What type of invoke is this?
1005
+ case CallDesc^.CallType of
1006
+ CDoMethod:
1007
+ // procedure with N arguments
1008
+ if Dest = nil then
983
1009
begin
1010
+ if not DoProcedure(Source, LIdent, VarParams) then
1011
+ begin
1012
+
1013
+ // ok maybe its a function but first we must make room for a result
1014
+ VarDataInit(LTemp);
1015
+ try
1016
+
1017
+ // notate that the destination shouldn't be bothered with
1018
+ // functions can still return stuff, we just do this so they
1019
+ // can tell that they don't need to if they don't want to
1020
+ SetClearVarToEmptyParam(LTemp);
1021
+
1022
+ // ok lets try for that function
1023
+ if not DoFunction(LTemp, Source, LIdent, VarParams) then
1024
+ RaiseDispError;
1025
+ finally
1026
+ VarDataClear(LTemp);
1027
+ end ;
1028
+ end
1029
+ end
984
1030
985
- // ok maybe its a function but first we must make room for a result
986
- VarDataInit(LTemp);
987
- try
988
-
989
- // notate that the destination shouldn't be bothered with
990
- // functions can still return stuff, we just do this so they
991
- // can tell that they don't need to if they don't want to
992
- SetClearVarToEmptyParam(LTemp);
993
-
994
- // ok lets try for that function
995
- if not DoFunction(LTemp, Source, LIdent, VarParams) then
996
- RaiseDispError;
997
- finally
998
- VarDataClear(LTemp);
999
- end ;
1031
+ // property get or function with 0 argument
1032
+ else if LArgCount = 0 then
1033
+ begin
1034
+ if not GetProperty(Dest^, Source, LIdent) and
1035
+ not DoFunction(Dest^, Source, LIdent, VarParams) then
1036
+ RaiseDispError;
1000
1037
end
1001
- end
1002
1038
1003
- // property get or function with 0 argument
1004
- else if LArgCount = 0 then
1005
- begin
1006
- if not GetProperty(Dest^, Source, LIdent) and
1007
- not DoFunction(Dest^, Source, LIdent, VarParams) then
1039
+ // function with N arguments
1040
+ else if not DoFunction(Dest^, Source, LIdent, VarParams) then
1008
1041
RaiseDispError;
1009
- end
1010
1042
1011
- // function with N arguments
1012
- else if not DoFunction(Dest^, Source, LIdent, VarParams) then
1013
- RaiseDispError;
1043
+ CPropertyGet:
1044
+ if not ((Dest <> nil ) and // there must be a dest
1045
+ (LArgCount = 0 ) and // only no args
1046
+ GetProperty(Dest^, Source, LIdent)) then // get op be valid
1047
+ RaiseDispError;
1014
1048
1015
- CPropertyGet:
1016
- if not ((Dest <> nil ) and // there must be a dest
1017
- (LArgCount = 0 ) and // only no args
1018
- GetProperty(Dest^, Source, LIdent)) then // get op be valid
1019
- RaiseDispError;
1049
+ CPropertySet:
1050
+ if not ((Dest = nil ) and // there can't be a dest
1051
+ (LArgCount = 1 ) and // can only be one arg
1052
+ SetProperty(Source, LIdent, VarParams[0 ])) then // set op be valid
1053
+ RaiseDispError;
1054
+ else
1055
+ RaiseDispError;
1056
+ end ;
1020
1057
1021
- CPropertySet:
1022
- if not ((Dest = nil ) and // there can't be a dest
1023
- (LArgCount = 1 ) and // can only be one arg
1024
- SetProperty(Source, LIdent, VarParams[0 ])) then // set op be valid
1025
- RaiseDispError;
1026
- else
1027
- RaiseDispError;
1058
+ finally
1059
+ PatchedFinalizeDispatchInvokeArgs(CallDesc, VarParams, true);
1028
1060
end ;
1029
1061
1030
1062
for I := 0 to Length(Strings) - 1 do
@@ -1033,13 +1065,12 @@ TStringDesc = record
1033
1065
Break;
1034
1066
if Strings[I].Ansi <> nil then
1035
1067
Strings[I].Ansi^ := AnsiString(Strings[I].Wide)
1036
- else if Strings[I].Unicode <> nil then
1037
- Strings[I].Unicode^ := UnicodeString(Strings[I].Wide)
1068
+ else
1069
+ if Strings[I].Unicode <> nil then
1070
+ Strings[I].Unicode^ := UnicodeString(Strings[I].Wide)
1038
1071
end ;
1039
- for I := Low(VarParams) to High(VarParams) do
1040
- VarDataClear(VarParams[I]);
1041
1072
end ;
1042
- { $ENDIF DELPHIXE2_OR_HIGHER }
1073
+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
1043
1074
1044
1075
procedure GetNamedParams ;
1045
1076
var
@@ -1066,17 +1097,17 @@ TStringDesc = record
1066
1097
if (CallDesc^.CallType = CPropertyGet) and (CallDesc^.ArgCount = 1 ) then begin
1067
1098
NewCallDesc := CallDesc^;
1068
1099
NewCallDesc.CallType := CDoMethod;
1069
- { $IFDEF DELPHIXE2_OR_HIGHER }
1100
+ { $IFDEF PATCHEDSYSTEMDISPINVOKE }
1070
1101
PatchedDispInvoke(Dest, Source, @NewCallDesc, Params);
1071
- { $ELSE DELPHIXE2_OR_HIGHER }
1102
+ { $ELSE PATCHEDSYSTEMDISPINVOKE }
1072
1103
inherited DispInvoke(Dest, Source, @NewCallDesc, Params);
1073
- { $ENDIF DELPHIXE2_OR_HIGHER }
1104
+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
1074
1105
end else
1075
- { $IFDEF DELPHIXE2_OR_HIGHER }
1106
+ { $IFDEF PATCHEDSYSTEMDISPINVOKE }
1076
1107
PatchedDispInvoke(Dest, Source, CallDesc, Params);
1077
- { $ELSE DELPHIXE2_OR_HIGHER }
1108
+ { $ELSE PATCHEDSYSTEMDISPINVOKE }
1078
1109
inherited ;
1079
- { $ENDIF DELPHIXE2_OR_HIGHER }
1110
+ { $ENDIF PATCHEDSYSTEMDISPINVOKE }
1080
1111
finally
1081
1112
if CallDesc^.NamedArgCount > 0 then SetLength(fNamedParams, 0 );
1082
1113
end ;
0 commit comments