Skip to content

net/unicoap: initialize .payload_representation in message_init helpers#22321

Open
adityachilka1 wants to merge 1 commit into
RIOT-OS:masterfrom
adityachilka1:fix/unicoap-payload-representation-init
Open

net/unicoap: initialize .payload_representation in message_init helpers#22321
adityachilka1 wants to merge 1 commit into
RIOT-OS:masterfrom
adityachilka1:fix/unicoap-payload-representation-init

Conversation

@adityachilka1
Copy link
Copy Markdown

Contribution description

Fixes #22285.

The four unicoap_message_init* inline initializers in sys/include/net/unicoap/message.h populated code, options, payload, and payload_size but never wrote the .payload_representation : 1 bitfield. The function-level contract above each initializer explicitly tells callers they do not need to zero the unicoap_message_t struct beforehand — but with a stack-allocated un-zeroed struct, the representation bit ends up holding whatever was on the stack. When that bit happens to be 1 (UNICOAP_PAYLOAD_NONCONTIGUOUS), subsequent calls to unicoap_message_payload_get_size, the chunks accessors, or any serialisation routine enter the noncontiguous codepath and dereference message->payload_chunks as an iolist_t* — even though the caller populated the contiguous-payload fields.

This PR adds message->payload_representation = UNICOAP_PAYLOAD_CONTIGUOUS; to each of the four initializers (unicoap_message_init_empty, unicoap_message_init, unicoap_message_init_string, unicoap_message_init_with_options).

The sibling unicoap_message_alloc_* helpers already get correct behaviour for free via designated initializers (any field not mentioned is value-initialised to zero, which is UNICOAP_PAYLOAD_CONTIGUOUS).

The fifth unicoap_message_init_string_with_options is deliberately unchanged — it delegates to unicoap_message_init_with_options internally, so it inherits the fix transitively.

Testing procedure

Before this patch, the following reproducer (taken from the issue body) can segfault depending on what happened to be on the stack:

unicoap_message_t message;  /* deliberately not zero-initialised */
unicoap_message_init_string(&message, code, "hello");
size_t n = unicoap_message_payload_get_size(&message);  /* may take noncontiguous branch and crash */

After the patch, message.payload_representation is always UNICOAP_PAYLOAD_CONTIGUOUS after any unicoap_message_init* call, so the contiguous-payload branch in unicoap_message_payload_get_size is always taken. The asserts in unicoap_message_payload_get and unicoap_message_payload_get_chunks keep the contract honest.

You can exercise this in the existing unicoap example app (examples/networking/coap/unicoap):

make -C examples/networking/coap/unicoap all
make -C examples/networking/coap/unicoap test  # if a test target exists for this board

The change is header-only and additive, so any build that pulls in net/unicoap/message.h covers it.

Issues/PRs references

Fixes #22285.

Declaration of AI-Tools / LLMs usage

AI-Tools / LLMs that were used are:

  • Claude (Sonnet) for code analysis, identifying the four direct-write initializers vs. the fifth delegating one, drafting the commit message and this PR body, and confirming the constant name (UNICOAP_PAYLOAD_CONTIGUOUS) by reading the existing setter unicoap_message_payload_set and the asserts in the contiguous/noncontiguous getters — with user (@adityachilka1) review of every code line before submission ("agent mode" with explicit user review at each step).

The C source change itself is mechanical (one identical line added to four already-existing function bodies) and matches the exact pattern used by the unicoap_message_payload_set setter elsewhere in the same file. No new logic is introduced.

The four `unicoap_message_init*` inline initializers in
`sys/include/net/unicoap/message.h` set `code`, `options`, `payload`,
and `payload_size` but never wrote the `.payload_representation : 1`
bitfield. The function-level contract documented above each initializer
is that callers do NOT need to zero the `unicoap_message_t` struct
before calling — but with a stack-allocated, un-zeroed struct, the
representation bit ends up holding whatever was on the stack. If that
bit happens to be `1` (= UNICOAP_PAYLOAD_NONCONTIGUOUS), subsequent
calls to `unicoap_message_payload_get_size`, the chunks accessors, or
serialisation enter the noncontiguous codepath and dereference
`message->payload_chunks` as an `iolist_t*` — even though the caller
populated the contiguous-payload fields.

Set `message->payload_representation = UNICOAP_PAYLOAD_CONTIGUOUS;` in
each of the four initializers. The sibling `unicoap_message_alloc_*`
helpers already get correct behaviour for free via designated
initializers (unmentioned fields are value-initialised to zero, and
UNICOAP_PAYLOAD_CONTIGUOUS is the zero value of the enum).

The fifth `unicoap_message_init_string_with_options` is unchanged on
purpose: it delegates to `unicoap_message_init_with_options` and
inherits the fix transitively.

Fixes RIOT-OS#22285.
@github-actions
Copy link
Copy Markdown

Hey @adityachilka1, thank you for your first contribution! We really appreciate it! If you haven't already, please take a look at our contributing guidelines before the review process starts. Also, due to how the GitHub review system works, please avoid force-pushing or squashing your commits unless asked to by a maintainer (or unless your commit is still in "draft commit" stage). Your pull request will be reviewed as soon as possible.

@github-actions github-actions Bot added Area: network Area: Networking Area: CoAP Area: Constrained Application Protocol implementations Area: sys Area: System labels May 23, 2026
@AnnsAnns AnnsAnns requested a review from carl-tud May 23, 2026 09:01
@AnnsAnns AnnsAnns added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels May 23, 2026
@AnnsAnns AnnsAnns removed the request for review from carl-tud May 23, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: CoAP Area: Constrained Application Protocol implementations Area: network Area: Networking Area: sys Area: System

Projects

None yet

Development

Successfully merging this pull request may close these issues.

net/unicoap: Message initialisers do not set .payload_representation

3 participants