@samitouri / QOSamiQemu / commits / 30724cfee6

hw/nvme: use GPtrArray for blocker_features

Let's use GPtrArray to build a list of blocker features and then g_strjoinv() to build a final comma-delimited string. While previous approach was technically correct, it is fragile (because we need to take care of static buffer size choice) and Coverity dislikes it too. Note, that we use g_ptr_array_new() to allocate array which means that GDestroyNotify callback is not set, so we can pass pointers to a static memory like g_ptr_array_add(..., (gpointer) "SR-IOV") without any problems as there won't be any attempt to free that memory. Resolves: Coverity CID 1663673 Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@futurfusion.io> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Klaus Jensen <k.jensen@samsung.com> [k.jensen: change cast from gpointer to void ptr] Signed-off-by: Klaus Jensen <k.jensen@samsung.com>

Alexander Mikhalitsyn committed Jul 9, 2026 at 10:47 UTC 30724cfee678b08f1975741e1f3035b9306d114e
1 file changed +17 -24
hw/nvme/ctrl.c
+17 -24
@@ -9352,22 +9352,11 @@ static void nvme_init_ctrl(NvmeCtrl *n, PCIDevice *pci_dev)
9352 }
9353 }
9354
9355 -#define BLOCKER_FEATURES_MAX_LEN 256
9356 -
9357 -static inline void nvme_add_blocker_feature(char *blocker_features,
9358 - const char *feature)
9359 -{
9360 - if (strlen(blocker_features) > 0) {
9361 - g_strlcat(blocker_features, ", ", BLOCKER_FEATURES_MAX_LEN);
9362 - }
9363 - g_strlcat(blocker_features, feature, BLOCKER_FEATURES_MAX_LEN);
9364 -}
9365 -
9355 static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9356 Error **errp)
9357 {
9358 uint64_t unsupported_cap, cap = ldq_le_p(&n->bar.cap);
9370 - char blocker_features[BLOCKER_FEATURES_MAX_LEN] = "";
9359 + g_autoptr(GPtrArray) blocker_features = g_ptr_array_new();
9360 bool adm_cmd_security_checked = false;
9361 bool cmd_io_mgmt_checked = false;
9362 bool cmd_zone_checked = false;
@@ -9416,15 +9405,15 @@ static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9405 }
9406
9407 if (namespaces_num > 1) {
9419 - nvme_add_blocker_feature(blocker_features,
9420 - "Namespace Attachment");
9408 + g_ptr_array_add(blocker_features,
9409 + (void *) "Namespace Attachment");
9410 }
9411
9412 break;
9413 }
9414 case NVME_ADM_CMD_VIRT_MNGMT:
9415 if (n->params.sriov_max_vfs) {
9427 - nvme_add_blocker_feature(blocker_features, "SR-IOV");
9416 + g_ptr_array_add(blocker_features, (void *) "SR-IOV");
9417 }
9418
9419 break;
@@ -9435,7 +9424,7 @@ static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9424 }
9425
9426 if (pci_dev->spdm_port) {
9438 - nvme_add_blocker_feature(blocker_features, "SPDM");
9427 + g_ptr_array_add(blocker_features, (void *) "SPDM");
9428 }
9429
9430 adm_cmd_security_checked = true;
@@ -9469,7 +9458,7 @@ static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9458
9459 /* check for NVME_IOMS_MO_RUH_UPDATE */
9460 if (n->subsys->params.fdp.enabled) {
9472 - nvme_add_blocker_feature(blocker_features, "FDP");
9461 + g_ptr_array_add(blocker_features, (void *) "FDP");
9462 }
9463
9464 cmd_io_mgmt_checked = true;
@@ -9504,8 +9493,8 @@ static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9493 }
9494
9495 if (ns->params.zoned) {
9507 - nvme_add_blocker_feature(blocker_features,
9508 - "Zoned Namespace");
9496 + g_ptr_array_add(blocker_features,
9497 + (void *) "Zoned Namespace");
9498 break;
9499 }
9500 }
@@ -9525,24 +9514,28 @@ static bool nvme_set_migration_blockers(NvmeCtrl *n, PCIDevice *pci_dev,
9514 * covered by unsupported_cap check.
9515 */
9516 if (NVME_CAP_CMBS(cap)) {
9528 - nvme_add_blocker_feature(blocker_features, "CMB");
9517 + g_ptr_array_add(blocker_features, (void *) "CMB");
9518 cap &= ~((uint64_t)CAP_CMBS_MASK << CAP_CMBS_SHIFT);
9519 }
9520
9521 if (NVME_CAP_PMRS(cap)) {
9533 - nvme_add_blocker_feature(blocker_features, "PMR");
9522 + g_ptr_array_add(blocker_features, (void *) "PMR");
9523 cap &= ~((uint64_t)CAP_PMRS_MASK << CAP_PMRS_SHIFT);
9524 }
9525
9526 unsupported_cap = cap & ~NVME_MIGRATION_SUPPORTED_CAP_BITS;
9527 if (unsupported_cap) {
9539 - nvme_add_blocker_feature(blocker_features, "unknown capability");
9528 + g_ptr_array_add(blocker_features, (void *) "unknown capability");
9529 }
9530
9531 assert(n->migration_blocker == NULL);
9543 - if (strlen(blocker_features) > 0) {
9532 + if (blocker_features->len > 0) {
9533 + g_autofree char *blocker_list = NULL;
9534 +
9535 + g_ptr_array_add(blocker_features, NULL);
9536 + blocker_list = g_strjoinv(", ", (void *)blocker_features->pdata);
9537 error_setg(&n->migration_blocker,
9545 - "Migration is not supported for %s", blocker_features);
9538 + "Migration is not supported for %s", blocker_list);
9539 if (migrate_add_blocker(&n->migration_blocker, errp) < 0) {
9540 return false;
9541 }