summaryrefslogtreecommitdiff
path: root/cli/spdxtool
diff options
context:
space:
mode:
authorPierre Pronchery <khorben@FreeBSD.org>2026-06-26 17:34:10 +0000
committerPierre Pronchery <khorben@FreeBSD.org>2026-06-29 05:21:50 +0000
commit0cf7106da9f36671ef62142c27de98eee9d874d6 (patch)
tree48090361499358411adb1d0bb16ca768e7c226a1 /cli/spdxtool
parentb0fc1b7a2fe8fcb18ee407227591bf25a86ffbaf (diff)
Diffstat (limited to 'cli/spdxtool')
-rw-r--r--cli/spdxtool/core.c28
-rw-r--r--cli/spdxtool/generate.c190
-rw-r--r--cli/spdxtool/generate.h29
-rw-r--r--cli/spdxtool/main.c217
-rw-r--r--cli/spdxtool/serialize.c4
-rw-r--r--cli/spdxtool/software.c49
6 files changed, 299 insertions, 218 deletions
diff --git a/cli/spdxtool/core.c b/cli/spdxtool/core.c
index 7dc7a8b41cce..62268b1b10a2 100644
--- a/cli/spdxtool/core.c
+++ b/cli/spdxtool/core.c
@@ -419,15 +419,24 @@ spdxtool_core_spdx_document_to_object(pkgconf_client_t *client, spdxtool_core_sp
if (!(spdxtool_serialize_object_add_string(object_list, "type", spdx->type) &&
spdxtool_serialize_object_add_string(object_list, "creationInfo", spdx->creation_info) &&
- spdxtool_serialize_object_add_string(object_list, "spdxId", spdx->spdx_id) &&
- spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array) &&
- spdxtool_serialize_object_add_array(object_list, "element", element_array)))
+ spdxtool_serialize_object_add_string(object_list, "spdxId", spdx->spdx_id)))
{
goto err;
}
+ /* object_add_array always takes ownership of the array (it is freed even on
+ * failure), so clear our reference before checking the result to avoid a
+ * double free at the error label.
+ */
+ bool ok = spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array);
root_element_array = NULL;
+ if (!ok)
+ goto err;
+
+ ok = spdxtool_serialize_object_add_array(object_list, "element", element_array);
element_array = NULL;
+ if (!ok)
+ goto err;
ret = spdxtool_serialize_value_object(object_list);
object_list = NULL;
@@ -813,13 +822,20 @@ spdxtool_core_relationship_to_object(pkgconf_client_t *client, const spdxtool_co
if (!(spdxtool_serialize_object_add_string(object_list, "type", relationship->type) &&
spdxtool_serialize_object_add_string(object_list, "creationInfo", relationship->creation_info) &&
spdxtool_serialize_object_add_string(object_list, "spdxId", relationship->spdx_id) &&
- spdxtool_serialize_object_add_string(object_list, "from", relationship->from) &&
- spdxtool_serialize_object_add_array(object_list, "to", to) &&
- spdxtool_serialize_object_add_string(object_list, "relationshipType", relationship->relationship_type)))
+ spdxtool_serialize_object_add_string(object_list, "from", relationship->from)))
{
+ /* none of the above transfers ownership of `to` */
+ spdxtool_serialize_array_free(to);
goto err;
}
+ /* object_add_array always takes ownership of `to` (it is freed even on failure) */
+ if (!spdxtool_serialize_object_add_array(object_list, "to", to))
+ goto err;
+
+ if (!spdxtool_serialize_object_add_string(object_list, "relationshipType", relationship->relationship_type))
+ goto err;
+
if (relationship->scope != NULL &&
!spdxtool_serialize_object_add_string(object_list, "scope", relationship->scope))
{
diff --git a/cli/spdxtool/generate.c b/cli/spdxtool/generate.c
new file mode 100644
index 000000000000..c5d8b29229c4
--- /dev/null
+++ b/cli/spdxtool/generate.c
@@ -0,0 +1,190 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ *​ Copyright (c) 2025 The FreeBSD Foundation
+ *​
+ *​ Portions of this software were developed by
+ * Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
+ * the FreeBSD Foundation
+ */
+
+#include <libpkgconf/stdinc.h>
+#include <libpkgconf/libpkgconf.h>
+#include "util.h"
+#include "core.h"
+#include "software.h"
+#include "serialize.h"
+#include "simplelicensing.h"
+#include "generate.h"
+
+// NOTE: this function is passed to pkgconf_pkg_traverse
+static void
+generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
+{
+ spdxtool_core_spdx_document_t *document = (spdxtool_core_spdx_document_t *)ptr;
+ pkgconf_node_t *node = NULL;
+ spdxtool_software_sbom_t *sbom = NULL;
+ char *package_spdx = NULL;
+ char *spdx_id_string = NULL;
+ char sep = spdxtool_util_get_uri_separator(client);
+
+ if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
+ return;
+
+ spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id);
+ if (!spdx_id_string)
+ goto err;
+
+ sbom = spdxtool_software_sbom_new(client, spdx_id_string, document->creation_info, "build");
+ free(spdx_id_string);
+ spdx_id_string = NULL;
+ if (!sbom)
+ goto err;
+
+ sbom->spdx_document = document;
+ sbom->rootElement = pkg;
+
+ package_spdx = spdxtool_util_get_spdx_id_string(client, "Package", pkg->id);
+ if (!package_spdx)
+ goto err;
+
+ pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0);
+ free(package_spdx);
+ package_spdx = NULL;
+
+ pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0);
+ pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0);
+
+ if (pkg->maintainer != NULL)
+ {
+ const char *supplier = spdxtool_core_spdx_document_add_maintainer(client, document, pkg->maintainer);
+ if (!supplier)
+ goto err;
+
+ pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0);
+ }
+
+ if (pkg->license.head != NULL)
+ {
+ pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER;
+
+ pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep);
+ char *spdx_id_name = pkgconf_buffer_freeze(&spdx_id_buf);
+ if (!spdx_id_name)
+ goto err;
+
+ package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
+ free(spdx_id_name);
+ if (!package_spdx)
+ goto err;
+
+ pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0);
+ free(package_spdx);
+ package_spdx = NULL;
+
+ pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER;
+ pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep);
+ spdx_id_name = pkgconf_buffer_freeze(&concluded_buf);
+ if (!spdx_id_name)
+ goto err;
+
+ package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
+ free(spdx_id_name);
+ if (!package_spdx)
+ goto err;
+
+ pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0);
+ free(package_spdx);
+ package_spdx = NULL;
+
+ PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node)
+ {
+ const pkgconf_license_t *license = node->data;
+ if (license->type == PKGCONF_LICENSE_EXPRESSION)
+ {
+ if (!spdxtool_core_spdx_document_add_license(client, document, license->data))
+ goto err;
+ }
+ }
+ }
+
+ node = calloc(1, sizeof(pkgconf_node_t));
+ if (!node)
+ goto err;
+
+ pkgconf_node_insert_tail(node, sbom, &document->rootElement);
+ return;
+
+err:
+ pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id);
+ free(package_spdx);
+ free(spdx_id_string);
+ spdxtool_software_sbom_free(sbom);
+}
+
+bool
+spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out, int maxdepth,
+ const char *creation_time, const char *creation_id, const char *agent_name)
+{
+ const char *agent_name_string = agent_name ? agent_name : "Default";
+ const char *creation_id_string = creation_id ? creation_id : "_:creationinfo_1";
+
+ spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, creation_id_string, agent_name_string);
+ if (!agent)
+ {
+ pkgconf_error(client, "Could not create agent struct");
+ return false;
+ }
+
+ spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, creation_id_string, creation_time);
+ if (!creation)
+ {
+ pkgconf_error(client, "Could not create creation info struct");
+ spdxtool_core_agent_free(agent);
+ return false;
+ }
+
+ char *spdx_id_int = spdxtool_util_get_spdx_id_int(client, "spdxDocument");
+ spdxtool_core_spdx_document_t *document = spdxtool_core_spdx_document_new(client, spdx_id_int, creation_id_string, agent->spdx_id);
+ free(spdx_id_int);
+ if (!document)
+ {
+ pkgconf_error(client, "Could not create document");
+ spdxtool_core_creation_info_free(creation);
+ spdxtool_core_agent_free(agent);
+ return false;
+ }
+
+ int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maxdepth, 0);
+ if (eflag != PKGCONF_PKG_ERRF_OK)
+ {
+ spdxtool_core_spdx_document_free(document);
+ spdxtool_core_creation_info_free(creation);
+ spdxtool_core_agent_free(agent);
+ return false;
+ }
+
+ spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, creation, document);
+ if (!root)
+ {
+ spdxtool_core_spdx_document_free(document);
+ spdxtool_core_creation_info_free(creation);
+ spdxtool_core_agent_free(agent);
+ return false;
+ }
+
+ pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER;
+ spdxtool_serialize_value_to_buf(&buffer, root, 0);
+ spdxtool_serialize_value_free(root);
+
+ bool ret = pkgconf_output_file_fmt(out, "%s\n", pkgconf_buffer_str(&buffer));
+ pkgconf_buffer_finalize(&buffer);
+
+ spdxtool_core_spdx_document_free(document);
+ spdxtool_core_creation_info_free(creation);
+ spdxtool_core_agent_free(agent);
+
+ if (!ret)
+ pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno));
+ return ret;
+}
diff --git a/cli/spdxtool/generate.h b/cli/spdxtool/generate.h
new file mode 100644
index 000000000000..818b8e4d9192
--- /dev/null
+++ b/cli/spdxtool/generate.h
@@ -0,0 +1,29 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ *​ Copyright (c) 2025 The FreeBSD Foundation
+ *​
+ *​ Portions of this software were developed by
+ * Tuukka Pasanen <tuukka.pasanen@ilmi.fi> under sponsorship from
+ * the FreeBSD Foundation
+ */
+
+#ifndef SPDXTOOL_GENERATE_H
+#define SPDXTOOL_GENERATE_H
+
+#include <stdio.h>
+#include <libpkgconf/libpkgconf.h>
+
+/*
+ * Build an SPDX SBOM for a solved dependency graph and write it to *out*.
+ *
+ * The dependency graph rooted at *world* must already have been solved (e.g.
+ * with pkgconf_queue_solve) so that every package's match is populated. The
+ * spdxtool_util_set_* configuration (URI root, separator, version, license)
+ * must have been applied to *client* beforehand.
+ */
+bool spdxtool_generate(pkgconf_client_t *client, pkgconf_pkg_t *world, FILE *out,
+ int maxdepth, const char *creation_time, const char *creation_id,
+ const char *agent_name);
+
+#endif
diff --git a/cli/spdxtool/main.c b/cli/spdxtool/main.c
index 7d52abe56670..a514341b93ab 100644
--- a/cli/spdxtool/main.c
+++ b/cli/spdxtool/main.c
@@ -17,6 +17,7 @@
#include "software.h"
#include "serialize.h"
#include "simplelicensing.h"
+#include "generate.h"
#define PKG_VERSION (((uint64_t) 1) << 1)
#define PKG_ABOUT (((uint64_t) 1) << 2)
@@ -55,177 +56,6 @@ error_handler(const char *msg, const pkgconf_client_t *client, void *data)
return true;
}
-// NOTE: this function is passed to pkgconf_pkg_traverse
-static void
-generate_spdx_package(pkgconf_client_t *client, pkgconf_pkg_t *pkg, void *ptr)
-{
- spdxtool_core_spdx_document_t *document = (spdxtool_core_spdx_document_t *)ptr;
- pkgconf_node_t *node = NULL;
- spdxtool_software_sbom_t *sbom = NULL;
- char *package_spdx = NULL;
- char *spdx_id_string = NULL;
- char sep = spdxtool_util_get_uri_separator(client);
-
- if (pkg->flags & PKGCONF_PKG_PROPF_VIRTUAL)
- return;
-
- spdx_id_string = spdxtool_util_get_spdx_id_string(client, "software_Sbom", pkg->id);
- if (!spdx_id_string)
- goto err;
-
- sbom = spdxtool_software_sbom_new(client, spdx_id_string, document->creation_info, "build");
- free(spdx_id_string);
- spdx_id_string = NULL;
- if (!sbom)
- goto err;
-
- sbom->spdx_document = document;
- sbom->rootElement = pkg;
-
- package_spdx = spdxtool_util_get_spdx_id_string(client, "Package", pkg->id);
- if (!package_spdx)
- goto err;
-
- pkgconf_tuple_add(client, &pkg->vars, "spdxId", package_spdx, false, 0);
- free(package_spdx);
- package_spdx = NULL;
-
- pkgconf_tuple_add(client, &pkg->vars, "creationInfo", document->creation_info, false, 0);
- pkgconf_tuple_add(client, &pkg->vars, "agent", document->agent, false, 0);
-
- if (pkg->maintainer != NULL)
- {
- const char *supplier = spdxtool_core_spdx_document_add_maintainer(client, document, pkg->maintainer);
- if (!supplier)
- goto err;
-
- pkgconf_tuple_add(client, &pkg->vars, "suppliedBy", supplier, false, 0);
- }
-
- if (pkg->license.head != NULL)
- {
- pkgconf_buffer_t spdx_id_buf = PKGCONF_BUFFER_INITIALIZER;
-
- pkgconf_buffer_append_fmt(&spdx_id_buf, "%s%chasDeclaredLicense", pkg->id, sep);
- char *spdx_id_name = pkgconf_buffer_freeze(&spdx_id_buf);
- if (!spdx_id_name)
- goto err;
-
- package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
- free(spdx_id_name);
- if (!package_spdx)
- goto err;
-
- pkgconf_tuple_add(client, &pkg->vars, "hasDeclaredLicense", package_spdx, false, 0);
- free(package_spdx);
- package_spdx = NULL;
-
- pkgconf_buffer_t concluded_buf = PKGCONF_BUFFER_INITIALIZER;
- pkgconf_buffer_append_fmt(&concluded_buf, "%s%chasConcludedLicense", pkg->id, sep);
- spdx_id_name = pkgconf_buffer_freeze(&concluded_buf);
- if (!spdx_id_name)
- goto err;
-
- package_spdx = spdxtool_util_get_spdx_id_string(client, "Relationship", spdx_id_name);
- free(spdx_id_name);
- if (!package_spdx)
- goto err;
-
- pkgconf_tuple_add(client, &pkg->vars, "hasConcludedLicense", package_spdx, false, 0);
- free(package_spdx);
- package_spdx = NULL;
-
- PKGCONF_FOREACH_LIST_ENTRY(pkg->license.head, node)
- {
- const pkgconf_license_t *license = node->data;
- if (license->type == PKGCONF_LICENSE_EXPRESSION)
- {
- if (!spdxtool_core_spdx_document_add_license(client, document, license->data))
- goto err;
- }
- }
- }
-
- node = calloc(1, sizeof(pkgconf_node_t));
- if (!node)
- goto err;
-
- pkgconf_node_insert_tail(node, sbom, &document->rootElement);
- return;
-
-err:
- pkgconf_error(client, "generate_spdx_package: failed for %s", pkg->id);
- free(package_spdx);
- free(spdx_id_string);
- spdxtool_software_sbom_free(sbom);
-}
-
-static bool
-generate_spdx(pkgconf_client_t *client, pkgconf_pkg_t *world, const char *creation_time, const char *creation_id, const char *agent_name)
-{
- const char *agent_name_string = agent_name ? agent_name : "Default";
- const char *creation_id_string = creation_id ? creation_id : "_:creationinfo_1";
-
- spdxtool_core_agent_t *agent = spdxtool_core_agent_new(client, creation_id_string, agent_name_string);
- if (!agent)
- {
- pkgconf_error(client, "Could not create agent struct");
- return false;
- }
-
- spdxtool_core_creation_info_t *creation = spdxtool_core_creation_info_new(client, agent->spdx_id, creation_id_string, creation_time);
- if (!creation)
- {
- pkgconf_error(client, "Could not create creation info struct");
- spdxtool_core_agent_free(agent);
- return false;
- }
-
- char *spdx_id_int = spdxtool_util_get_spdx_id_int(client, "spdxDocument");
- spdxtool_core_spdx_document_t *document = spdxtool_core_spdx_document_new(client, spdx_id_int, creation_id_string, agent->spdx_id);
- free(spdx_id_int);
- if (!document)
- {
- pkgconf_error(client, "Could not create document");
- spdxtool_core_creation_info_free(creation);
- spdxtool_core_agent_free(agent);
- return false;
- }
-
- int eflag = pkgconf_pkg_traverse(client, world, generate_spdx_package, document, maximum_traverse_depth, 0);
- if (eflag != PKGCONF_PKG_ERRF_OK)
- {
- spdxtool_core_spdx_document_free(document);
- spdxtool_core_creation_info_free(creation);
- spdxtool_core_agent_free(agent);
- return false;
- }
-
- spdxtool_serialize_value_t *root = spdxtool_serialize_sbom(client, agent, creation, document);
- if (!root)
- {
- spdxtool_core_spdx_document_free(document);
- spdxtool_core_creation_info_free(creation);
- spdxtool_core_agent_free(agent);
- return false;
- }
-
- pkgconf_buffer_t buffer = PKGCONF_BUFFER_INITIALIZER;
- spdxtool_serialize_value_to_buf(&buffer, root, 0);
- spdxtool_serialize_value_free(root);
-
- bool ret = pkgconf_output_file_fmt(sbom_out, "%s\n", pkgconf_buffer_str(&buffer));
- pkgconf_buffer_finalize(&buffer);
-
- spdxtool_core_spdx_document_free(document);
- spdxtool_core_creation_info_free(creation);
- spdxtool_core_agent_free(agent);
-
- if (!ret)
- pkgconf_error(client, "spdxtool: Could not output to file: %s", strerror(errno));
- return ret;
-}
-
static int
version(void)
{
@@ -365,38 +195,25 @@ main(int argc, char *argv[])
if ((want_flags & PKG_HELP) == PKG_HELP)
return usage();
- while (1)
- {
- const char *package = argv[pkg_optind];
-
- if (package == NULL)
- break;
-
- while (isspace((unsigned char)package[0]))
- package++;
+ /* Join the remaining arguments into a single query string, as the main
+ * pkgconf CLI does, and let the dependency parser handle module names,
+ * comparison operators and versions.
+ */
+ pkgconf_buffer_t queryparams = PKGCONF_BUFFER_INITIALIZER;
- /* skip empty packages */
- if (package[0] == '\0')
- {
- pkg_optind++;
- continue;
- }
+ while (pkg_optind < argc && argv[pkg_optind] != NULL)
+ {
+ if (pkgconf_buffer_len(&queryparams) > 0)
+ pkgconf_buffer_push_byte(&queryparams, ' ');
- if (argv[pkg_optind + 1] == NULL || !PKGCONF_IS_OPERATOR_CHAR(*(argv[pkg_optind + 1])))
- {
- pkgconf_queue_push(&pkgq, package);
- pkg_optind++;
- }
- else
- {
- char packagebuf[PKGCONF_BUFSIZE];
+ pkgconf_buffer_append(&queryparams, argv[pkg_optind]);
+ pkg_optind++;
+ }
- snprintf(packagebuf, sizeof packagebuf, "%s %s %s", package, argv[pkg_optind + 1], argv[pkg_optind + 2]);
- pkg_optind += 3;
+ if (pkgconf_buffer_len(&queryparams) > 0)
+ pkgconf_queue_push(&pkgq, pkgconf_buffer_str(&queryparams));
- pkgconf_queue_push(&pkgq, packagebuf);
- }
- }
+ pkgconf_buffer_finalize(&queryparams);
if (!pkgconf_queue_solve(&pkg_client, &pkgq, &world, maximum_traverse_depth))
{
@@ -409,7 +226,7 @@ main(int argc, char *argv[])
spdxtool_util_set_spdx_license(&pkg_client, bom_license);
spdxtool_util_set_spdx_version(&pkg_client, spdx_version);
- if (!generate_spdx(&pkg_client, &world, creation_time, creation_id, agent_name))
+ if (!spdxtool_generate(&pkg_client, &world, sbom_out, maximum_traverse_depth, creation_time, creation_id, agent_name))
{
ret = EXIT_FAILURE;
goto out;
diff --git a/cli/spdxtool/serialize.c b/cli/spdxtool/serialize.c
index fc5c460d77cb..813095b8b7ee 100644
--- a/cli/spdxtool/serialize.c
+++ b/cli/spdxtool/serialize.c
@@ -47,8 +47,8 @@ serialize_escape_string(pkgconf_buffer_t *buffer, const char *s)
pkgconf_buffer_append(buffer, "\\t");
break;
default:
- if (*p < 0x20)
- pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)*p);
+ if ((unsigned char) *p < 0x20)
+ pkgconf_buffer_append_fmt(buffer, "\\u%04x", (unsigned int)(unsigned char) *p);
else
pkgconf_buffer_push_byte(buffer, *p);
}
diff --git a/cli/spdxtool/software.c b/cli/spdxtool/software.c
index ac76cf73e7de..c95ec84cbdfa 100644
--- a/cli/spdxtool/software.c
+++ b/cli/spdxtool/software.c
@@ -137,6 +137,10 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo
pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
+ /* an unresolved (but tolerated) dependency has no match */
+ if (match == NULL)
+ continue;
+
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
@@ -168,6 +172,10 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo
pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
+ /* an unresolved (but tolerated) dependency has no match */
+ if (match == NULL)
+ continue;
+
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", sbom->rootElement->id, sep, sep, match->id);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
@@ -236,17 +244,24 @@ spdxtool_software_sbom_to_object(pkgconf_client_t *client, spdxtool_software_sbo
goto err;
}
- if (!spdxtool_serialize_object_add_array(object_list, "software_sbomType", sbom_type_array))
- goto err;
+ /* object_add_array always takes ownership of the array (it is freed even on
+ * failure), so clear our reference before checking the result to avoid a
+ * double free at the error label.
+ */
+ bool ok = spdxtool_serialize_object_add_array(object_list, "software_sbomType", sbom_type_array);
sbom_type_array = NULL;
-
- if (!spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array))
+ if (!ok)
goto err;
- root_element_array = NULL;
- if (!spdxtool_serialize_object_add_array(object_list, "element", element_array))
+ ok = spdxtool_serialize_object_add_array(object_list, "rootElement", root_element_array);
+ root_element_array = NULL;
+ if (!ok)
goto err;
+
+ ok = spdxtool_serialize_object_add_array(object_list, "element", element_array);
element_array = NULL;
+ if (!ok)
+ goto err;
if (!spdxtool_core_spdx_document_add_package(client, sbom->spdx_document, sbom->rootElement))
goto err;
@@ -343,9 +358,14 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
goto err;
}
- if (!spdxtool_serialize_object_add_array(object_list, "originatedBy", originated_by))
- goto err;
+ /* object_add_array always takes ownership of the array (it is freed even on
+ * failure), so clear our reference before checking the result to avoid a
+ * double free at the error label.
+ */
+ bool ok = spdxtool_serialize_object_add_array(object_list, "originatedBy", originated_by);
originated_by = NULL;
+ if (!ok)
+ goto err;
supplier = spdxtool_util_tuple_lookup(client, &pkg->vars, "suppliedBy");
if (supplier)
@@ -357,9 +377,10 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
if (!spdxtool_serialize_array_add_string(supplied_by, supplier))
goto err;
- if (!spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by))
- goto err;
+ ok = spdxtool_serialize_object_add_array(object_list, "suppliedBy", supplied_by);
supplied_by = NULL;
+ if (!ok)
+ goto err;
}
if (!serialize_copyright_lines_to_object(object_list, &pkg->copyright))
@@ -442,6 +463,10 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
+ /* an unresolved (but tolerated) dependency has no match */
+ if (match == NULL)
+ continue;
+
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)
@@ -484,6 +509,10 @@ spdxtool_software_package_to_object(pkgconf_client_t *client, pkgconf_pkg_t *pkg
pkgconf_pkg_t *match = dep->match;
pkgconf_buffer_t relationship_buf = PKGCONF_BUFFER_INITIALIZER;
+ /* an unresolved (but tolerated) dependency has no match */
+ if (match == NULL)
+ continue;
+
pkgconf_buffer_append_fmt(&relationship_buf, "%s%cdependsOn%c%s", pkg->id, sep, sep, match->id);
char *relationship_str = pkgconf_buffer_freeze(&relationship_buf);
if (!relationship_str)