Skip to content

std: /dev/ptmx in MSYS2 is not recognized as a tty in std::io::IsTerminal #119658

Closed

Description

@petrochenkov

How to reproduce:

./x t tests/run-make --test-args emit-to-stdout

That test (tests\run-make\emit-to-stdout\Makefile) checks that rustc's behavior with options like --emit obj is different depending on whether stdout is tty or not.
That test uses /dev/ptmx as stdout and fails when run under MSYS2.

cc @ChrisDenton

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Jan 6, 2024
  2. petrochenkov commented on Jan 6, 2024

    @petrochenkov
    ContributorAuthor
    we@WIN-GQ6AS7OLS34 MINGW64 ~
    $ rustc --emit obj=- hello.rs 1>/dev/ptmx
    
    we@WIN-GQ6AS7OLS34 MINGW64 ~
    $ rustc --emit obj=- hello.rs
    error: option `-o` or `--emit` is used to write binary output type `obj` to stdout, but stdout is a tty
    
    error: aborting due to 1 previous error
    

    Cannot check the behavior on Linux right now, but if nobody complains about failing run-make tests, then /dev/ptmx is probably considered a tty there.
    UPD: Yep, /dev/ptmx is a tty on Linux and rustc refuses to --emit obj into it.

  3. ChrisDenton commented on Jan 6, 2024

    @ChrisDenton
    Member

    Does it work with MSYS=enable_pcon set in msys2.ini?

    For msys2 without pseudoconsole support there's no way to really know if something is a tty or not so we use heuristics based on the pipe name, these may need updated. If msys2 is using the Windows pseudoconsole then it should just work as it should be detected as a normal Windows console handle (unless /dev/ptmx is special in some other way).

  4. petrochenkov commented on Jan 6, 2024

    @petrochenkov
    ContributorAuthor

    Does it work with MSYS=enable_pcon set in msys2.ini?

    No, it doesn't help.

    For msys2 without pseudoconsole support there's no way to really know if something is a tty or not so we use heuristics based on the pipe name, these may need updated

    I did assume it was some missing heuristic in fn msys_tty_on.

  5. ChrisDenton commented on Jan 6, 2024

    @ChrisDenton
    Member

    Ah, actually the problem is this check:

    // At this point, we *could* have a false negative. We can determine that this is a true
    // negative if we can detect the presence of a console on any of the standard I/O streams. If
    // another stream has a console, then we know we're in a Windows console and can therefore
    // trust the negative.
    for std_handle in [c::STD_INPUT_HANDLE, c::STD_OUTPUT_HANDLE, c::STD_ERROR_HANDLE] {
    let std_handle = c::GetStdHandle(std_handle);
    if !std_handle.is_null()
    && std_handle != handle
    && c::GetConsoleMode(std_handle, &mut out) != 0
    {
    return false;
    }
    }

    The trouble is even if enable_pcon is set (which it turns out it is by default now) /dev/ptmx is still a pipe instead of a pseduoconsole handle. So unless all std handles are redirected, it will return negative.

  6. ChrisDenton commented on Jan 6, 2024

    @ChrisDenton
    Member

    I created a fix in #119664 by simply removing the above code. This decreases the chances of a false negative at the cost of increasing the chances of a false positive. But I think simply inspecting the pipe name is overall the most reliable way to detect an msys2 tty.

  7. added
    O-windowsOperating system: Windows
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Jan 6, 2024
  8. lygstate commented on Jan 16, 2024

    @lygstate
    Contributor

    Why /dev/ptmx is a pipe, can that be checked by environment variable?

  9. ChrisDenton commented on Jan 17, 2024

    @ChrisDenton
    Member

    You'd have to ask msys2 why that is. Maybe it's a bug or maybe there's some reason for it. I don't know.

    can that be checked by environment variable

    I don't think so.

  10. petrochenkov commented on Jan 22, 2024

    @petrochenkov
    ContributorAuthor

    You'd have to ask msys2 why that is. Maybe it's a bug or maybe there's some reason for it. I don't know.

    @mati865, maybe you know?

  11. mati865 commented on Jan 22, 2024

    @mati865
    Member

    Unfortunately I don't know much about Cygwin's internals.

  12. Biswa96 commented on Jan 22, 2024

    @Biswa96

    Unfortunately I am not familiar with Rust language. I assumed the rust code looks like following C code.

    #include <stdio.h>
    #include <windows.h>
    
    int main(void)
    {
        DWORD mode;
        printf("%d\n", GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode));
        printf("%d\n", GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode));
        printf("%d\n", GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode));
    }

    That program prints 1 (TRUE) for all handles in msys2 environment with conpty enabled.
    With MSYS=disable_pcon environment variable, that program prints 0 (FALSE) for all handles.

  13. ChrisDenton commented on Jan 22, 2024

    @ChrisDenton
    Member

    @Biswa96 if that program is called isconsole then doing the following:

    ./isconsole 2>/dev/ptmx
    

    prints:

    1
    1
    0
    
  14. Biswa96 commented on Jan 22, 2024

    @Biswa96

    @tyan0 may provide some information about that.

  15. added 2 commits that reference this issue on Jan 22, 2024
    06c2757
    67d0936
  16. tyan0 commented on Jan 22, 2024

    @tyan0

    /dev/ptmx is a device for native msys2 (cygwin) programs. I guess you are using native windows rust compiler. In that case, the program built is also native windows program.

    /dev/ptmx is a tty for native msys2 program, however it is just a pipe for native windows program. So, the result is as the author reported.

    You can confirm the behaviour with the code:

    #include <stdio.h>
    #include <unistd.h>
    int main() {
        printf("%d\n", isatty(0));
        printf("%d\n", isatty(1));
        printf("%d\n", isatty(2));
        return 0;
    }
    

    If you compile this using /usr/bin/gcc and run ./a.exe 2>/dev/ptmx, the result is:

    1
    1
    1
    

    however, with /mingw64/bin/gcc, the result is:

    64
    64
    0
    

    I do not think there is much meaning to check behaviour with /dev/ptmx for native windows program, because it does not provide any meaningful functions for native windows program.

  17. added a commit that references this issue on Jan 23, 2024
    2d15bb9
  18. Biswa96 commented on Jan 23, 2024

    @Biswa96

    I am bit curious why a test for native Windows platform runs a command like program > /dev/ptmx. Should not that test be excluded in Windows?

  19. ChrisDenton commented on Jan 23, 2024

    @ChrisDenton
    Member

    Test file is here: https://github.com/rust-lang/rust/blob/master/tests/run-make/emit-to-stdout/Makefile

    On Windows our "run-make" tests use msys2 (or git bash, but same difference) so the Makefile is cross-platform, This particular test is testing that emitting binary data to a tty correctly fails. This is definitely something that should be tested on Windows. I'm not totally sure why /dev/ptmx is used for this but I'd assume it's so that the tty is independent of the one we're using for normal output (otherwise it would be annoying if the test fails and binary data is actually written to the tty).

    See also #111626 which introduced the test. cc @pjhades

  20. pjhades commented on Jan 23, 2024

    @pjhades
    Contributor

    This particular test is testing that emitting binary data to a tty correctly fails.

    Yes, that's the purpose of adding such (failure) tests.

    I am bit curious why a test for native Windows platform runs a command like program > /dev/ptmx. Should not that test be excluded in Windows?

    I'm not totally sure why /dev/ptmx is used for this but I'd assume it's so that the tty is independent of the one we're using for normal output (otherwise it would be annoying if the test fails and binary data is actually written to the tty).

    If I remember correctly, in the test I initially tried

    obj: $(OUT)
    	$(RUSTC) --emit obj=- $(SRC) 2>$(OUT)/$@ || true
    	diff $(OUT)/$@ emit-obj.stderr
    

    but found that the tests would then fail, because stdout was already redirected in the test environment, so the expected error didn't happen. I used /dev/ptmx because that was the one that worked on all the platforms.

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

    C-bugCategory: This is a bug.O-windowsOperating system: WindowsT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions