Skip to content

[Bug] JSON objects passed to forwards then iterated on causes memory problems #34

@nickdnk

Description

@nickdnk

Description

If you have two plugins where one creates an object and forwards it to another, say:

Plugin A:

public void OnPluginStart()
{
  gForward = new GlobalForward("FORWARD_NAME", ET_Ignore, Param_Cell);
  
  JSON_Object obj = new JSON_Object();
  Call_StartForward(gForward);
  Call_PushCell(obj);
  Call_Finish();
  
  json_cleanup_and_delete(obj);
}

Consumed by another plugin like this:

Plugin B:

public void FORWARD_NAME(const JSON_Object obj) {
  obj.Iterate(); // Do whatever, just call Iterate(), either directly
  // or via DeepCopy() or ShallowCopy():
  JSON_Object copy = obj.DeepCopy();
  // Do something, maybe async (SQL for instance), with copy
  json_cleanup_and_delete(copy);
}

The fact that Iterate() calls delete on the cached snapshot that belongs to obj (this silently fails) and creates a new one (which will fail when Plugin A calls delete on it) causes the consuming plugin to leak the snapshot it creates every time this method is called. From the current code:

public int Iterate()
{
    if (! this.OrderedKeys) {
        if (this.Snap != null) {
            delete this.Snap; // This will attempt to delete the handle created by Plugin A,
            // if one exists - say if you had iterated on the object before passing it to the forward.
            this.Snap = null;
        }

        this.Snap = this.Snapshot(); // And this will create a new handle on Plugin A's object, which belongs to Plugin B.
        // Plugin A cannot clean this up in its `Cleanup`, and it will linger in Plugin B.
    }

    return this.Length;
}

Versions

sm-json: v4.x
SourceMod Compiler: 1.11
SourceMod Build: Don't remember

Additional Information

I've been working on trying to solve this all day, with the help of @KillStr3aK on the SM Discord. I don't have a solution to this problem as long as Iterate is being used like it is. If the snapshot was returned and it was the callers responsibility to clean it up, like when normally iterating a string map, it would be solvable.

An issue was just opened on the AlliedModders GitHub (alliedmodders/sourcemod#1957), but that is more generic and about the lack of an exception when accessing handles you shouldn't. If there is no solution from SourceMod's side, then sm-json will likely need to take a different approach to iterating objects.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions