Skip to content

Bug: Label_4A_DIS dereferences fields[1].substring with no length guard — comma-less DIS payloads throw TypeError and abort MessageDecoder.decode() #493

Description

@kevinelliott

Summary

Label_4A_DIS.decode splits message.text on , and then unconditionally does fields[1].substring(2) — with no fields.length check and no guard on the shape of fields[1]. Because the plugin qualifies on preambles: ['DIS'], any 4A message that starts with DIS but has no comma (e.g. a truncated header, or a DIS-only marker) causes fields[1] to be undefined, so undefined.substring(2) throws TypeError: Cannot read properties of undefined (reading 'substring'). The thrown error escapes the plugin and aborts MessageDecoder.decode() for the rest of the plugin chain — same failure mode as #469, #470, #471, #474, #480, #481, #482.

Affected code

lib/plugins/Label_4A_DIS.ts:16-31

decode(message: Message, options: Options = {}): DecodeResult {
  const decodeResult = this.initResult(message, 'Latest New Format');

  decodeResult.decoded = true;
  const fields = message.text.split(',');
  ResultFormatter.timestamp(
    decodeResult,
    DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + '00'),  // ← throws if fields.length < 2
  );
  ResultFormatter.callsign(decodeResult, fields[2]);                  // ← also unguarded
  ResultFormatter.text(decodeResult, fields.slice(3).join(''));
  ...
}

fields[2] is a secondary hazard: on a two-field message (DIS01,190009), fields[2] is undefined, and ResultFormatter.callsign stores it as-is and formats ${undefined} into the output — silent bad data rather than a crash, but still wrong.

The test.skip('decodes Label 4A_DIS <invalid>', …) case in lib/plugins/Label_4A_DIS.test.ts:43-52 is explicitly disabled with the comment "all messages should decode" — the plugin currently makes the opposite assumption in code and crashes instead.

Reproduction

const decoder = new MessageDecoder();

// Preamble matches, but no comma
decoder.decode({ label: '4A', text: 'DIS' });
// TypeError: Cannot read properties of undefined (reading 'substring')

// Also crashes on a truncated header like just 'DIS01'
decoder.decode({ label: '4A', text: 'DIS01' });
// TypeError: Cannot read properties of undefined (reading 'substring')

Beyond the crash itself, the failure aborts the entire MessageDecoder.decode() loop, so any plugin that would have decoded the message after Label_4A_DIS in the chain never gets a chance to try.

Suggested fix

Guard on fields.length before dereferencing, matching the pattern used in the fixes for #469/#470/#471:

const fields = message.text.split(',');
if (fields.length < 3 || fields[1].length < 2) {
  return this.failUnknown(decodeResult, message.text, options);
}
ResultFormatter.timestamp(
  decodeResult,
  DateTimeUtils.convertHHMMSSToTod(fields[1].substring(2) + '00'),
);
ResultFormatter.callsign(decodeResult, fields[2]);
ResultFormatter.text(decodeResult, fields.slice(3).join(''));

Test coverage

Add cases to lib/plugins/Label_4A_DIS.test.ts for text: 'DIS', text: 'DIS01', and text: 'DIS01,190009' that assert the decoder returns decoded: false / decodeLevel: 'none' without throwing. The currently-skipped <invalid> case can then be re-enabled.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions