Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

memory issue for recursive function #151

Closed
Edwardmark opened this issue Jan 19, 2024 · 7 comments
Closed

memory issue for recursive function #151

Edwardmark opened this issue Jan 19, 2024 · 7 comments

Comments

@Edwardmark
Copy link

Edwardmark commented Jan 19, 2024

I have a TreeNode class which defines a tree structure. And I want to convert it to json using yyjson.

yyjson_mut_val *convertTreeNodeToJSON(const std::shared_ptr<TreeNode> &node, yyjson_mut_doc *doc)
{
    yyjson_mut_val *jsonNode = nullptr;
    yyjson_mut_val *subNode = nullptr;

    if (node->GetValue().empty())
    {
        // Object or Array node
        bool isArrayNode = false;

        // Check if all siblings has same name, it true, then it is array
        auto parent = node->GetParent();
        if (parent)
        {
            auto sameKeyChildren = parent->GetChild(node->GetName());
            if (sameKeyChildren.size() == parent->GetChildren().size())
            {
                isArrayNode = true;
            }
        }

        if (isArrayNode)
        {
            jsonNode = yyjson_mut_arr(doc);
            for (const auto &child : node->GetChildren())
            {
                subNode = convertTreeNodeToJSON(child, doc);
                yyjson_mut_arr_add_val(jsonNode, subNode);
            }
        }
        else
        {
            jsonNode = yyjson_mut_obj(doc);

            for (const auto &child : node->GetChildren())
            {
                subNode = convertTreeNodeToJSON(child, doc);
                yyjson_mut_val *key = yyjson_mut_str(doc, child->GetName().c_str());
                yyjson_mut_obj_add(jsonNode, key, subNode);
            }
        }
    }
    else
    {
        // Value node
        jsonNode = yyjson_mut_str(doc, node->GetValue().c_str());
    }
    // when downstream recursion end, the json_str is null, invalid
    size_t json_len;
    char *json_str = yyjson_mut_val_write(jsonNode, YYJSON_WRITE_PRETTY, &json_len);
    std::cout << json_str << std::endl;
    return jsonNode;
}

int main()
{
    // Example tree
    std::shared_ptr<TreeNode> root = std::make_shared<TreeNode>();
    root->SetName("root");

    std::shared_ptr<TreeNode> objNode = std::make_shared<TreeNode>();
    objNode->SetName("object");

    std::shared_ptr<TreeNode> key1 = std::make_shared<TreeNode>("key1", "value1");
    std::shared_ptr<TreeNode> key2 = std::make_shared<TreeNode>("key2", "value2");

    objNode->AddChild(key1);
    objNode->AddChild(key2);

    std::shared_ptr<TreeNode> arrayNode = std::make_shared<TreeNode>("array");
    std::shared_ptr<TreeNode> item1 = std::make_shared<TreeNode>("key", "item1");
    std::shared_ptr<TreeNode> item2 = std::make_shared<TreeNode>("key", "item2");

    arrayNode->AddChild(item1);
    arrayNode->AddChild(item2);

    root->AddChild(objNode);
    root->AddChild(arrayNode);

    // Convert tree to JSON
    yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
    yyjson_mut_val *json = convertTreeNodeToJSON(root, doc);
    yyjson_mut_doc_set_root(doc, json);

    // Convert JSON to string
    size_t json_len;
    char *json_str = yyjson_mut_val_write(json, YYJSON_WRITE_PRETTY, &json_len);
    std::cout << json_str << std::endl;
    // Cleanup
    yyjson_mut_doc_free(doc);
}

The expected output should be:

{
  "root": {
    "object": {
      "key1": "value1",
      "key2": "value2"
    },
    "array": [
      "item1",
      "item2"
    ]
  }
}

But the actual result in main is NULL, and the cout << json_str << endl; in the recursion function outputs:

"item1"
"item2"
{
    "key": "item2",
    "key": "item2"
}
"value1"
"value2"
{
    "key2": "value2",
    "key2": "value2"
}
{
    "objec": {
        "key": "\u0000\u0000\u0000\u0000\u0000",
        "key": "\u0000\u0000\u0000\u0000\u0000"
    },
    "object": {
        "key2": "\u0000\u0000\u0000\u0000\u0000\u0000",
        "key2": "\u0000\u0000\u0000\u0000\u0000\u0000"
    }
}

It seems that the result is destructed when the function call end, so it returns null.
So what is the problem? Why the result is null? Could you please give me some hits? Thanks. @TkTech @lundmark @ibireme @nixzhu @fd00 Thanks.

@nixzhu
Copy link
Contributor

nixzhu commented Jan 19, 2024

@Edwardmark I don't have much experience with cpp, but you are passing the same doc pointer to the recursive function convertTreeNodeToJSON, is this a problem?

@Edwardmark
Copy link
Author

@nixzhu Thanks for you reply. I want to convert a tree structure to json, so I have to use the same doc pointer. The problem is about the jsonNode or SubNode in the recursion function. I print the value, it shows when the bottom recursion end, the upper function call cannot get their value, print result is null.

@Edwardmark
Copy link
Author

@Edwardmark I don't have much experience with cpp, but you are passing the same doc pointer to the recursive function convertTreeNodeToJSON, is this a problem?

It is not about cpp, I want to verify if the doc owns its subnode memory when calling the recursion function? And what should I do to fix the issue? Thanks .

@ibireme
Copy link
Owner

ibireme commented Jan 19, 2024

@Edwardmark The doc holds memory for all json values, so the recursive call seems good.

There are two string handling issues:

  1. yyjson_mut_str() doesn't take ownership of the string. If the passed string is modified or freed during use, errors like \u0000 may occur. Consider using yyjson_mut_strcpy() instead.
  2. The string returned by yyjson_mut_val_write() needs to be freed after use.

If you share the TreeNode source code, we can better understand and replicate the issue.

@Edwardmark
Copy link
Author

Edwardmark commented Jan 19, 2024

@ibireme Thanks for your reply. It is the problem. I change yyjson_mut_str() to yyjson_mut_strcpy() and it worked.
And for problem2, how to free the string? Could you give me a example? Thanks.

@ibireme
Copy link
Owner

ibireme commented Jan 19, 2024

@ibireme Thanks for your reply. It is the problem. I change yyjson_mut_str() to yyjson_mut_strcpy() and it worked. And for problem2, how to free the string? Could you give me a example? Thanks.

Just call free(json_str).

@Edwardmark
Copy link
Author

@ibireme Thanks.

@ibireme ibireme closed this as completed Jan 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants