|WARNING| dev: fix hotplug notification to secondary
dpdklab at iol.unh.edu
dpdklab at iol.unh.edu
Mon Jul 6 17:49:50 CEST 2026
Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/166578
_AI Code Review_
=== Patch Review: series.patch (via Claude) ===
Review date: 2026-07-06
# DPDK Patch Review
## Summary
This patch fixes a critical logic bug in multi-process hotplug notification and adds comprehensive unit tests. The core fix is correct, but there are several style issues and one potential correctness concern in the test code.
---
## Errors
### 1. Potential use-after-free in `run_primary_hotplug_test()`
**File:** `app/test/test_dev_hotplug.c`
**Lines:** 290-291
The code calls `rte_memzone_free(mz)` at line 290, then attempts to access `dev` (which may reference memory in that memzone or related structures) immediately after. While `dev` was obtained before the free, if the device removal at line 284 failed or was skipped, the pointer could be stale.
```c
out:
if (pid > 0) {
int wstatus;
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus))
printf("Primary: secondary exited with status %d\n", WEXITSTATUS(wstatus));
}
rte_memzone_free(mz); /* <-- memzone freed here */
if (test_result == TEST_SUCCESS)
printf("== MP hotplug test passed ==\n");
else
printf("== MP hotplug test FAILED ==\n");
return test_result;
```
**Fix:** Move the device cleanup check and `rte_dev_remove()` call to before the `out:` label, or ensure it completes before `rte_memzone_free()`.
```c
out:
if (pid > 0) {
int wstatus;
waitpid(pid, &wstatus, 0);
if (WIFEXITED(wstatus))
printf("Primary: secondary exited with status %d\n", WEXITSTATUS(wstatus));
}
/* Clean up device before freeing memzone */
dev = find_device_by_name(HOTPLUG_TEST_DEV);
if (dev != NULL) {
printf("Primary: removing device %s\n", HOTPLUG_TEST_DEV);
rte_dev_remove(dev);
}
if (mz != NULL)
rte_memzone_free(mz);
/* ... print result ... */
```
---
## Warnings
### 1. Missing release notes update
**File:** Release notes (not modified)
This patch fixes Bugzilla #1963 and adds new public test APIs (`REGISTER_FAST_TEST` registration). While test-only changes typically do not require release notes, the bug fix in `eal_common_dev.c` is a correctness fix for multi-process hotplug that could affect users. The release notes should mention the fix.
**Suggested addition to current release notes (`doc/guides/rel_notes/release_26_07.rst` or similar):**
```rst
* **Fixed multi-process hotplug notification.**
Fixed a logic error in ``rte_dev_probe()`` and ``rte_dev_remove()``
that prevented secondary processes from receiving device hotplug
notifications in multi-process configurations.
```
### 2. `REGISTER_FAST_TEST` uses `NOHUGE_SKIP` / `ASAN_SKIP` instead of `ASAN_FAILS`
**File:** `app/test/test_dev_hotplug.c`
**Line:** 320
```c
REGISTER_FAST_TEST(dev_hotplug_mp_autotest, NOHUGE_SKIP, ASAN_SKIP, test_dev_hotplug_mp);
```
The test is skipped under ASAN, but the correct macro for tests that are incompatible with ASan should be `ASAN_FAILS` (based on the guidelines' mention of `ASAN_OK` / `ASAN_FAILS` as the two valid options). Check if `ASAN_SKIP` is a valid macro; if not, use `ASAN_FAILS`.
**Suggested fix (if `ASAN_SKIP` is not defined):**
```c
REGISTER_FAST_TEST(dev_hotplug_mp_autotest, NOHUGE_SKIP, ASAN_FAILS, test_dev_hotplug_mp);
```
### 3. Child process error path does not call `_exit()`
**File:** `app/test/test_dev_hotplug.c`
**Lines:** 253
After `fork()`, the child process uses `exit(TEST_FAILED)` if `execv()` fails. In test code that may have registered cleanup handlers or opened files, `_exit()` is safer than `exit()` to avoid double-cleanup issues.
```c
if (setenv(RECURSIVE_ENV_VAR, "run_hotplug_secondary", 1) == 0)
execv(argv[0], argv);
exit(TEST_FAILED); /* Should be _exit() */
```
**Fix:**
```c
if (setenv(RECURSIVE_ENV_VAR, "run_hotplug_secondary", 1) == 0)
execv(argv[0], argv);
_exit(TEST_FAILED);
```
### 4. Allocated strings in child process not freed before exec failure
**File:** `app/test/test_dev_hotplug.c`
**Lines:** 240-252
The child process allocates 5 strings with `strdup()` but does not free them if `execv()` fails. While the process exits immediately, this is a minor resource leak on the error path.
**Fix (low priority):**
```c
argv[0] = strdup(prgname);
argv[1] = strdup("-l");
argv[2] = strdup(core_str);
argv[3] = strdup("--proc-type=secondary");
argv[4] = strdup(prefix);
argv[5] = NULL;
if (setenv(RECURSIVE_ENV_VAR, "run_hotplug_secondary", 1) != 0) {
for (int i = 0; i < 5; i++)
free(argv[i]);
_exit(TEST_FAILED);
}
if (execv(argv[0], argv) != 0) {
for (int i = 0; i < 5; i++)
free(argv[i]);
_exit(TEST_FAILED);
}
```
---
## Style Issues (Info)
### 1. Implicit comparison in boolean assignment
**File:** `lib/eal/common/eal_common_dev.c`
**Lines:** 272, 431
```c
bool do_mp = internal_conf->no_shconf == 0;
```
While this is explicit comparison (which is correct per guidelines), the double-negative naming (`no_shconf == 0` to get "do multiprocess") is confusing. Consider renaming the local variable or adding a comment.
**Suggested improvement (comment):**
```c
/* Multi-process is enabled when shared config is NOT disabled */
bool do_mp = internal_conf->no_shconf == 0;
```
### 2. Missing NULL check on `strdup()` return values
**File:** `app/test/test_dev_hotplug.c`
**Lines:** 240-245
`strdup()` can return NULL on allocation failure. The code does not check these before passing to `execv()`.
**Suggested fix:**
```c
argv[0] = strdup(prgname);
argv[1] = strdup("-l");
argv[2] = strdup(core_str);
argv[3] = strdup("--proc-type=secondary");
argv[4] = strdup(prefix);
if (!argv[0] || !argv[1] || !argv[2] || !argv[3] || !argv[4])
_exit(TEST_FAILED);
argv[5] = NULL;
```
### 3. Inconsistent naming: `test_dev_hotplug_api` vs `test_dev_hotplug_mp`
**File:** `app/test/test_dev_hotplug.c`
The naming is consistent within the file but could be more descriptive. Consider `test_hotplug_single_process` and `test_hotplug_multiprocess` for clarity.
---
## Positive Observations
1. **Core bug fix is correct:** The change from `!!internal_conf->no_shconf` to `internal_conf->no_shconf == 0` correctly inverts the logic to enable multi-process notification when shared config is enabled.
2. **Test coverage is comprehensive:** The patch adds both single-process API tests and multi-process notification tests, which will catch regressions in this area.
3. **Atomic operations used correctly:** The test coordination uses `rte_atomic_*_explicit()` with appropriate memory ordering (`release` for signaling, `acquire` for waiting, `relaxed` for result storage).
4. **Resource cleanup attempted:** The test tries to remove the probed device in both success and failure paths.
---
## Recommendation
**Merge after addressing the use-after-free concern (Error #1) and adding release notes (Warning #1).**
The other warnings and style issues are minor and can be addressed in a follow-up patch if needed.
More information about the test-report
mailing list