In order to set a breakpoint when the assertion is verified, I expanded the macro force_assert(x) in buffer_string_prepare_copy() and buffer_realloc()
and compile lighttpd with -O0 -g
# gdb lighttpd
GNU gdb (GDB) 7.5.1
Copyright (C) 2012 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 "arm-buildroot-linux-gnueabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /usr/sbin/lighttpd...done.
(gdb) list buffer.c:86
warning: Source file is more recent than executable.
81 force_assert(sz > len);
82
83 b->size = sz;
84 b->ptr = realloc(b->ptr, sz);
85
86do {
87if (!(NULL != b->ptr))
88log_failed_assert(__FILE__, __LINE__, "assertion failed: NULL != b->ptr");
89} while(0);
90}
(gdb) break buffer.c:88
Breakpoint 1 at 0x2599c: file buffer.c, line 88.
(gdb) list
91
92__attribute_cold__
93static void buffer_alloc_replace(buffer *b, size_t size) {
94 /*(discard old data so realloc() does not copy)*/
95 if (NULL != b->ptr) {
96 free(b->ptr);
97 b->ptr = NULL;
98 }
99 buffer_realloc(b, size);
100}
(gdb) list
101
102char* buffer_string_prepare_copy(buffer *b, size_t size) {
103do {
104if (!(NULL != b))
105log_failed_assert(__FILE__, __LINE__, "assertion failed: NULL != b");
106} while(0);
107
108if (size >= b->size) buffer_alloc_replace(b, size);
109
110b->used = 0;
(gdb) break buffer.c:105
Breakpoint 2 at 0x25a34: file buffer.c, line 105.
(gdb) run -D -f /etc/lighttpd/lighttpd.conf
Breakpoint 1, buffer_realloc (b=0xe3048, len=47284223) at buffer.c:88
88log_failed_assert(__FILE__, __LINE__, "assertion failed: NULL != b->ptr");
(gdb) bt
#0 buffer_realloc (b=0xe3048, len=47284223) at buffer.c:88
#1 0x00025a0c in buffer_alloc_replace (b=0xe3048, size=47284223)
at buffer.c:99
#2 0x00025a64 in buffer_string_prepare_copy (b=0xe3048, size=47284223)
at buffer.c:108
#3 0x0002e6b4 in chunk_init (sz=47284224) at chunk.c:76
#4 0x0002f308 in chunkqueue_buffer_open_resize (c=0xb00d8, sz=47280832)
at chunk.c:347
#5 0x0002f390 in chunkqueue_prepend_buffer_open_sz (cq=0xb2360, sz=47280832)
at chunk.c:358
#6 0xb6c24c2c in fcgi_create_env (srv=0x6a008, hctx=0xc8798)
at mod_fastcgi.c:230
#7 0x00039a54 in gw_write_request (srv=0x6a008, hctx=0xc8798)
at gw_backend.c:1813
#8 0x0003a004 in gw_send_request (srv=0x6a008, hctx=0xc8798)
at gw_backend.c:1934
#9 0x0003a484 in gw_handle_subrequest (srv=0x6a008, con=0x85988, p_d=0x77e00)
at gw_backend.c:2026
#10 0x0003de90 in plugins_call_handle_subrequest (srv=0x6a008, con=0x85988)
at plugin.c:338
#11 0x000158b4 in http_response_prepare (srv=0x6a008, con=0x85988)
at response.c:695
#12 0x00018760 in connection_state_machine (srv=0x6a008, con=0x85988)
at connections.c:1157
#13 0x000138a0 in server_main (srv=0x6a008, argc=4, argv=0xbeefad04)
at server.c:2037
#14 0x00013b04 in main (argc=4, argv=0xbeefad04) at server.c:2091
The strace corresponding to this is :
gettimeofday({1544613432, 15036}, NULL) = 0
epoll_wait(6, {{EPOLLIN, {u32=7, u64=7}}}, 2049, 1000) = 1
ioctl(7, FIONREAD, [389724]) = 0
brk(0x22fc000) = 0x22fc000
read(7, "\243\337\341\262\240^B\364\33#\v\t\20\242_oYh\343_H\350wv\262v/\256\220\260\317\177"..., 262143) = 262143
write(8, "\243\337\341\262\240^B\364\33#\v\t\20\242_oYh\343_H\350wv\262v/\256\220\260\317\177"..., 262143) = 262143
gettimeofday({1544613432, 31560}, NULL) = 0
epoll_wait(6, {{EPOLLIN, {u32=7, u64=7}}}, 2049, 1000) = 1
ioctl(7, FIONREAD, [127581]) = 0
read(7, "@a\340/\315\210\312\344\303\215S\265\304\32r\"\5ry\263\237\247\213\346\f\33xhhk.\267"..., 262143) = 127581
write(8, "@a\340/\315\210\312\344\303\215S\265\304\32r\"\5ry\263\237\247\213\346\f\33xhhk.\267"..., 127581) = 127581
socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0) = 9
connect(9, {sa_family=AF_LOCAL, sun_path="/tmp/php.socket-1"}, 19) = 0
mmap2(NULL, 34619392, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
brk(0x43ff000) = 0x22fc000
mmap2(NULL, 34750464, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
mmap2(NULL, 2097152, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0xb6a00000
munmap(0xb6b00000, 1048576) = 0
mprotect(0xb6a00000, 135168, PROT_READ|PROT_WRITE) = 0
mmap2(NULL, 34619392, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
write(2, "buffer.c.86: assertion failed: N"..., 46buffer.c.86: assertion failed: NULL != b->ptr
) = 46
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
tgkill(9228, 9228, SIGABRT) = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=9228, si_uid=0} ---
+++ killed by SIGABRT +++
I attached the lighttpd.conf I use.
As you said, with server.stream-request-body=2
, it's working all right.
Here is the ./configure result:
Plugins:
enabled:
mod_access
mod_accesslog
mod_alias
mod_auth
mod_authn_file
mod_cgi
mod_compress
mod_deflate
mod_dirlisting
mod_evhost
mod_expire
mod_extforward
mod_fastcgi
mod_flv_streaming
mod_indexfile
mod_openssl
mod_proxy
mod_redirect
mod_rewrite
mod_rrdtool
mod_scgi
mod_secdownload
mod_setenv
mod_simple_vhost
mod_sockproxy
mod_ssi
mod_staticfile
mod_status
mod_userdir
mod_usertrack
mod_vhostdb
mod_webdav
mod_wstunnel
disabled:
mod_authn_gssapi
mod_authn_ldap
mod_authn_mysql
mod_authn_pam
mod_cml
mod_geoip
mod_magnet
mod_mysql_vhost
mod_trigger_b4_dl
mod_vhostdb_dbi
mod_vhostdb_ldap
mod_vhostdb_mysql
mod_vhostdb_pgsql
Features:
enabled:
auth-crypt
compress-deflate
compress-gzip
large-files
network-ipv6
network-openssl
regex-conditionals
disabled:
compress-bzip2
dbi
geoip
kerberos
ldap
lua
mysql
pam
postgresql
stat-cache-fam
storage-gdbm
storage-memcached
webdav-locks
webdav-properties
Are you using openssl?
So, yes, lighttpd is compiled with openssl, but I don't use it (the web pages are on http:// )
What is the size of the POST request?
It's 47279924 bytes.
Can this be reproduced right when you start lighttpd and send a single request, or is it something that happens after many requests have been sent?
I can reproduce it each time, with a single request.
The attempts by lighttpd to mmap 45+ MB of memory look large, expecially on a low-memory system.
Yes, definitely. (My system has 128MiB, and the uploaded file is in a tmpfs, so if it's mapped in memory and in the tmpfs, it's the end !)
Tell me if you need more infos.
[multiple] reduce initial buffer sz if large POST (fixes #2922)
reduce initial buffer size if large POST to backend stored in temp files
regression in lighttpd 1.4.52
(thx rgenoud)
x-ref:
"[regression] lighttpd gets killed after uploading a big file"
https://redmine.lighttpd.net/issues/2922