Skip to content

Fix write multiple coils byte count validation - #2974

Merged
janiversen merged 4 commits into
pymodbus-dev:devfrom
MrAlaskan:fix/write-multiple-coils-bytes-check
Jul 23, 2026
Merged

Fix write multiple coils byte count validation#2974
janiversen merged 4 commits into
pymodbus-dev:devfrom
MrAlaskan:fix/write-multiple-coils-bytes-check

Conversation

@MrAlaskan

Copy link
Copy Markdown
Contributor

Summary

Validate the byte count when processing a Write Multiple Coils (FC 0x0F) request.

Problem

A Write Multiple Coils request specifies a Quantity of Outputs, a Byte Count, and the output-value bytes. The byte count must equal ceil(Quantity of Outputs / 8), and the payload length must match that byte count.

Previously, WriteMultipleCoilsRequest.decode() read but ignored the Byte Count. If a request declared 16 coils but supplied only one data byte, the decoder produced eight coil values. datastore_update() could then write those eight values and return a successful response for eight coils instead of rejecting the inconsistent request. This silently changed the meaning of the request and could modify datastore state.

Changes

The decoder now preserves the declared quantity, byte count, and actual payload length. Before accessing the datastore, the request verifies that the byte count matches ceil(Quantity of Outputs / 8) and that the payload has exactly the declared length. Invalid requests return ILLEGAL_DATA_VALUE (0x03), while valid client-constructed and decoded requests retain their existing behavior.

Tests cover byte counts that are too small or too large, payloads that are shorter or longer than declared, and successful processing of a valid request. They also verify that malformed requests do not call async_setValues().

@janiversen janiversen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please fix variable name problem (ubuntu 3.14).

@MrAlaskan
MrAlaskan requested a review from janiversen July 23, 2026 09:42

function_code = 15
rtu_byte_count_pos = 6
count: int

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All 3 have values that depends on the actual request.

Having those as class variables creates a potential problem, when used in parallel. This is one of the rare cases where init is needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. The three request-dependent values are now initialized per instance in init.

Comment thread pymodbus/pdu/bit_message.py Outdated
self, context: ModbusServerContext, device_id: int
) -> ModbusPDU:
"""Run a request against a datastore."""
count = len(self.bits)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It is very confusing to have a class variable self.count and a local variable count.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done. The local count variable has been removed, and self.count is now used consistently.

@janiversen
janiversen merged commit 6063742 into pymodbus-dev:dev Jul 23, 2026
16 checks passed
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