Skip to content

asynInterposeCom: reject a bad ixon option value instead of sending it#234

Merged
MarkRivers merged 1 commit into
epics-modules:masterfrom
physwkim:fix/interpose-com-ixon-return
Jul 16, 2026
Merged

asynInterposeCom: reject a bad ixon option value instead of sending it#234
MarkRivers merged 1 commit into
epics-modules:masterfrom
physwkim:fix/interpose-com-ixon-return

Conversation

@physwkim

Copy link
Copy Markdown
Contributor

In setOption, the ixon branch's else clause writes "Bad option value" into errorMessage but is missing return asynError;, so execution falls through to sbComPortOption(…, xBuf, 2, …) and transmits xBuf[1] — an uninitialized stack byte — as the value of a telnet SET-CONTROL command. Only xBuf[0] is assigned on that path.

The two sibling branches either side of it (parity, crtscts) both end their else with return asynError;; only ixon drops it. The SET-CONTROL value space includes CPO_CONTROL_BREAK_ON = 5, so a stack byte that happens to be 5 asserts a physical BREAK on the serial line to the attached instrument — and because setOption ends with return status;, the caller is told the option was set successfully.

Add the missing return asynError;. Verified with a real interpose over a fake RFC-2217 server: setOption("break","on") first to leave 5 in that stack slot, then setOption("ixon","1") — before, returns asynSuccess and transmits wire byte 5 (BREAK-ON); after, returns asynError and transmits nothing.

setOption("ixon", val) writes "Bad option value" into pasynUser->errorMessage
when val is neither "n" nor "y", but the else branch fell through instead of
returning.  xBuf is a plain uninitialized local (char xBuf[5]) of which only
xBuf[0] is set (CPO_SET_CONTROL), so sbComPortOption() then transmitted
whatever happened to be on the stack in xBuf[1] as the telnet SET-CONTROL
value, and setOption() returned that call's status -- telling the caller the
option had been set successfully.

The value space of SET-CONTROL is not limited to flow control:
CPO_CONTROL_BREAK_ON is 5, so a stack byte of 5 asserts a BREAK on the
physical serial line of the attached instrument.

The two sibling branches already do this:  parity ("Invalid parity selection")
and crtscts ("Bad  value"), the structurally identical branch immediately
above, both end with return asynError.  Only ixon omitted it.

Verified with a test harness that drives the real interpose with a fake
RFC 2217 server underneath it and inspects the bytes reaching the socket.
setOption("break","on") is used first as a legitimate call that leaves
CPO_CONTROL_BREAK_ON in xBuf[1]; being the same function at the same call
depth, the following setOption("ixon","1") reuses that stack slot:

  before:
    setOption("break","on") -> asynSuccess ; SET-CONTROL byte on wire = 5
    setOption("ixon","1")   -> asynSuccess ; SET-CONTROL byte on wire = 5
                               errorMessage = "Bad option value"
                               (1 frame transmitted for a rejected value)
  after:
    setOption("ixon","1")   -> asynError   ; nothing transmitted
                               errorMessage = "Bad option value"
@MarkRivers
MarkRivers merged commit 3a05695 into epics-modules:master Jul 16, 2026
16 of 17 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