-1

適切にフォーマットされていない JSON オブジェクトを非整列化しようとすると、UnMarshall 関数からのオブジェクト参照が期待されますが、nil になります。しかし、アプリケーションを閉じると、そのオブジェクトがメモリ リークを生成します。

TMyObject = class
private
  FName: String;
end;

AJSON := TJSONObject.ParseJSONValue('{ type: "MyObject.TMyObject", id: 1, fields: { FName: "David", FAge: 20 } }');

//FAge attribute don't exists in TMyObject, so it raises an exception when unmarshalling


with TJSONUnMarshal.Create() do  
begin  
  try
    Result := Unmarshal( AJSON );
    //First chance exception at $77322F71. Exception class EConversionError with message 'Internal: Field FAge cannot be found in type TMyObject'. Process MyApp.exe (3056)
  finally
    Free();
  end;
  //Here the result is nil, but internally the object was created and is alive
end

function TJSONUnMarshal.Unmarshal(Data: TJSONValue): TObject;
  var
    Root: TJSONObject;
begin
  if not (Data is TJSONObject) then
    raise EConversionError.Create(SCannotCreateObject);

  // clear previous warnings
  ClearWarnings;
  Root := TJSONObject(Data);
  try
    Result := CreateObject(Root)
  finally
    FObjectHash.Clear;
  end;
end;

JSON オブジェクトが予期された形式でない場合、例外が発生しますが、参照を作成したオブジェクトを破棄せず、関数でそれを返しません。

したがって、サーバーを消費する人はいくつかの関数を呼び出すことができ、リクエストに送信された JSON が適切にフォーマットされていることを保証するものは何もありません。

どうすればこのような状況に対処できますか? それぞれのクラスで JSON オブジェクトを検証する方法はありますか?

ps: Delphi XE7 を使用しています。

4

2 に答える 2

0

Unmarshalオブジェクトを作成し、すべてのオブジェクトを別々に扱う場合、(おそらく) 使用します。

AJSON := TJSONObject.ParseJSONValue('{ type: "MyObject.TMyObject", id: 1, fields: { FName: "David", FAge: 20 } }');

try
  if Assigned(AJSON) then
    UnmarshalThisObject(AJSON);  
finally
  FreeAndNil(AJSON);
end;

procedure UnmarshalThisObject(AJSON: TJSONObject);
var
  oUnMarshalObject: TJSONUnMarshal;
  oUnMarshalResult: TUnmarshalType {dont know};
begin
  if Assigned(AJSON) then
  begin
    oUnMarshalObject := TJSONUnMarshal.Create();
    try
      oUnMarshalResult := oUnMarshalObject.Unmarshal(AJSON);
    finally
      FreeAndNil(oUnMarshalResult);
      FreeAndNil(oUnMarshalObject);
    end;
  end;
end;

それが役に立てば幸い。

于 2014-09-30T17:42:53.603 に答える
0

Unmarshal新しく作成されたオブジェクトを返すような関数は、次のように実装する必要があります。

function CreateObj: TObject;
begin
  Result := TObject.Create;
  try
    // do stuff with Result
  except
    Result.Free;
    raise;
  end;
end;

にそのようなtry/exceptブロックUnmarshalがなく、チェックするコードが表示されない場合は、発生するたびにリークします。

外部からできることはあまりありません。このようなバグは、外部から簡単に修正することはできません。オブジェクトが漏洩すると、それを手に入れて破壊することはできません。

QCレポートは必ず提出してください。短期的には、不足している/ブロックUnmarshalを追加するために、コードを変更して再コンパイルする必要があるかもしれませんtryexcept


この問題に対処する別の方法は、例外につながるこの関数入力のフィードを停止することだと思います。

  1. 例外が送信の失敗によるものである場合は、送信されたデータをハッシュし、受信時にハッシュをチェックして問題を軽減します。
  2. 例外がクライアントとサーバー間のバージョンの非互換性によるものである場合は、バージョン チェックを強化してください。
  3. 例外が一般的なプログラミング エラーによるものである場合は、エラーを修正します。
于 2014-09-30T18:19:02.890 に答える