fix(commons): report TTS options allocation failures as out-of-memory

SH
2d ago
+142-22

Description

rac_tts_options_from_proto can only fail when it cannot allocate a string, because every caller passes a non-null out. Its three call sites still reported that as RAC_ERROR_DECODING_ERROR ("failed to convert TTSOptions"), so a real out-of-memory condition looked like malformed client input:

  • rac_tts_synthesize_lifecycle_proto (tts_module.cpp)
  • rac_tts_synthesize_stream_lifecycle_proto (tts_module.cpp)
  • rac_tts_stream_start_proto (rac_tts_stream.cpp)

The adapter now returns a rac_result_t instead of a bool: RAC_ERROR_NULL_POINTER for a null out, RAC_ERROR_OUT_OF_MEMORY when the voice or language copy fails, and RAC_SUCCESS otherwise. The three call sites pass that code through. Only the return type changes. The cleanup and failure-output rules in the header comment stay as they were. Malformed request bytes are still rejected earlier, when the request is parsed, and still return RAC_ERROR_DECODING_ERROR. This matches how rac_vlm_image_from_proto already separates the two cases.

No other code calls the adapter (I checked core/, engines/ and bindings/).

Fixes #1060

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring

Testing

  • Lint passes locally (git clang-format --diff HEAD -- core reports no changes to the touched lines)
  • Added/updated tests for changes

I extended core/tests/test_nonllm_lifecycle_proto_abi.cpp. When rac_commons is a static library, the test defines its own rac_alloc / rac_free / rac_strdup, which keeps the linker from using rac_memory.cpp's versions. The test's rac_strdup returns NULL for one sentinel string. I put that sentinel into TTSOptions.language_code and, separately, into TTSOptions.voice, and checked that all three ABIs return RAC_ERROR_OUT_OF_MEMORY. Malformed request bytes still return RAC_ERROR_DECODING_ERROR on all three. The mock TTS backend gained a trivial synthesize_stream, so the lifecycle stream path gets as far as the options conversion. The interposition only builds when rac_commons is a STATIC_LIBRARY, which is set in core/tests/CMakeLists.txt.

Without the fix, the test reports 6 failures (all of the OOM checks). With it, all checks pass.

cmake --preset macos-debug
cmake --build build/macos-debug
ctest --preset macos-debug   # 100% tests passed out of 106

Labels

  • Commons - Changes to shared native code (core)

Checklist

  • Code follows project style guidelines
  • Self-review completed
  • Documentation updated (if needed)

Summary by cubic

Reports out-of-memory conditions during TTS options conversion as RAC_ERROR_OUT_OF_MEMORY instead of RAC_ERROR_DECODING_ERROR, so allocation failures are no longer indistinguishable from malformed client input.

  • rac_tts_options_from_proto now returns rac_result_t; its three call sites (lifecycle one-shot, lifecycle stream, and stream sessions) propagate that result instead of always reporting a decoding error.
  • Malformed request bytes are still rejected during parsing and return RAC_ERROR_DECODING_ERROR.
  • Adds ABI tests that inject allocation failures via a test-local rac_strdup and verify all three call sites report RAC_ERROR_OUT_OF_MEMORY.

Fixes #1060.

Summary by CodeRabbit

  • Bug Fixes
    • TTS requests now report more specific errors when options cannot be processed, including insufficient memory and invalid output handling.
    • One-shot, streaming, and session-start synthesis consistently preserve and return the underlying option-conversion error instead of reporting a generic decoding failure.
    • Malformed TTS requests continue to return a decoding error.