这个问题是提供一个MCVE来说明我之前的答案所揭示的问题:
Unexpected failure of custom registered Reverter using TJSONUnMarshal
在我之前的q中,@ VirusTrinity的答案解决了我最初遇到的问题, 即通过解组操作获得的对象被错误地返回 使用Nil TStringlist字段。但是,修复程序发现了一个新问题,就是这个问题 在关闭应用程序时,它会生成0xC0000005异常,访问冲突 地址0x00000000读取地址0x00000000。下面的代码显示了这种行为,生成 关机时AV相同,原因相同。
由于在Data.DBXJSONReflect中PopulateFields(objFields, Obj, customizer);
执行function TJSONUnMarshal.CreateObject(JsonObj: TJSONObject): TObject
期间内存损坏,显然会发生AV。
如果您在代码中放置了如下所示的断点,请添加一个监视 TEncoding.FAnsiEncoding然后单步执行
AnObject:= jUnmarshal.Unmarshal(jValue);
你应该发现FMaxCharSize中的值从1变为5(有时候 在之前的q我得到7而不是5)。这种变化似乎是对症 内存损坏,显然导致AV关机。
更新:要查看AV发生的位置,请在类过程TEncoding.FreeEncodings的入口点放置一个断点。对我来说,AV发生在
FreeAndNil(FANSIEncoding);
被调用。
更新#2: TEncoding.FAnsiEncoding损坏的地方是使用Field参数值function TJSONUnMarshal.ClassTypeOf
调用FDelimiter
并执行语句
fRtti := tRtti.GetField(Field);
对ClassTypeOf
的调用来自声明
else if HasReverter(ComposeKey(ClassTypeOf(Data, FieldName),
FIELD_ANY)) then
在procedure TJSONUnMarshal.PopulateFields
任何人都可以确认问题并告知原因吗?
代码:
program MATest;
{$APPTYPE CONSOLE}
uses Classes, System.SysUtils, JSon, DBXJson, DBXJSONReflect;
procedure Test;
var
TL1,
TL2 : TStringlist;
AnObject : TObject;
jMarshal: TJSONMarshal;
jUnMarshal : TJSonUnMarshal;
jValue: TJSONValue;
begin
TL1 := TStringlist.Create;
TL1.Add('AAA');
try
jMarshal := TJSONMarshal.Create(TJSONConverter.Create);
jValue := jMarshal.Marshal(TL1);
Writeln(jValue.ToString);
jUnMarshal := TJSONUnMarshal.Create; // < Put breakpoint here and
// add watch of TEncoding.FAnsiEncoding in System.SysUtils
AnObject:= jUnMarshal.UnMarshal(jValue);
TL2 := TStringlist(AnObject);
Writeln(TL2.Text);
Readln;
finally
jValue.Free;
jMarshal.Free;
jUnMarshal.Free;
TL1.Free;
TL2.Free;
end;
end;
begin
try
Test;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.