h3rald / min

A small but practical concatenative programming language and shell
https://min-lang.org
MIT License
317 stars 23 forks source link

recv-line fails occasionally #191

Open jo-he opened 1 year ago

jo-he commented 1 year ago

Considering the following example from the manual:

{} socket "httpbin.org" 80 connect :cli

cli "GET /uuid HTTP/1.1\r\nHost: httpbin.org\r\n\r\n" send

cli recv-line puts :line
(line "\\}" match? not)
(
  cli recv-line puts @line
) while

Sometimes it fails with:

HTTP/1.1 200 OK
Date: Thu, 23 Feb 2023 21:40:16 GMT
(!) test.min(8,15) [recv-line]: Bad file descriptor
    test.min(8,15) in symbol: recv-line
    test.min(9,7) in symbol: while

When it repeatedly fails in "development mode" (min -d), it repeatedly works in "normal" mode.

Another time, it repeatedly fails in normal mode, but repeatedly works in development mode.

Really strange. I could reproduce this on two entirely different Linux distributions in completely different environments, using the pre-build Linux binary (0.37.0).

strace output from a working run:

sendto(3, "GET /uuid HTTP/1.1\r\nHost: httpbi"..., 41, MSG_NOSIGNAL, NULL, 0) = 41
recvfrom(3, "HTTP/1.1 200 OK\r\nDate: Thu, 23 F"..., 4000, 0, NULL, NULL) = 229
ioctl(1, TIOCGWINSZ, {ws_row=66, ws_col=192, ws_xpixel=1344, ws_ypixel=990}) = 0
writev(1, [{iov_base="HTTP/1.1 200 OK", iov_len=15}, {iov_base="\n", iov_len=1}], 2) = 16
writev(1, [{iov_base="Date: Thu, 23 Feb 2023 08:22:12 "..., iov_len=35}, {iov_base="\n", iov_len=1}], 2) = 36
writev(1, [{iov_base="Content-Type: application/json", iov_len=30}, {iov_base="\n", iov_len=1}], 2) = 31
writev(1, [{iov_base="Content-Length: 53", iov_len=18}, {iov_base="\n", iov_len=1}], 2) = 19
writev(1, [{iov_base="Connection: keep-alive", iov_len=22}, {iov_base="\n", iov_len=1}], 2) = 23
writev(1, [{iov_base="Server: gunicorn/19.9.0", iov_len=23}, {iov_base="\n", iov_len=1}], 2) = 24
writev(1, [{iov_base="Access-Control-Allow-Origin: *", iov_len=30}, {iov_base="\n", iov_len=1}], 2) = 31
writev(1, [{iov_base="Access-Control-Allow-Credentials"..., iov_len=38}, {iov_base="\n", iov_len=1}], 2) = 39
writev(1, [{iov_base="", iov_len=0}, {iov_base="\r\n", iov_len=2}], 2) = 2
writev(1, [{iov_base="", iov_len=0}, {iov_base="\n", iov_len=1}], 2) = 1
recvfrom(3, "{\n  \"uuid\": \"e79ffad6-4dc6-4bf5-"..., 4000, 0, NULL, NULL) = 53

strace output from a failure:

sendto(3, "GET /uuid HTTP/1.1\r\nHost: httpbi"..., 41, MSG_NOSIGNAL, NULL, 0) = 41
recvfrom(3, "HTTP/1.1 200 OK\r\nDate: Thu, 23 F"..., 4000, 0, NULL, NULL) = 282
ioctl(1, TIOCGWINSZ, {ws_row=66, ws_col=192, ws_xpixel=1344, ws_ypixel=990}) = 0
writev(1, [{iov_base="HTTP/1.1 200 OK", iov_len=15}, {iov_base="\n", iov_len=1}], 2) = 16
mmap(NULL, 524288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7031989a5000
writev(1, [{iov_base="Date: Thu, 23 Feb 2023 08:22:14 "..., iov_len=35}, {iov_base="\n", iov_len=1}], 2) = 36
writev(1, [{iov_base="Content-Type: application/json", iov_len=30}, {iov_base="\n", iov_len=1}], 2) = 31
writev(1, [{iov_base="Content-Length: 53", iov_len=18}, {iov_base="\n", iov_len=1}], 2) = 19
writev(1, [{iov_base="Connection: keep-alive", iov_len=22}, {iov_base="\n", iov_len=1}], 2) = 23
writev(1, [{iov_base="Server: gunicorn/19.9.0", iov_len=23}, {iov_base="\n", iov_len=1}], 2) = 24
writev(1, [{iov_base="Access-Control-Allow-Origin: *", iov_len=30}, {iov_base="\n", iov_len=1}], 2) = 31
writev(1, [{iov_base="Access-Control-Allow-Credentials"..., iov_len=38}, {iov_base="\n", iov_len=1}], 2) = 39
writev(1, [{iov_base="", iov_len=0}, {iov_base="\r\n", iov_len=2}], 2) = 2
writev(1, [{iov_base="", iov_len=0}, {iov_base="\n", iov_len=1}], 2) = 1
writev(1, [{iov_base="{", iov_len=1}, {iov_base="\n", iov_len=1}], 2) = 2
writev(1, [{iov_base="  \"uuid\": \"7ebde30d-80e4-489e-85"..., iov_len=48}, {iov_base="\n", iov_len=1}], 2) = 49
recvfrom(544, 0x7fff6ba5ab87, 1, 0, NULL, NULL) = -1 EBADF (Bad file descriptor)

In the last call we see that the first three syscall parameters are somehow messed up.