'Memory leak When Returning TJSONVALUE from Function

I have a JSON array of objects that I iterate. From each element of the array I retrieve further json data via a function that returns a JSONValue. I then must add that returned jsonvalue to the specific array element. It works perfectly except that Delphi is reporting a memory leak on shutdown and I just can't find it. I'm pretty new to JSON and I've spent all day on this. Can someone help by suggesting the right way to go about this. Simplified code below. Many Thanks.

function TForm1.Function1(ThisProductJSON: String): Integer;
Var
  MultiObj    : TJSONObject;
  OtherValues : TJSONVALUE;
  ThisObject  : TJSONObject;
  I           : Integer;
  jsArr       : TJSONARRAY;

  S:String;
  Stockcode : String;
begin
  MultiObj:=TJSONObject.Create(nil);
  s:='[{"ThisElement":1,"Thiscode":12345,"ThisBarcode":"2345678901231","Price":1.00,"Measure":"EA","Description":"Some Description"},'+
      '{"ThisElement":2,"Thiscode":21345,"ThisBarcode":"3124567890123","Price":2.00,"Measure":"EA","Description":"Some Description"},'+
      '{"ThisElement":3,"Thiscode":31345,"ThisBarcode":"6123457890123","Price":3.00,"Measure":"EA","Description":"Some Description"},'+
      '{"ThisElement":4,"Thiscode":41345,"ThisBarcode":"9123456780123","Price":4.00,"Measure":"EA","Description":"Some Description"},'+
      '{"ThisElement":5,"Thiscode":51345,"ThisBarcode":"8234567901235","Price":5.00,"Measure":"EA","Description":"Some Description"}]';
  ThisProductJSON:=S;
  try
    try

      MultiObj.AddPair('ThisName','ThisValue');
      MultiObj.AddPair('AnotherName','AnotherValue');
      I:=0;
      JSArr:=TJSONObject.ParseJSONValue(ThisProductJSON).AsType<TJSONARRAY>;
            //Process all products in the array with a call to detailed Rest for each product
             begin
                for I := 0 to jsArr.count-1 do //iterate through the array
                  begin

                    Stockcode:= jsArr.Items[I].GetValue<string>('Thiscode');

                    ThisObject:=TJSONObject(jsArr[i]); // Make ThisObject Point to the jsArr[i] as an object so I can add the Other Values to this array element

                    OtherValues :=(GetOtherDetails(Stockcode)); // Call the below function to return the JSONVALUE containing addtional data

                    ThisObject.AddPair('OtherDetails',OtherValues); // Add all of the additional data in OtherValues JSONVALUE to this element of array via the object
                  end;
                MultiObj.AddPair('WoWMultiProduct',JSARR); // This MultiObj hokds the consolidated data
              end;


    except
      On E: Exception do
        begin
           //Errror handling here
        end;
    end;

  finally
    MultiObj.Free;
    OtherValues.Free; // <<- I thought this would free the Result of the function but I think its leaking
    JSARR.Free;
    if assigned(ThisObject) then ThisObject.Free;
  end;
end;

function TForm1.GetOtherDetails(Stockcode: String): TJSONVALUE;
Var
  ThisResponseObject, MYRESULT  : TJSONOBJECT;
  vNIP, vCOO          : TJSONVALUE;

begin

  DetailedRESTRequest.execute;  //<-- This REST Service Returns aditional JSON data
  MyResult:=TJSONObject.Create;
  if DetailedRESTResponse.StatusCode=200 then
     begin
        Try

          Try
             ThisResponseObject := TJSONObject.ParseJSONValue(DetailedRESTResponse.content)as TJSONObject; // Resd the entire JSON Response into TJSONObject
              vCOO:=ThisResponseObject.Getvalue('COO'); // Get First JSON Value I need
              vNIP:=ThisResponseObject.Getvalue('Nip');  // Get Next JSON Value I Need
              MyResult.AddPair('NIPInfo',vNip); // Thiis is the only way I know how to Add the Values
              MyResult.AddPair('COO',vCOO);     // So that I can get them both together in the Result

              Result:= TJSONObject.ParseJSONValue(MyResult.ToJSON)as TJSONValue; // Get back the JSONValue from the function

          Except
              On E:Exception do
                begin
                  // Some Error Handling Here e.Classname+' ' +E.Message ;

                end;
          End;
        Finally
          If Assigned(ThisResponseObject) then ThisResponseObject.Free;
          // NOTE IF I FREE MYRESULT OBJECT I GET ACCESS VIOLATION WHEN I TRY TO USE THE RESULT OF THE FUNCTION
        End;

     end;

end;


Solution 1:[1]

JSON objects are a tree-like data structure. When you request a value from a node, with getvalue (for example), it is actually giving you a reference to that node's object.

so, when you do the following in the "GetOtherDetails" function:

vCOO:=ThisResponseObject.Getvalue('COO');
MyResult.AddPair('COO',vCOO);

You make ThisResponseObject and MyResult share nodes (memory locations), so when you free one of them the other will try to free memory locations that no longer exist and generate the access violation

ThisResponseObject.free;
MyResult.Free; //access violation

Similarly, on "Function1" when doing:

ThisObject:=TJSONObject(jsArr[i]);
OtherValues :=(GetOtherDetails(Stockcode)); 
ThisObject.AddPair('OtherDetails',OtherValues);

You're making ThisObject contain OtherValues object... so when you try to free the two objects you're going to run into memory problems.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GatoSoft