viniciussanchez / dataset-serialize

JSON to DataSet and DataSet to JSON converter for Delphi and Lazarus (FPC)
MIT License
645 stars 156 forks source link

Violação de acesso de memória (FPC: 3.3 - Lazarus: 3) #211

Closed edsontmarques closed 10 months ago

edsontmarques commented 11 months ago

Detectei um erro de violação de acesso de memória ao dar Free em um TJSONObject na seguinte situação:

procedure TfraUsuarios.DoRequestJSON;
var
  Response: IResponse;
  JSONObject: TJSONObject;
begin
  Response := TRequest.New
                                         .BaseURL('http://xxx:9000/yyy/zzz');
                                         .ContentType('application/json')
                                         .Get;

  JSONObject := GetJSON(Response.Content) as TJSONObject;
  try
    if JSONObject.Booleans['status'] then
    begin
      dtsTeste.DataSet.DisableControls;
      try
        dtsTeste.DataSet.Close;
        dtsTeste.DataSet.LoadStructure(JSONObject.Arrays['structure']);
        dstTeste.CreateDataset;
        dtsTeste.DataSet.LoadFromJSON(JSONObject.Arrays['data']);
        dtsTeste.DataSet.First;
      finally
        dtsTeste.DataSet.EnableControls;
      end;
  finally
    JSONObject.Free;
  end;
end; 

Tanto LoadStructure() como LoadFromJSON() podem provocar a violação de acesso. Basta comentar qualquer uma das duas que o JSONObject.Free funciona normalmente.

Infelizmente não tive condições de aprofundar mais para entender a causa.

mbertolani commented 11 months ago

Verifica a função GetJson, no seu exemplo o compilador vai liberar a o JSONObject automaticamente, por isso dá erro quando tenta destruir o objeto

edsontmarques commented 11 months ago

Obrigado pela resposta. Vou verificar... Mas é como expliquei: Se comentarmos as chamadas de LoadStructure e LoadFromJSON, a liberação de memória ocorre normalmente quando a execução chega em JSONObject.Free. Pelo comportamento parece que há alguma interferência do Dataset-Serialize... "parece"... Se alguma estrutura deste código do exemplo estiver assumindo desalocação o JSONObject, mesmo assim, parece que há algum problema nessa tentativa, porque está ocorrendo memory leak. Eu fiz o teste... tentei apenas comentar o comando JSONObject.Free, justamente considerando que alguém estivesse fazendo a desalocação no meio do caminho. Mas percebi que, comentando o JSONObject.Free, ocorre memory leak.

viniciussanchez commented 10 months ago

Se olhar o código fonte dos métodos, ou até mesmo no Ctrl+barra de espaço, vai ver a documentação feita em XML Doc

image

Existe o parâmetro para você informar quem é o dono do JSON. No caso por padrão o dono é o DataSet-Serialize. Ou seja, ele mesmo destroi o JSON passado como parâmetro. Sendo assim, quando você tenta destruir o JSON depois, vai dar o Access violation, porque ele já foi destruído.

O mesmo acontece no LoadFromJSON:

image

Desculpa a demora em responder...