|WARNING| [2/2] test/pcapng: check timestamps over a long capture

dpdklab at iol.unh.edu dpdklab at iol.unh.edu
Sun Sep 27 22:47:36 CEST 2026


Test-Label: ai-code-review
Test-Status: WARNING
https://dpdk.org/patch/170047

_AI Code Review_

=== Patch Review: series.patch (via Claude) ===
Review date: 2026-09-27

# DPDK Patch Review

## Patch 1/2: pcapng: revert use of reciprocal divide for timestamps

### Errors

**Use-after-free risk in timestamp calculation**

In `pcapng_timestamp()`, when `cycles < self->tsc_base`, the subtraction `self->tsc_base - cycles` is performed on unsigned values. While this is mathematically correct due to two's complement, the code comment says it handles "both directions" but only explicitly checks the `<` case. The reverse case (`cycles >= self->tsc_base`) has no explicit overflow protection if `cycles - self->tsc_base` produces a value that causes `pcapng_cycles_to_ns()` to overflow.

**Potential integer overflow in `pcapng_cycles_to_ns()`**

```c
static uint64_t
pcapng_cycles_to_ns(uint64_t delta)
{
	const uint64_t hz = rte_get_tsc_hz();
	uint64_t secs = delta / hz;
	uint64_t rem = delta % hz;

	return secs * NS_PER_S + (rem * NS_PER_S) / hz;
```

If `secs` is very large, `secs * NS_PER_S` can overflow before the addition. For a TSC frequency of 2 GHz and `delta = UINT64_MAX`, `secs = 9223372036` and `secs * NS_PER_S` overflows. The removed reciprocal code had explicit overflow prevention via pre-shift; this version does not.

Suggested fix: Add overflow check or clamp `secs`:
```c
if (secs > UINT64_MAX / NS_PER_S)
	return UINT64_MAX;
return secs * NS_PER_S + (rem * NS_PER_S) / hz;
```

**Missing error check on `rte_timespec_to_ns()`**

```c
self->offset_ns = rte_timespec_to_ns(&ts);
```

`rte_timespec_to_ns()` can fail (return 0) on overflow or invalid input, but the return value is not checked. If `clock_gettime()` returns an invalid timespec (e.g., negative `tv_nsec` on some platforms), `offset_ns` could be silently wrong.

Suggested fix:
```c
uint64_t offset = rte_timespec_to_ns(&ts);
if (offset == 0) {
	rte_errno = EINVAL;
	goto fail;
}
self->offset_ns = offset;
```

### Warnings

**Unnecessary explicit comparison in `unlikely()`**

```c
if (unlikely(cycles < self->tsc_base))
```

DPDK style requires explicit comparison for integers. However, `unlikely()` is a hint macro, not a truthiness test. The comparison `cycles < self->tsc_base` is already explicit. This is acceptable, but for consistency with other DPDK code, some prefer `cycles < self->tsc_base` without `unlikely()` when the condition is already explicit. Not a strict violation.

**Release notes not updated for bug fix**

This patch fixes a wraparound bug (Fixes: 4fc65615b274) but does not update `doc/guides/rel_notes/release_*.rst` to document the fix. Users upgrading would benefit from knowing this overflow issue was resolved.

---

## Patch 2/2: test/pcapng: check timestamps over a long capture

### Errors

**Use of `false` constant without `<stdbool.h>` include**

```c
TEST_ASSERT(false, "mkstemps() failed");
```

The code uses `false` but does not `#include <stdbool.h>`. While `TEST_ASSERT` may be a macro that accepts any zero value, relying on implicit definitions is fragile. Either include `<stdbool.h>` or use `0`.

**File descriptor leak on `rte_pcapng_fdopen()` failure**

```c
tmp_fd = mkstemps(file_name, strlen(".pcapng"));
if (tmp_fd == -1) {
	rte_pktmbuf_free(mc);
	TEST_ASSERT(false, "mkstemps() failed");
}

base_ns = current_timestamp();
pcapng = rte_pcapng_fdopen(tmp_fd, NULL, NULL, "longts", NULL);
if (pcapng == NULL) {
	close(tmp_fd);
	rte_pktmbuf_free(mc);
	TEST_ASSERT(false, "rte_pcapng_fdopen failed");
}
```

If `rte_pcapng_fdopen()` fails, `tmp_fd` is closed. However, the temporary file created by `mkstemps()` remains on disk (not removed). This is a **resource leak** (filesystem, not memory). On repeated test runs, `/tmp` accumulates stale `pcapng_test_*.pcapng` files.

Suggested fix: Always `remove(file_name)` in error paths:
```c
if (pcapng == NULL) {
	close(tmp_fd);
	remove(file_name);
	rte_pktmbuf_free(mc);
	TEST_ASSERT(false, "rte_pcapng_fdopen failed");
}
```

**Missing cleanup on `rte_pcapng_add_interface()` failure**

```c
ret = rte_pcapng_add_interface(pcapng, port_id, DLT_EN10MB,
			       NULL, NULL, NULL);
if (ret < 0) {
	rte_pcapng_close(pcapng);
	rte_pktmbuf_free(mc);
	TEST_ASSERT(false, "can not add port %u", port_id);
}
```

If `rte_pcapng_add_interface()` fails, the temporary file is not removed, leaking filesystem resources.

Suggested fix: Add `remove(file_name)` before `TEST_ASSERT`.

**Missing cleanup on `rte_pcapng_write_packets()` failure**

```c
len = rte_pcapng_write_packets(pcapng, &mc, 1);
rte_pktmbuf_free(mc);
rte_pcapng_close(pcapng);
TEST_ASSERT(len > 0, "write failed at +%u s", offsets[i]);
```

If `len <= 0`, the test aborts without removing the temporary file.

Suggested fix: Remove file before assertion or in a cleanup block.

**Missing cleanup on `read_one_timestamp()` failure**

```c
ret = read_one_timestamp(file_name, &got_ns);
TEST_ASSERT(ret == 0, "can not read back +%u s", offsets[i]);
```

If `read_one_timestamp()` fails, the file is not removed.

### Warnings

**Hardcoded tolerance (2 seconds) without justification**

```c
TEST_ASSERT(diff <= 2 * NS_PER_S,
	    "timestamp off by %"PRIu64" ns at +%u s",
	    diff, offsets[i]);
```

The test allows up to 2 seconds of error. Given that `clock_gettime()` and `rte_get_tsc_cycles()` are sampled separately and the TSC may drift, some tolerance is reasonable. However, 2 seconds is arbitrary and may be too large to catch real bugs or too small on slow/loaded systems. Consider documenting why 2 seconds was chosen or making it a named constant.

**Commented-out or unclear behavior in comment**

```c
/* An overflow wraps and misses by the whole offset. */
```

This comment suggests the test is checking for wraparound overflow, but the logic only checks if `diff > 2 * NS_PER_S`. A wraparound by the full offset would be `diff  offsets[i] * NS_PER_S`. If the overflow is severe, `diff` could be huge and the test should catch it, but the comment doesn't clearly explain what failure mode is expected.

---

## Summary

### Patch 1/2
- **3 Errors**: Integer overflow in `pcapng_cycles_to_ns()`, missing error check on `rte_timespec_to_ns()`, no explicit overflow guard in timestamp subtraction.
- **1 Warning**: Missing release notes update.

### Patch 2/2
- **5 Errors**: Missing `<stdbool.h>` for `false`, temporary file not removed on `rte_pcapng_fdopen()` failure, not removed on `rte_pcapng_add_interface()` failure, not removed on `rte_pcapng_write_packets()` failure, not removed on `read_one_timestamp()` failure (4 resource leaks in error paths).
- **2 Warnings**: Hardcoded 2-second tolerance without justification, unclear comment about overflow behavior.

Both patches require fixes to error handling and overflow prevention before merge.


More information about the test-report mailing list