Zulip Chat Archive

Stream: lean4

Topic: socket.lean segfault and lean_decode_io_error API


James Sully (Jul 02 2024 at 03:50):

Hi! I'm trying to play around with sockets in lean. I'm using this library

Here's my main:

import Socket

def withUnixSocket path (action : Socket  IO a) := do
  let addr := Socket.SockAddrUnix.unix path
  let sock : Socket  Socket.mk .unix .stream
  sock.connect addr

  let result  action sock

  sock.close

  return result

def main : IO Unit := do

  let sockPath := "/home/james/tmp/lean-timer-socket"

  withUnixSocket sockPath λ _sock  do
    IO.println "socket connected"
    let stdout  IO.getStdout
    _  stdout.getLine

  IO.println "end"

Running this results in a segfault.

Looking at the implementation of socket.lean, it seems like it uses alloy. Is there a way to have alloy compile with debugging symbols so that I can try to figure out what's going on?

James Sully (Jul 02 2024 at 05:21):

Ah, it was because I was trying to connect to a nonexistent socket. touching /home/james/tmp/lean-timer-socket changes it from a segfault to an exception.

github issue here: https://github.com/hargoniX/socket.lean/issues/14

Henrik Böving (Jul 02 2024 at 06:55):

The segfault seems to occur, as some error messages are seemingly unable to cope with having no file name around (others again are unable to cope with having a file name around) in the implementation of error decoding. Your error specifically goes to this branch https://github.com/leanprover/lean4/blob/554e7234330cf06efffe0cb52092e783a27561cc/src/runtime/io.cpp#L175 which then presumably segfaults on the assertion.

I'm a little curious as to why we simply crash if a file name is not provided/provided. This would assume on the one hand knowledge of both the internal behaviors as well as the errors you are potentially about to throw. In particular there might be cases where you throw both file and not file related errros so you have to branch on errno yourself. This makes the trivial fix of "just supply a file name if you are a sockaddr_un" a bit too wonky for me because who knows maybe the socket API is able to throw other errors that trigger segfaults with a file name provided :/

Maybe @Sebastian Ullrich can shine some light on these decisions?

James Sully (Jul 02 2024 at 06:57):

Haha thanks, I was just up to there in my digging in.
I think in this case there ought to be a path - errno is 2 - ENOENT, so it seems like socket.lean should provide the path that's missing.
I guess you're talking about a separate issue to that

James Sully (Jul 02 2024 at 07:09):

One thing I'm a little confused by: wouldn't an assert crash cleanly, rather than segfaulting?

James Sully (Jul 02 2024 at 07:11):

src/runtime/debug.h:

#define lean_assert(COND) DEBUG_CODE({if (LEAN_UNLIKELY(!(COND))) { lean::notify_assertion_violation(__FILE__, __LINE__, #COND); lean::invoke_debugger(); }})

James Sully (Jul 02 2024 at 07:15):

src/include/lean/lean.h:

#define LEAN_UNLIKELY(x) (__builtin_expect((x), 0))

I'm not sure how to find __builtin_expect, so I can't really decipher what's going on here.

James Sully (Jul 02 2024 at 07:17):

I would assume lean::notify_assertion_violation would print something out, but I don't see it. Perhaps assertions are disabled in release builds, and it segfaults later due to continuing with invalid data?

James Sully (Jul 02 2024 at 07:18):

I know all this isn't super relevant to the matter at hand, I'm just taking this as a learning opportunity

Henrik Böving (Jul 02 2024 at 07:25):

James Sully said:

Haha thanks, I was just up to there in my digging in.
I think in this case there ought to be a path - errno is 2 - ENOENT, so it seems like socket.lean should provide the path that's missing.
I guess you're talking about a separate issue to that

But is that generally a good idea? What if we also throw errors where the decode code assumes we have not passed a file name? If the assertion was enabled that would also be a bug.

James Sully (Jul 02 2024 at 07:32):

Ahh, it took me a bit but I think I'm following you now.

James Sully (Jul 02 2024 at 07:34):

it does seem like there's an implicit expectation for the caller to check errno themselves and decide accordingly whether to provide fname, and you're saying lean_decode_io_error should be able to handle an fname even if it's redundant, so that callers don't have to do this check themselves?

Henrik Böving (Jul 02 2024 at 07:35):

Yes

James Sully (Jul 02 2024 at 07:35):

gotcha


Last updated: May 02 2025 at 03:31 UTC