jeremycw / httpserver.h

Single header library for writing non-blocking HTTP servers in C
MIT License
1.78k stars 143 forks source link

Test crashes on OpenBSD #61

Open ChihHao-Su opened 2 years ago

ChihHao-Su commented 2 years ago

OS: OpenBSD 7.2 snapshot amd64 Compiler: GCC 11.2.0

I compiled and started test/main.c first, then ran test/run. All tests before Chunked Request close: (expect empty) are OK, but the test server crashes when running this test.

Output from test/run:

Small Response Body:
Hello, World!

Empty Response:

Echo Body:
Echo test

Get Header:
localhost:8080

Request Body larger than max in mem size:
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 48.0M  100 24.0M  100 24.0M  31.5M  31.5M --:--:-- --:--:-- --:--:-- 63.0M

Chunked Response:
Hello, World!Hello, World!Hello, World!

Chunked Response keep-alive:
Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!

Chunked Response close:
Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!Hello, World!

Chunked Request keep-alive: (expect empty)
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  512k  100  256k  100  256k  12.5M  12.5M --:--:-- --:--:-- --:--:-- 26.3M
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  512k  100  256k  100  256k  21.9M  21.9M --:--:-- --:--:-- --:--:-- 45.4M

Chunked Request close: (expect empty)
(The test server crashed here)

I try to figure it out with gdb. Here is what i got:

☁  test [master] ⚡  egdb ./test             
GNU gdb (GDB) 9.2
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-unknown-openbsd7.1".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...
(gdb) r
Starting program: /home/niko/src/httpserver.h/test/test 

(Reaching test "chunked Request close: (expect empty)")
Program received signal SIGABRT, Aborted.
thrkill () at /tmp/-:3
3   /tmp/-: No such file or directory.
(gdb) bt
#0  thrkill () at /tmp/-:3
#1  0x000000a6d65096ae in _libc_abort () at /usr/src/lib/libc/stdlib/abort.c:51
#2  0x000000a6d6511aaf in memcpy (dst0=<optimized out>, src0=<optimized out>, length=<optimized out>) at /usr/src/lib/libc/string/memcpy.c:74
#3  0x000000a401d319ce in hs_stream_shift (stream=0xa67da65318) at ./../httpserver.h:824
#4  0x000000a401d32553 in http_parse (parser=0xa67da65348, stream=0xa67da65318) at ./../httpserver.h:983
#5  0x000000a401d331c9 in hs_read_and_process_request (request=0xa67da65300) at ./../httpserver.h:1121
#6  0x000000a401d3341a in http_session (request=0xa67da65300) at ./../httpserver.h:1164
#7  0x000000a401d33608 in hs_session_io_cb (ev=0x7f7ffffd1cd0) at ./../httpserver.h:1578
#8  0x000000a401d34f03 in http_server_listen_addr (serv=0xa67da96d00, ipaddr=0x0) at ./../httpserver.h:1604
#9  0x000000a401d34f43 in http_server_listen (serv=0xa67da96d00) at ./../httpserver.h:1611
#10 0x000000a401d356bb in main () at main.c:119

(gdb) frame #2
Invalid character '#' in expression.

(gdb) frame 2
#2  0x00000b4cfcc73aaf in memcpy (dst0=<optimized out>, src0=<optimized out>, length=<optimized out>) at /usr/src/lib/libc/string/memcpy.c:74
74  /usr/src/lib/libc/string/memcpy.c: No such file or directory.

(gdb) frame 3
#3  0x00000b4af9ca99ce in hs_stream_shift (stream=0xb4d4ef4eb18) at ./../httpserver.h:824
824     memcpy(dst, src, bytes);

(gdb) list
819   if (stream->token.index == stream->anchor) return;
820   if (stream->token.len > 0) {
821     char* dst = stream->buf + stream->anchor;
822     char const* src = stream->buf + stream->token.index;
823     int bytes = stream->length - stream->token.index;
824     memcpy(dst, src, bytes);
825   }
826   stream->token.index = stream->anchor;
827   stream->index = stream->token.len + stream->anchor;
828   stream->length = stream->anchor + stream->token.len;

(gdb) print *dst
$1 = 102 'f'

(gdb) print *src
$2 = -32 '\340'

(gdb) print bytes
$3 = 32710

(gdb) print stream->length
$4 = 32883

(gdb) print stream->token.len
$5 = 32710

(gdb) frame 4
#4  0x00000b4af9caa553 in http_parse (parser=0xb4d4ef4eb48, stream=0xb4d4ef4eb18) at ./../httpserver.h:983
983   if (parser->state == CB) hs_stream_shift(stream);

(gdb) list
978     parser->state = to;
979     http_token_t emitted = hs_transition_action(parser, stream, c, from, to);
980     hs_stream_consume(stream);
981     if (emitted.type != HS_TOK_NONE) return emitted;
982   }
983   if (parser->state == CB) hs_stream_shift(stream);
984   token = hs_meta_emit(parser);
985   http_token_t current = hs_stream_current_token(stream);
986   if (
987     current.type != HS_TOK_CHUNK_BODY &&

(gdb) print *stream
$6 = {
  buf = 0xb4d992cb000 "POST /chunked-req HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: curl/7.84.0\r\nAccept: */*\r\nTransfer-Encoding: chunked\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nfff4\r\n\340\257\240\312\375\317\343\364\253\264<\363Fj}p\252F\207\377\275\n\033$\236\021M"..., total_bytes = 32883, capacity = 65536, length = 32883, index = 32883, anchor = 167, token = {index = 173, len = 32710, type = 6}, flags = 0 '\000'}

(gdb) frame 5
#5  0x00000b4af9cab1c9 in hs_read_and_process_request (request=0xb4d4ef4eb00) at ./../httpserver.h:1121
1121        token = http_parse(&request->parser, &request->stream);

(gdb) frame 6
#6  0x00000b4af9cab41a in http_session (request=0xb4d4ef4eb00) at ./../httpserver.h:1164
1164          hs_read_and_process_request(request);

(gdb) print *request
$7 = {handler = 0xb4af9cab5a0 <hs_session_io_cb>, chunk_cb = 0xb4af9cad140 <chunk_req_cb>, data = 0xb4d4ef56bc0, stream = {
    buf = 0xb4d992cb000 "POST /chunked-req HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: curl/7.84.0\r\nAccept: */*\r\nTransfer-Encoding: chunked\r\nContent-Type: application/x-www-form-urlencoded\r\n\r\nfff4\r\n\340\257\240\312\375\317\343\364\253\264<\363Fj}p\252F\207\377\275\n\033$\236\021M"..., total_bytes = 32883, capacity = 65536, length = 32883, index = 32883, anchor = 167, token = {index = 173, len = 32710, type = 6}, flags = 0 '\000'}, parser = {
    content_length = 65524, body_consumed = 32710, match_index = 0, header_count = 5, state = 17 '\021', meta = 11 '\v'}, state = 1, socket = 7, timeout = 20, server = 0xb4d4ef5d500, tokens = {buf = 0xb4d4ef34c00, capacity = 32, 
    size = 14}, flags = 9 '\t'}

(gdb)