Skip to content

SimDevice action is called for addresses flagged INVALID (gaps and the end of a block) before the request is rejected #3022

Description

@holgerarthaber

Version: pymodbus 3.15.0 (dev identical in simruntime.py / simdevice.py), Python 3.12

SimDevice.__create_block() fills gaps between SimData entries with DataType.INVALID entries and appends one more INVALID entry at the end of every block. Those entries count towards register_count, so get_reg_block() lets an access to them pass its range check. The INVALID flag is only evaluated in __check_block() after self.action(...) has been awaited. The action is therefore called for addresses that do not exist — for a write, with the values — before the request is rejected with ILLEGAL_ADDRESS. The client gets the right exception, but an action that reacts to writes acts on registers that do not exist. #2926 fixed the lower bound in the same function; this is the other side.

import asyncio
from pymodbus.simulator import DataType, SimData, SimDevice
from pymodbus.simulator.simcore import SimCore

seen = []
async def action(fc, start_address, address, count, current_registers, set_values):
seen.append((fc, address, set_values))

device = SimDevice(1, simdata=(
[SimData(0, values=False, datatype=DataType.BITS)],
[SimData(0, values=False, datatype=DataType.BITS)],
[SimData(0, values=[0] * 5, datatype=DataType.REGISTERS), # holding 0..4
SimData(10, values=[0] * 5, datatype=DataType.REGISTERS)], # holding 10..14 - gap 5..9
[SimData(0, values=0, datatype=DataType.REGISTERS)]), action=action)

async def main():
core = SimCore([device])
for address in (7, 15): # in the gap, one past the end
seen.clear()
rc = await core.async_setValues(1, 6, address, [4321])
print(address, rc, seen)
asyncio.run(main())

7 ExcCodes.ILLEGAL_ADDRESS [(6, 7, [4321])]

15 ExcCodes.ILLEGAL_ADDRESS [(6, 15, [4321])]

Expected: the action is only called for addresses that exist; an access to an INVALID address is rejected before the action runs.
Suggested fix: in __check_block(), evaluate the INVALID (and READONLY) flags before awaiting self.action.
Workaround: a bounds check inside the action.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions