dsp: pdr: Add pldm_entity_association_tree_copy_root_check()

Allocations cannot be treated as infallible. Ensure that copying
the entity association tree signals failure to the caller along with
cleaning up after itself to avoid leaking memory.

Change-Id: Icfd255b45530e42a6a3a0a3205e665eed53708d1
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/src/dsp/pdr.c b/src/dsp/pdr.c
index 0f73f02..670e1ed 100644
--- a/src/dsp/pdr.c
+++ b/src/dsp/pdr.c
@@ -1213,26 +1213,49 @@
 	return node;
 }
 
-static void entity_association_tree_copy(pldm_entity_node *org_node,
-					 pldm_entity_node **new_node)
+static int entity_association_tree_copy(pldm_entity_node *org_node,
+					pldm_entity_node **new_node)
 {
+	int rc;
+
 	if (org_node == NULL) {
-		return;
+		return 0;
 	}
+
 	*new_node = malloc(sizeof(pldm_entity_node));
+	if (!*new_node) {
+		return -ENOMEM;
+	}
+
 	(*new_node)->parent = org_node->parent;
 	(*new_node)->entity = org_node->entity;
 	(*new_node)->association_type = org_node->association_type;
 	(*new_node)->remote_container_id = org_node->remote_container_id;
 	(*new_node)->first_child = NULL;
 	(*new_node)->next_sibling = NULL;
-	entity_association_tree_copy(org_node->first_child,
-				     &((*new_node)->first_child));
-	entity_association_tree_copy(org_node->next_sibling,
-				     &((*new_node)->next_sibling));
+
+	rc = entity_association_tree_copy(org_node->first_child,
+					  &((*new_node)->first_child));
+	if (rc) {
+		goto cleanup;
+	}
+
+	rc = entity_association_tree_copy(org_node->next_sibling,
+					  &((*new_node)->next_sibling));
+	if (rc) {
+		entity_association_tree_destroy((*new_node)->first_child);
+		goto cleanup;
+	}
+
+	return 0;
+
+cleanup:
+	free(*new_node);
+	*new_node = NULL;
+	return rc;
 }
 
-LIBPLDM_ABI_STABLE
+LIBPLDM_ABI_DEPRECATED
 void pldm_entity_association_tree_copy_root(
 	pldm_entity_association_tree *org_tree,
 	pldm_entity_association_tree *new_tree)
@@ -1244,6 +1267,19 @@
 	entity_association_tree_copy(org_tree->root, &(new_tree->root));
 }
 
+LIBPLDM_ABI_TESTING
+int pldm_entity_association_tree_copy_root_check(
+	pldm_entity_association_tree *org_tree,
+	pldm_entity_association_tree *new_tree)
+{
+	if (!org_tree || !new_tree) {
+		return -EINVAL;
+	}
+
+	new_tree->last_used_container_id = org_tree->last_used_container_id;
+	return entity_association_tree_copy(org_tree->root, &(new_tree->root));
+}
+
 LIBPLDM_ABI_STABLE
 void pldm_entity_association_tree_destroy_root(
 	pldm_entity_association_tree *tree)