Skip to content

Invalid file descriptor 0xff for FileWatching #34

Closed

Description

@mzaffalon

I am trying to connect to a machine running Linux from Windows

import LibSSH as ssh
session = ssh.Session("192.168.80.9"; user="root", log_verbosity=ssh.SSH_LOG_FUNCTIONS)

crashes with

Unhandled Task ERROR: ArgumentError: Passed file descriptor fd=Base.Libc.WindowsRawSocket(0xffffffffffffffff) is not a valid file descriptor

On my system the first two calls to ret = lib.ssh_connect(session_ptr) return SSH_AGAIN. Only after the first call session.fd is a positive number. Does _wait_loop(session) start too early?

I use LibSSH v0.7.1 and Julia v1.12.5.

Activity

  1. JamesWrigley commented on Mar 8, 2026

    @JamesWrigley
    Member

    Could you post the full stack trace?

    And yeah, I could see thread safety being the issue. You could test it by starting Julia with -t 1,0 to only start one thread, or you could try #33 which has improved thread safety.

  2. mzaffalon commented on Mar 8, 2026

    @mzaffalon
    Author

    This is with LibSSH v0.7.1 and starting as julia --project=.

    julia> session = ssh.Session("192.168.80.9"; user="root", log_verbosity=ssh.SSH_LOG_FUNCTIONS)
    [2026/03/08 19:19:08.217836, 3] ssh_config_parse_file:  Reading configuration data from C:\Users\nmrsu/.ssh/config
    [2026/03/08 19:19:08.219831, 3] ssh_connect:  libssh 0.11.3 (c) 2003-2025 Aris Adamantiadis, Andreas Schneider and libssh contributors. Distributed under the LGPL, please refer to COPYING file for information about your rights, using threading threads_pthread
    [2026/03/08 19:19:08.223821, 3] getai:  host 192.168.80.9 matches an IP address
    [2026/03/08 19:19:08.226813, 3] ssh_socket_connect:  Nonblocking connection socket: 1416
    [2026/03/08 19:19:08.227810, 3] ssh_connect:  Socket connecting, now waiting for the callbacks to work
    [2026/03/08 19:19:08.229805, 4] ssh_socket_pollcallback:  Poll callback on socket 1416 (POLLOUT ), out buffer 0
    [2026/03/08 19:19:08.231799, 3] ssh_socket_pollcallback:  Received POLLOUT in connecting state
    [2026/03/08 19:19:08.232796, 4] socket_callback_connected:  Socket connection callback: 1 (0)
    [2026/03/08 19:19:08.234790, 3] ssh_client_connection_callback:  session_state=2
    [2026/03/08 19:19:08.235788, 3] ssh_socket_unbuffered_write:  Enabling POLLOUT for socket
    [2026/03/08 19:19:08.236786, 4] ssh_socket_unbuffered_write:  wrote 23
    [2026/03/08 19:19:08.237783, 3] ssh_connect:  current state : 2
    Unhandled Task ERROR: ArgumentError: Passed file descriptor fd=Base.Libc.WindowsRawSocket(0xffffffffffffffff) is not a valid file descriptor
    Stacktrace:
     [1] FileWatching._FDWatcher(fd::Base.Libc.WindowsRawSocket, readable::Bool, writable::Bool)
       @ FileWatching C:\Users\nmrsu\.julia\juliaup\julia-1.12.5+0.x64.w64.mingw32\share\julia\stdlib\v1.12\FileWatching\src\FileWatching.jl:418
     [2] _FDWatcher
       @ C:\Users\nmrsu\.julia\juliaup\julia-1.12.5+0.x64.w64.mingw32\share\julia\stdlib\v1.12\FileWatching\src\FileWatching.jl:413 [inlined]
     [3] _FDWatcher
       @ C:\Users\nmrsu\.julia\juliaup\julia-1.12.5+0.x64.w64.mingw32\share\julia\stdlib\v1.12\FileWatching\src\FileWatching.jl:405 [inlined]
     [4] poll_fd(s::RawFD, timeout_s::Float64; readable::Bool, writable::Bool)
       @ FileWatching C:\Users\nmrsu\.julia\juliaup\julia-1.12.5+0.x64.w64.mingw32\share\julia\stdlib\v1.12\FileWatching\src\FileWatching.jl:801
     [5] _safe_poll_fd(::RawFD, ::Vararg{Any}; kwargs::@Kwargs{readable::Bool, writable::Bool})
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\LibSSH.jl:174
     [6] _safe_poll_fd
       @ C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\LibSSH.jl:171 [inlined]
     [7] macro expansion
       @ .\lock.jl:376 [inlined]
     [8] _wait_loop(session::LibSSH.Session)
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:476
     [9] (::LibSSH.var"#7#8"{LibSSH.Session})()
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:79
    
    caused by: InterruptException:
    Stacktrace:
     [1] try_yieldto(undo::typeof(Base.ensure_rescheduled))
       @ Base .\task.jl:1157
     [2] wait()
       @ Base .\task.jl:1229
     [3] wait(c::Base.GenericCondition{ReentrantLock}; first::Bool)
       @ Base .\condition.jl:141
     [4] wait(session::LibSSH.Session)
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:450
     [5] connect(session::LibSSH.Session)
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:511
     [6]
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:221
     [7] Session
       @ C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:186 [inlined]
     [8] top-level scope
       @ REPL[2]:1
    Some type information was truncated. Use `show(err)` to see complete types.
    
  3. mzaffalon commented on Mar 8, 2026

    @mzaffalon
    Author

    Starting single threaded did not change anything. On the branch safety, it hangs here

    julia> session = ssh.Session("192.168.80.9"; user="root", log_verbosity=ssh.SSH_LOG_FUNCTIONS)
    [2026/03/08 19:28:56.657714, 3] ssh_config_parse_file:  Reading configuration data from C:\Users\nmrsu/.ssh/config
    [2026/03/08 19:28:56.660669, 3] ssh_connect:  libssh 0.11.3 (c) 2003-2025 Aris Adamantiadis, Andreas Schneider and libssh contributors. Distributed under the LGPL, please refer to COPYING file for information about your rights, using threading threads_pthread
    [2026/03/08 19:28:56.663662, 3] getai:  host 192.168.80.9 matches an IP address
    [2026/03/08 19:28:56.664659, 3] ssh_socket_connect:  Nonblocking connection socket: 1488
    [2026/03/08 19:28:56.665656, 3] ssh_connect:  Socket connecting, now waiting for the callbacks to work
    [2026/03/08 19:28:56.667651, 4] ssh_socket_pollcallback:  Poll callback on socket 1488 (POLLOUT ), out buffer 0
    [2026/03/08 19:28:56.668648, 3] ssh_socket_pollcallback:  Received POLLOUT in connecting state
    [2026/03/08 19:28:56.670643, 4] socket_callback_connected:  Socket connection callback: 1 (0)
    [2026/03/08 19:28:56.671643, 3] ssh_client_connection_callback:  session_state=2
    [2026/03/08 19:28:56.672640, 3] ssh_socket_unbuffered_write:  Enabling POLLOUT for socket
    [2026/03/08 19:28:56.674632, 4] ssh_socket_unbuffered_write:  wrote 23
    [2026/03/08 19:28:56.675630, 3] ssh_connect:  current state : 2
    
    ERROR: InterruptException:
    Stacktrace:
     [1] poptask(W::Base.IntrusiveLinkedListSynchronized{Task})
       @ Base .\task.jl:1216
     [2] wait()
       @ Base .\task.jl:1228
     [3] wait(c::Base.GenericCondition{ReentrantLock}; first::Bool)
       @ Base .\condition.jl:141
     [4] wait(session::LibSSH.Session)
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:476
     [5] connect(session::LibSSH.Session)
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:617
     [6]
       @ LibSSH C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:236
     [7] Session
       @ C:\Users\nmrsu\zaffalon\lock-dumps\dev\LibSSH\src\session.jl:201 [inlined]
     [8] top-level scope
       @ REPL[2]:1
    Some type information was truncated. Use `show(err)` to see complete types.
    
  4. mzaffalon commented on Mar 8, 2026

    @mzaffalon
    Author

    Out of curiosity: what was the reason to wrap libssh instead of libssh2 which is shipped by default with Julia?

  5. JamesWrigley commented on Mar 8, 2026

    @JamesWrigley
    Member

    Interesting 🤔 I'll dig into it more next week. If you're down to have a go yourself, you could try modifying this loop body to notify waiters immediately if the file descriptor is not valid:

    while !(@atomic session._waiter_stop_flag) && isopen(session)

    Out of curiosity: what was the reason to wrap libssh instead of libssh2 which is shipped by default with Julia?

    Libssh is much better documented and has more features (particularly server support) compared to libssh2. In fact, back when I started writing the bindings libssh2 didn't have any API docs at all.

  6. JamesWrigley commented on May 9, 2026

    @JamesWrigley
    Member

    Could you try again with latest master? I made some more thread safety fixes.

  7. mzaffalon commented on May 9, 2026

    @mzaffalon
    Author

    Thank you for working on the issue. Since now it hangs while trying to connect to the Linux system, I tried the demo on the localhost and this too hangs

    julia> session = ssh.Session("127.0.0.1", 2222)
    [2026/05/09 18:04:50.195600, 3] ssh_config_parse_file:  Reading configuration data from C:\Users\nmrsu/.ssh/config
    [2026/05/09 18:04:50.197594, 1] ssh_strict_fopen:  Failed to open a file C:/ProgramData/ssh/ssh_config for reading: No such file or directory
    [2026/05/09 18:04:50.200587, 3] ssh_connect:  libssh 0.11.4 (c) 2003-2025 Aris Adamantiadis, Andreas Schneider and libssh contributors. Distributed under the LGPL, please refer to COPYING file for information about your rights, using threading threads_pthread
    [2026/05/09 18:04:50.203579, 3] getai:  host 127.0.0.1 matches an IP address
    [2026/05/09 18:04:50.205575, 3] ssh_socket_connect:  Nonblocking connection socket: 1228
    [2026/05/09 18:04:50.207569, 3] ssh_connect:  Socket connecting, now waiting for the callbacks to work
    [2026/05/09 18:04:50.208565, 4] ssh_socket_pollcallback:  Poll callback on socket 1228 (POLLOUT ), out buffer 0
    [2026/05/09 18:04:50.210560, 3] ssh_socket_pollcallback:  Received POLLOUT in connecting state
    [2026/05/09 18:04:50.211558, 4] socket_callback_connected:  Socket connection callback: 1 (0)
    [2026/05/09 18:04:50.213552, 3] ssh_client_connection_callback:  session_state=2
    [2026/05/09 18:04:50.214550, 3] ssh_socket_unbuffered_write:  Enabling POLLOUT for socket
    [2026/05/09 18:04:50.215546, 4] ssh_socket_unbuffered_write:  wrote 23
    [2026/05/09 18:04:50.217542, 3] ssh_connect:  current state : 2
    

    I also had to comment out the block in LibSSH.jl starting with @compile_workload begin because the compilation hanged too.
    This was on a Windows 10. On a Windows 11, there is no output at all. Can it be that the session is blocked by my organization?

  8. JamesWrigley commented on May 19, 2026

    @JamesWrigley
    Member

    Mmm not sure. Seems kinda unlikely if the LibSSH release worked 🤔 (insofar as it didn't hang)

    We currently don't test windows on CI, I'll add that and see if I can reproduce it.

  9. JamesWrigley commented on Aug 5, 2026

    @JamesWrigley
    Member

    @DeniedPyro, thanks for the report, I closed that issue in favor of keeping everything in this one. I sneakily documented Windows as unsupported in v1 because I couldn't figure it out in time 🙈 I'll have another go this week-ish.

  10. JamesWrigley commented on Aug 11, 2026

    @JamesWrigley
    Member

    Could y'all try the branch in #48? It uses a custom build of libssh that fixes windows support.

  11. DeniedPyro commented on Aug 11, 2026

    @DeniedPyro
    Contributor

    @JamesWrigley Looks good on my side! it runs correctly!

  12. mzaffalon commented on Sep 8, 2026

    @mzaffalon
    Author

    @JamesWrigley: thank you for the work and sorry for joining the party late. On the windows branch, authentication with a private key hangs. Authentication with a password instead works.

    julia> ssh.userauth_publickey(session, "private-key")
    ERROR: InterruptException:
    Stacktrace:
      [1] poptask(W::Base.IntrusiveLinkedListSynchronized{Task})
        @ Base .\task.jl:1216
      [2] wait()
        @ Base .\task.jl:1228
      [3] wait(c::Base.GenericCondition{ReentrantLock}; first::Bool)
        @ Base .\condition.jl:141
      [4] wait
        @ .\condition.jl:136 [inlined]
      [5] wait
        @ C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\utils.jl:32 [inlined]
      [6] macro expansion
        @ C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:552 [inlined]
      [7] macro expansion
        @ .\lock.jl:376 [inlined]
      [8] wait(session::LibSSH.Session)
        @ LibSSH C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:549
      [9] _session_trywait(f::Function, session::LibSSH.Session)
        @ LibSSH C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:1623
     [10] userauth_publickey(session::LibSSH.Session, privkey::LibSSH.PKI.SshKey; throw::Bool)
        @ LibSSH C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:1456
     [11] userauth_publickey
        @ C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:1451 [inlined]
     [12] #userauth_publickey#177
        @ C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:1430 [inlined]
     [13] userauth_publickey(session::LibSSH.Session, path::String)
        @ LibSSH C:\Users\nmr\zaffalon\LibSSH\dev\LibSSH\src\session.jl:1428
     [14] top-level scope
        @ REPL[20]:1
    
  13. JamesWrigley commented on Oct 18, 2026

    @JamesWrigley
    Member

    Could you try again with v1.2.2? I finally got access to a windows system and was able to fix a segfault in CI.

  14. mzaffalon commented on Oct 20, 2026

    @mzaffalon
    Author

    With LibSSH v1.2.2:

    julia> ssh.userauth_publickey(session, "private-key")
    AuthStatus_Success::AuthStatus = 0
    
    julia> read(`ls`, session, String)
    "toggle-H0.py\n"
    

    Fantastic, thank you!

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