Skip to content

Fix FlexRadio meter-list parse crash on frame without "meter " keyword#491

Merged
patrickrb merged 1 commit into
devfrom
optio/task-6679e17c-ff56-4ed7-914f-7a1373b9efea
Jul 9, 2026
Merged

Fix FlexRadio meter-list parse crash on frame without "meter " keyword#491
patrickrb merged 1 commit into
devfrom
optio/task-6679e17c-ff56-4ed7-914f-7a1373b9efea

Conversation

@patrickrb

Copy link
Copy Markdown
Owner

Summary

FlexMeterInfos.setMeterInfos() can throw an uncaught StringIndexOutOfBoundsException and crash the entire app when a FlexRadio METER_LIST response frame is corrupt or truncated.

Root cause

The parser sliced the meter-definition list with:

temp = content.substring(content.indexOf("meter ") + "meter ".length()).split("#");

with no guard on the indexOf() result. When content does not contain "meter ", indexOf() returns -1, so the offset becomes -1 + 6 = 5, and substring(5) throws StringIndexOutOfBoundsException for any frame shorter than 5 characters (e.g. "0").

This parse runs on the FlexRadio TCP read thread (RadioTcpClient.SocketThread.run()), whose read loop catches only SocketException/IOException:

} catch (SocketException e){ ...
} catch (IOException e) { ...

A RuntimeException therefore propagates out of the read thread uncaught → Android's default handler terminates the process. Same failure class as the previously fixed Xiegu handle (PR #488) and Icom/Kenwood/Yaesu CAT parser crashes (PRs #487/#489): a rig-response parser that trusts the shape of untrusted serial/network input.

Fix

Validate that the "meter " keyword is present before slicing; if it is not, return early (a non-meter frame carries no meter definitions to parse). This is the smallest safe change and additionally prevents a long non-meter frame from being mis-parsed as garbage meter definitions.

int meterIndex = content.indexOf("meter ");
if (meterIndex < 0) return;
temp = content.substring(meterIndex + "meter ".length()).split("#");

No protocol behavior changes for well-formed meter lists.

Testing

  • New FlexMeterInfosTest (pure JVM, no Robolectric — FlexMeterInfos touches no Android types):
    • shortFrameWithoutMeterKeyword_doesNotCrash — the crash regression; fails with StringIndexOutOfBoundsException on the pre-fix code, passes after.
    • parsesWellFormedMeterList — confirms ids (sMeterId/swrId/pwrId/alcId/tempCId), unit mapping, and numeric fields still parse correctly.
    • emptyContent_isNoOp, frameWithoutMeterKeyword_isIgnored, meterKeywordAtEnd_doesNotCrash, reparseUpdatesExistingDefinitions.
  • Verified the regression by reverting the fix and re-running: the buggy code fails exactly shortFrameWithoutMeterKeyword_doesNotCrash.
  • ./gradlew :app:testDebugUnitTest — full suite BUILD SUCCESSFUL.
  • ./gradlew :app:assembleDebug (native/cmake included) — BUILD SUCCESSFUL.

Risk assessment

Very low. One-file guard on a single parse path; no DSP, encoder/decoder, waterfall, or audio code touched. Well-formed frames are unaffected; the only behavior change is that malformed/non-meter frames are now ignored instead of crashing (or being parsed as junk).

Affected platforms

All (FlexRadio 6xxx TCP CAT path).

🤖 Generated with Claude Code

FlexMeterInfos.setMeterInfos() parsed the meter definition list with
    content.substring(content.indexOf("meter ") + 6)
and no guard on the indexOf() result. When a corrupt or truncated
METER_LIST frame does not contain "meter ", indexOf() returns -1, so
the offset becomes 5 and substring(5) throws
StringIndexOutOfBoundsException on any frame shorter than 5 chars.

This runs on the FlexRadio TCP read thread (RadioTcpClient.SocketThread),
whose read loop catches only SocketException/IOException, so the
RuntimeException escapes and crashes the whole app.

Root cause: missing validation that the "meter " keyword is present
before slicing the string. Fix returns early when the keyword is absent
(a non-meter frame has no meter definitions to parse), which also stops
non-meter frames from being parsed as garbage.

Adds FlexMeterInfosTest (pure JVM) covering the crash regression, empty
input, keyword-at-end, non-meter frames, well-formed parsing, and
in-place re-parse.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 23.35%. Comparing base (54b5b13) to head (ea5bde8).

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff            @@
##                dev     #491   +/-   ##
=========================================
  Coverage     23.35%   23.35%           
  Complexity      162      162           
=========================================
  Files           167      167           
  Lines         21450    21450           
  Branches       3154     3154           
=========================================
  Hits           5009     5009           
  Misses        16248    16248           
  Partials        193      193           
Flag Coverage Δ
android 13.26% <ø> (ø)
native 9.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI 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.

Pull request overview

This PR hardens the FlexRadio METER_LIST parser to avoid an app-crashing StringIndexOutOfBoundsException when a response frame is corrupt/truncated and lacks the "meter " keyword, and adds JVM unit tests to prevent regressions.

Changes:

  • Add a guard in FlexMeterInfos.setMeterInfos() to return early when "meter " is missing before slicing/parsing.
  • Add a new pure-JVM FlexMeterInfosTest covering the crash regression and validating well-formed parsing behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ft8af/app/src/main/java/com/k1af/ft8af/flex/FlexMeterInfos.java Adds a safe "meter " presence check to prevent substring-based crashes on malformed frames.
ft8af/app/src/test/java/com/k1af/ft8af/flex/FlexMeterInfosTest.java Adds unit tests for malformed/non-meter frames and for correct parsing of a representative meter list.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@patrickrb patrickrb merged commit 6135d45 into dev Jul 9, 2026
18 checks passed
@patrickrb patrickrb deleted the optio/task-6679e17c-ff56-4ed7-914f-7a1373b9efea branch July 9, 2026 03:47
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.

2 participants