Skip to content

fix: validate byte array length in RegisterFunctions converters (#38)#216

Open
JoshuaVlantis wants to merge 1 commit into
NModbus:masterfrom
JoshuaVlantis:fix/issue-38-readintholdingregisters-wordsize
Open

fix: validate byte array length in RegisterFunctions converters (#38)#216
JoshuaVlantis wants to merge 1 commit into
NModbus:masterfrom
JoshuaVlantis:fix/issue-38-readintholdingregisters-wordsize

Conversation

@JoshuaVlantis

Copy link
Copy Markdown

Summary

Closes #38.

ModbusMasterEnhanced.ReadIntHoldingRegisters (and its Uint / Float siblings) crashed with ArgumentOutOfRangeException: startIndex when the configured wordSize was smaller than the requested numeric type. The exception came from BitConverter.ToInt32(e, e.Length - 4) with e.Length == 2, which gave the caller no idea why their request failed.

This change adds an explicit RequireMinimumByteLength guard in RegisterFunctions so ByteValueArraysToInts, ByteValueArraysToUInts and ByteValueArraysToFloats reject narrow input up front with an ArgumentException that names the offending element and the minimum wordSize required for the read.

It also multi-targets NModbus.UnitTests at net6.0;net8.0 (in addition to the existing net4.6) so the suite can run on Linux .NET runtimes.

Test plan

  • dotnet test NModbus.UnitTests/NModbus.UnitTests.csproj -f net8.0 -c Release passes (265/265 after the fix, including 6 new tests for the validation behavior)
  • Failing-first run with the new tests confirmed the original crash before the fix
  • dotnet build NModbus.IntegrationTests/NModbus.IntegrationTests.csproj -f net6.0 -c Release still succeeds

…bus#38)

ReadIntHoldingRegisters, ReadUintHoldingRegisters and ReadFloatHoldingRegisters
on ModbusMasterEnhanced crashed with a confusing
"ArgumentOutOfRangeException: startIndex" thrown from BitConverter when the
configured wordSize was smaller than the target numeric type (e.g. wordSize=16
for a 32-bit int read).

Add an explicit length check to ByteValueArraysToInts, ByteValueArraysToUInts
and ByteValueArraysToFloats so callers see an actionable ArgumentException
naming the parameter, the offending element index, and the minimum wordSize
required for that read.

Also multi-target NModbus.UnitTests at net6.0 and net8.0 so the test suite can
run on Linux .NET runtimes alongside the existing net4.6 target.

Tests:
* ReadIntHoldingRegisters_WordSize16_ThrowsClearArgumentException
* ReadUintHoldingRegisters_WordSize16_ThrowsClearArgumentException
* ReadFloatHoldingRegisters_WordSize16_ThrowsClearArgumentException
* ReadShortHoldingRegisters_WordSize16_StillWorks
* ReadIntHoldingRegisters_WordSize32_StillWorks
* ByteValueArraysToInts_FrontPaddingWithSmallArray_ThrowsClearArgumentException
@Flundrahn

Copy link
Copy Markdown

Great PR as far as I can see, all tests pass and I have manually tested the old behavior of BitConverter to verify it was already throwing.

It's already good enough to merge.

A nice addition for readability could be to also use sizeof(int) etc instead of the magic numbers that were already present in the RegisterFunctions class.


<PropertyGroup>
<TargetFramework>net4.6</TargetFramework>
<TargetFrameworks>net4.6;net6.0;net8.0</TargetFrameworks>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Let's remove this change here and handle it in #218


private static void RequireMinimumByteLength(byte[][] data, int minBytes, string operation)
{
// Issue #38: previously, supplying byte arrays narrower than the target

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Can remove long comment, code is nice and clear already and there does not seem to be a convention with references to specific issues in this code base.


public static ushort[] ByteValueArraysToUShorts(byte[][] data, bool frontPadding = true)
{
return frontPadding

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Also add validation here

Suggested change
RequireMinimumByteLength(data, sizeof(ushort), nameof(ByteValueArraysToShorts));
return frontPadding


public static short[] ByteValueArraysToShorts(byte[][] data, bool frontPadding = true)
{
return frontPadding

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Also add validation here

Suggested change
RequireMinimumByteLength(data, sizeof(short), nameof(ByteValueArraysToShorts));
return frontPadding

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

paneA-2: 採用しました。peek / consume 初期 lookup / claim 失敗後の latest の3回 findUnique を mockResolvedValueOnce で順序固定し、updateMany count=0 経路を通すよう修正しました(d52bb1bf7)。

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.

Extensions ReadIntHoldingRegisters crashes when using it on 16 bit devices

3 participants