spsc_pbuf, the buffer can become logically empty while rd_idx and wr_idx both remain at a non-zero offset. This breaks the next large allocation and causes spsc_pbuf_write() to return -ENOMEM.Environment:
-
nRF Connect SDK v3.2.4
-
Zephyr OS v4.2.99-9673eec75908
-
Hardware: nRF9160
Problem:
After a successful spsc_pbuf_write() and spsc_pbuf_read() that empties the buffer, a second write of the same size fails with -ENOMEM even though the buffer is logically empty and has enough total capacity.
Steps to reproduce:
-
Initialize an
spsc_pbufwith 4096 bytes. -
spsc_pbuf_write()a 2511-byte packet — succeeds. -
spsc_pbuf_read()the packet — succeeds, buffer is empty. -
spsc_pbuf_write()another 2511-byte packet — fails with-ENOMEM.
Root cause analysis:
A 2511-byte packet uses:
-
2511 bytes payload
-
2-byte length header
-
padding to 4-byte alignment
-
total internal advance = 2516 bytes
After the read, rd_idx == wr_idx == 2516. The buffer is empty, but the indices are not reset to 0, so the next allocation sees a non-canonical empty buffer state and fails to allocate the new packet.
Proposed fix:
In spsc_pbuf_free(), after advancing rd_idx, if the buffer is empty (rd_idx == wr_idx), normalize the empty state by resetting the index(es) to 0.
Workaround:
Reinitialize the buffer after each successful read:
int ret = spsc_pbuf_read(json_cmd_pbuf, dst, dst_len);
if (ret > 0) {
json_cmd_pbuf = spsc_pbuf_init(json_cmd_pbuf_mem, sizeof(json_cmd_pbuf_mem), 0);
}