Skip to content

Reject partial parses in stou32 - #4555

Merged
mzegla merged 2 commits into
openvinotoolkit:mainfrom
Daksha1611:fix-stou32-partial-parse
Oct 7, 2026
Merged

mzegla merged 2 commits into
openvinotoolkit:mainfrom
Daksha1611:fix-stou32-partial-parse

Conversation

@Daksha1611

@Daksha1611 Daksha1611 commented Sep 12, 2026 •

Copy link
Copy Markdown
Contributor

🛠 Summary

Fixes #4554.

stou32() is the only converter in stringutils that does not verify the whole string was consumed. std::stoul stops at the first character it cannot use and still reports success, so stou32("12abc") returned 12, stou32("3.9") returned 3 and stou32("0x10") returned 0. Its siblings all guard against this by passing &idx and comparing against the length — stou64 at :143-147, stoi32 at :161-165, stof at :203-206. This adds the same check.

Two call sites are affected. grpcservermodule.cpp:79 reads the GRPC_SERVERS environment variable, so GRPC_SERVERS=4x silently started 4 servers instead of being rejected and falling back to config.grpcWorkers(). s2t_servable.cpp:81 uses it as a fallback for the transcription temperature field; that endpoint is also addressed in #4553, and either change alone fixes it — they do not conflict.

The surrounding erase_spaces() call is deliberately left alone, so stou32("12 34") still yields 1234. That is a separate question from partial parsing — note stou64 rejects " 100 " outright — and I did not want two behaviour changes in one commit.

The existing StringUtils.stou32 case covers a negative value, overflow and the maximum, none of which change. Adds StringUtils.stou32RejectsPartialParse for the trailing-garbage spellings plus plain numbers.

I have no OVMS build container available, so this is not compiled against the full tree and CI will need to confirm the build. I did check the change in isolation and confirmed the existing test inputs are unaffected. Draft for that reason.

🧪 Checklist

  • Unit tests added.
  • The documentation updated.
  • Change follows security best practices.

stou32() is the only converter in stringutils that does not verify the whole
string was consumed. std::stoul stops at the first character it cannot use
and still reports success, so:

  stou32("12abc") == 12
  stou32("3.9")   == 3
  stou32("0x10")  == 0
  stou32("100%")  == 100

Its siblings all guard against this by passing &idx and comparing against
the length - stou64 at :143-147, stoi32 at :161-165, stof at :203-206.
(stoi64 at :181-185 validates by scanning digits first, which is
equivalent.) Add the same check.

Call sites this affects:

  grpcservermodule.cpp:79 - the GRPC_SERVERS environment variable.
    GRPC_SERVERS=4x silently started 4 servers instead of being rejected
    and falling back to config.grpcWorkers().
  s2t_servable.cpp:81 - the transcription temperature field, where the
    value is used as a fallback after ovms::stof has already rejected it.

The surrounding erase_spaces() call is deliberately left alone, so
stou32("12 34") still yields 1234. That is a separate question from partial
parsing - note stou64 rejects "   100 " outright - and changing it would be
a second behaviour change in one commit.

Tests: the existing StringUtils.stou32 case only covers a negative value,
overflow and the maximum, none of which change. Adds
StringUtils.stou32RejectsPartialParse for the trailing-garbage spellings
above, plus the plain-number cases to pin that valid input still parses.
@Daksha1611
Daksha1611 marked this pull request as ready for review September 12, 2026 07:09
@mzegla
mzegla requested a lite review from Copilot October 6, 2026 14:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation and regression coverage address the issue; only a minor wording nit remains.

Review effort: Lite
Findings: None

What changed in this PR

Fixes stou32() to reject partially parsed numeric strings, matching sibling converters.

Changes:

  • Added full-consumption validation to stou32.
  • Added regression tests for malformed and valid inputs.
File Description
src/​test/​stringutils_test.cpp Adds coverage for partial-parse rejection and valid values.
src/​stringutils.cpp Rejects inputs not fully consumed by std::stoul.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@mzegla
mzegla merged commit 4e61e33 into openvinotoolkit:main Oct 7, 2026
10 checks passed
mzegla pushed a commit that referenced this pull request Oct 19, 2026
…it (#4553)

### 🛠 Summary

Fixes #4552.

`parseTemperature()` parsed the multipart `temperature` field with
`ovms::stof` and, on failure, retried with `ovms::stou32`. `ovms::stof`
requires the whole field to be consumed; `ovms::stou32` does not, and it
erases spaces first. The fallback therefore rescued exactly the values
`stof` had just rejected, turning malformed input into a plausible
temperature instead of the intended `Invalid temperature type.` error:

```
temperature=0.5x   -> accepted as 0.0, not 0.5, so sampling is silently off
temperature=0abc   -> accepted as 0.0
temperature=1e400  -> accepted as 1.0
temperature=5 5    -> accepted as 55.0
```

The fallback had no purpose — `ovms::stof` already parses integer
spellings, so `"1"` never reached it. Every input it could rescue is
malformed by definition. Removing it lets the existing error path fire.

This deliberately adds no range check. Passing a negative temperature
through for GenAI to reject is the behaviour established by #4201 and
pinned by `negativeTemperatureEnableSampling`, so I left it alone rather
than quietly reverse it. Happy to revisit separately if the endpoint
should enforce the OpenAI audio range at the parse layer.

Adds four cases for the spellings above. The three existing
`SttServableParseTemperatureTest` cases are unaffected — `-1.0`, `0` and
`1.0` all parse cleanly through `ovms::stof` and never reached the
fallback.

The root cause is that `ovms::stou32` alone among the `stringutils`
converters does not check for a partial parse; that is #4554, and the
two fixes are independent.

Since #4555 merged, stou32 rejects partial parses itself, so on main
only "5 5" is still accepted
(stou32 strips the space and parses 55). The other three values stay as
regression tests.

I have no OVMS build container available, so this is not compiled
against the full tree and CI will need to confirm the build. I did check
the change in isolation and verified the three existing test inputs
behave identically. Draft for that reason.

### 🧪 Checklist

- [ ] Unit tests added.
- [ ] The documentation updated.
- [ ] Change follows security best practices.

---------

Co-authored-by: michalkulakowski <Michal.Kulakowski@intel.com>
@Daksha1611
Daksha1611 deleted the fix-stou32-partial-parse branch October 26, 2026 16:39
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.

stou32() accepts partial parses, unlike the other stringutils converters

3 participants