Skip to content

fix(c): describe the real hazard in insecure-use-strtok-fn - #4022

Open
Eljees wants to merge 2 commits into
semgrep:developfrom
Eljees:agent/strtok-message-thread-safety
Open

fix(c): describe the real hazard in insecure-use-strtok-fn#4022
Eljees wants to merge 2 commits into
semgrep:developfrom
Eljees:agent/strtok-message-thread-safety

Conversation

@Eljees

@Eljees Eljees commented Jul 27, 2026

Copy link
Copy Markdown

Fixes #3772

Problem

The insecure-use-strtok-fn message describes strtok()'s documented behavior as if it were the hazard:

Avoid using 'strtok()'. This function directly modifies the first argument buffer, permanently erasing the delimiter character. Use 'strtok_r()' instead.

Modifying the input in place is exactly what strtok() is specified to do, and it is not why the rule recommends strtok_r(). As #3772 points out, the message leaves a reader unsure what the actual risk is — and it doesn't explain what makes the suggested replacement better, since strtok_r() modifies the buffer in the same way.

Change

Message only — the pattern, metadata and severity are untouched.

The rewrite leads with the real reason strtok_r() exists: strtok() keeps the parser position in a hidden static buffer, so it is neither reentrant nor thread-safe and interleaved or concurrent calls clobber each other's state. In-place modification is kept as a secondary note, and strtok_s() (C11 Annex K) is mentioned next to strtok_r() for portability.

No test changes are needed since matching behavior is unchanged.

The message presented strtok()'s documented behavior (modifying the
first argument in place) as the problem. The security-relevant issue is
that strtok() is not reentrant or thread-safe: it stores the parser
position in a hidden static buffer, so interleaved or concurrent calls
corrupt each other's state.

Reword the message around that, keep the in-place modification as a
secondary note, and mention strtok_s() alongside strtok_r().

Signed-off-by: Eljees <3.14hell@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02990032ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

permanently erasing the
delimiter character. Use 'strtok_r()' instead.
Avoid 'strtok()': it is not reentrant or thread-safe, since it keeps the parser
position in a hidden static buffer, so interleaved or concurrent calls (even on

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Describe the saved parser state rather than a buffer

When this diagnostic is shown for any strtok() call, it incorrectly implies that the function stores the parser position in a hidden character buffer. The hidden object is parser state—typically a static pointer into the caller-provided input—while the input itself remains the only token buffer and is modified in place. Since this change is specifically intended to explain the real hazard, calling that state a “static buffer” gives users an inaccurate memory model; describe it as hidden static state or a saved pointer instead.

Useful? React with 👍 / 👎.

Comment on lines +5 to +7
Avoid 'strtok()': it is not reentrant or thread-safe, since it keeps the parser
position in a hidden static buffer, so interleaved or concurrent calls (even on
unrelated strings) clobber each other's state. It also modifies its input in

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Qualify the thread-safety claim as a portability guarantee

For implementations that keep the tokenizer state in thread-local storage, concurrent calls from different threads do not clobber one another, so the unconditional statement that strtok() is not thread-safe is stronger than the C interface guarantees. The portable problem is that C does not require strtok() to avoid data races, while interleaved calls in the same thread still share state. Phrase this as “not guaranteed to be thread-safe” rather than promising that every implementation exhibits concurrent state corruption.

Useful? React with 👍 / 👎.

Avoid 'strtok()': it is not reentrant or thread-safe, since it keeps the parser
position in a hidden static buffer, so interleaved or concurrent calls (even on
unrelated strings) clobber each other's state. It also modifies its input in
place, overwriting each delimiter with a NUL byte. Use the reentrant

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit the NUL-overwrite claim to token-ending delimiters

For inputs with leading, trailing, or consecutive delimiters, strtok() skips some delimiters without modifying them and overwrites only the delimiter that terminates each returned token. Thus “overwriting each delimiter” is observably false—for example, tokenizing ",,a,,b,," leaves several commas intact—and can mislead users inspecting or reusing the mutated buffer. State that token-ending delimiters are replaced with NUL bytes instead.

Useful? React with 👍 / 👎.

Address review feedback on the strtok message:

- the saved parser position is hidden static state (a pointer into the caller's string), not a separate buffer;

- the C standard does not require strtok() to be thread-safe, rather than every implementation racing;

- only the delimiter that terminates each token is overwritten with NUL, not every delimiter.

Signed-off-by: Eljees <3.14hell@gmail.com>
@Eljees

Eljees commented Jul 29, 2026

Copy link
Copy Markdown
Author

All three are right, and on a PR that is specifically about message accuracy they matter. Fixed in d2e8e14:

  • "hidden static buffer" -> "hidden static state". The saved scan position is a pointer into the caller's string, not a separate buffer; the input is the only buffer, and it is modified in place.
  • "not reentrant or thread-safe" -> "not reentrant, and the C standard does not require it to be thread-safe". Implementations that keep the state in TLS are safe across threads; the portable problem is that nothing guarantees it, while interleaved calls in one thread still share state.
  • "each delimiter" -> "each token-ending delimiter". Leading, trailing and repeated delimiters are skipped without being modified - tokenizing ",,a,,b,," leaves several commas intact.

semgrep --test on c/lang/security/insecure-use-strtok-fn.c still passes and --validate reports no errors; the pattern is unchanged, so matching behaviour is identical.

@Eljees

Eljees commented Aug 9, 2026

Copy link
Copy Markdown
Author

Ping on this one and #4023, #4024, #4025, #4026, #4027, #4029 - all open since 27-28 July without a review. They are independent of each other, so they can be handled or closed one by one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

insecure-use-strtok-fn: rule message describes normal behavior instead of actual security risks

1 participant