zig
zig copied to clipboard
Incorrect MIPS termios constants
Zig Version
0.10.0-dev.4418+99c3578f6
Steps to Reproduce
#12079 apparently exposed an interesting C ABI issue for MIPS Linux that @topolarity found where when trying to run tests like this the output looks malformed like this:
$ cat test0.zig
test { }
test "test a" {
return error.SkipZigTest;
}
test "test b" {
return error.SkipZigTest;
}
$ ./build/stage3/bin/zig test test0.zig -target mips-linux --test-cmd qemu-mips --test-cmd-bin
Test [2/3] test.test a... SKIP
Test [3/3] test.test b... SKIP
1 passed; 2 skipped; 0 failed.
%
The issue boils down to this tcsetattr
https://github.com/ziglang/zig/blob/5127dae7a28159af8d348d3680f34d51c5cadaaa/lib/std/Progress.zig#L246 in getTerminalCursorColumn
in std.Progress
.
This however is purely a C ABI issue. It should actually work.
Here's reproducible code: it gets termios (the terminal's config) and then sets it. It shouldn't change the terminal at all:
Zig:
const std = @import("std");
pub fn main() !void {
const current_termios = try std.os.tcgetattr(std.os.STDERR_FILENO);
try std.os.tcsetattr(std.os.STDERR_FILENO, .NOW, current_termios);
}
zig build-exe x.zig -target mips-linux; qemu-mips x
Outcome: broken terminal with echo etc. not working.
C:
#include <termios.h>
#include <unistd.h>
int main() {
struct termios current_termios;
tcgetattr(STDERR_FILENO, ¤t_termios);
tcsetattr(STDERR_FILENO, TCSANOW, ¤t_termios);
}
mips-linux-gnu-gcc -static x.c; qemu-mips a.out
Outcome: terminal is the same as before.
You might need the packages gcc-mips-linux-gnu
, qemu-user
, and qemu-system-mips
for your system in order to reproduce this issue.
Expected Behavior
The terminal doesn't break.
Oh I thought this was probably a C ABI issue, but it looks like a broken syscall. The layout of termios
matches just fine on MIPS and the example works with -lc
, so the problem is when Zig performs the ioctl
syscall directly
That or there's some kind of initialization dance that libc is doing which Zig is not
Aha! This is suspicious:
pub const T = struct {
pub const CGETS = if (is_mips) 0x540D else 0x5401;
pub const CSETS = 0x5402;
pub const CSETSW = 0x5403;
pub const CSETSF = 0x5404;
pub const CGETA = 0x5405;
pub const CSETA = 0x5406;
....
Indeed almost all of these are incorrect for MIPS, except for CGETS
Ops, missclick. Sorry about that
See arch/mips/include/uapi/asm/ioctls.h for the full list. Also note the comment in include/uapi/asm-generic/ioctls.h:
The architectures that use different values here typically try to be compatible with some Unix variants for the same architecture.
In this case I bet it's copying IRIX.
This PR is related: https://github.com/ziglang/zig/pull/12771
It tries to define the constants the same way the kernel does, however, I haven't confirmed if all ioctl numbers behave this way, there could be some older values that don't use this new mechanism.