Opened 2 years ago
Closed 2 years ago
#17861 closed bug (fixed)
tcflush() is implemented incorrectly
Reported by: | waddlesplash | Owned by: | nobody |
---|---|---|---|
Priority: | normal | Milestone: | R1/beta4 |
Component: | System/POSIX | Version: | R1/beta3 |
Keywords: | Cc: | ||
Blocked By: | Blocking: | ||
Platform: | All |
Description
https://xref.landonf.org/source/xref/haiku/src/system/libroot/posix/termios.c#88
https://xref.landonf.org/source/xref/haiku/src/add-ons/kernel/generic/tty/tty.cpp#1774
The libroot version passes a value, the kernel counterpart expects a pointer.
FWIW, Linux apparently uses a value here, so if any code from other OSes invokes this ioctl directly, we need to go that route: https://github.com/bminor/musl/blob/cfdfd5ea3ce14c6abf7fb22a531f3d99518b5a1b/src/termios/tcflush.c
Oddly enough the TTY driver doesn't seem to support this ioctl at all however.
Attachments (1)
Change History (8)
comment:2 by , 2 years ago
TCSBRK and TCFLSH are the only ones with int arg at https://man7.org/linux/man-pages/man4/tty_ioctl.4.html that we support.
comment:3 by , 2 years ago
Oddly enough the TTY driver doesn't seem to support this ioctl at all however.
The tty driver is used only for pseudo-tty (Terminal) and should probably be renamed "pty" as in Linux. I don't think it makes sense to flush there as there are no buffers?
The tcflush support was added (by me) somewhat recently and I was not able to test it very much at the time. As said in the commit message (hrev54559) I have no idea what I'm doing here. I have just copied the code for other ioctls (that use a pointer) and didn't notice the difference.
I think rudolfc had done some testing and it at least allowed him to compile his app, but it wasn't working there either.
I think the "flush" ioctl also need implementation in at least pc_serial, possibly also usb_serial, to make sure the physical buffers are also flushed.
comment:4 by , 2 years ago
Hello guys. After I made the following changes, I was able to use a Python module (PySerial, reading from real hardware with pc_serial
on a loopback wire) without any modifications (it relies on termios' calls to tcflush/tcdrain/etc).
diff --git a/src/add-ons/kernel/generic/tty/tty.cpp b/src/add-ons/kernel/generic/tty/tty.cpp index 913e2708..629003d0 100644 --- a/src/add-ons/kernel/generic/tty/tty.cpp +++ b/src/add-ons/kernel/generic/tty/tty.cpp @@ -1758,10 +1758,7 @@ tty_control(tty_cookie* cookie, uint32 op, void* buffer, size_t length) else if (op == TIOCCBRK) set = false; else { - int value; - if (user_memcpy(&value, buffer, sizeof(value)) != B_OK) - return B_BAD_ADDRESS; - + uintptr_t value = (uintptr_t) buffer; set = value != 0; } @@ -1773,9 +1770,7 @@ tty_control(tty_cookie* cookie, uint32 op, void* buffer, size_t length) case TCFLSH: { - int value; - if (user_memcpy(&value, buffer, sizeof(value)) != B_OK) - return B_BAD_ADDRESS; + uintptr_t value = (uintptr_t) buffer; if (value & TCOFLUSH) { struct tty* otherTTY = cookie->other_tty; if (otherTTY->open_count <= 0)
I've tested the change on the latest nightlies, both on 32 and 64 bits. It works with the test case I'll attach after this comment.
I would like to submit the change for review, but I though it might be prudent to ask for input here first (as I feel I'm way out of my comfort zone with this types of changes).
Thanks in advance.
follow-up: 6 comment:5 by , 2 years ago
an int value is preferred at least for TCFLSH (see TTYFLUSH here)
int value = (int)(uintptr_t) buffer;
comment:6 by , 2 years ago
Replying to korli:
an int value is preferred at least for TCFLSH
Thanks korli!
I'll double check for TIOCCBRK too, and hopefully send a patch for review! Thank you for your work! It is always appreciated!
by , 2 years ago
Attachment: | test_serial.py added |
---|
Updating the test script, as this version works more reliably and it's easier to use.
tcdrain()
seems to have a similar issue. I got an strace that reads:[ 14335] ioctl(0x3, TCSBRK, 0x1, 0x0) = 0x80001301 Bad address () (52 us)
See the TCSBRK case on: https://xref.landonf.org/source/xref/haiku/src/add-ons/kernel/generic/tty/tty.cpp#1753
Edit: I guess
tcsendbreak()
will have the same issue as well (both seem to ioctl with TCSBRK and an int value).Edit2: BSerialPort also calls tcflush() with an int (I caught it with strace:
[ 739] ioctl(0x3, TCFLSH, 0x1, 0x0) = 0x80001301 Bad address () (35 us)
)