deallocate後に参照を行っている
Closed this issue · 1 comments
tkomatsu commented
make debug
でサニタイザをつけてコンパイルし、実行しました。
1件目のリクエストを受け付け、レスポンスを返した後にabortしました。
ログは以下の通りです。
❯ ./webserv
localhost - [Sat, Sep 2021 03:20:58 GMT] "GET / HTTP/1.1" 200 647 "curl/7.64.1"
=================================================================
==14623==ERROR: AddressSanitizer: heap-use-after-free on address 0x617000000438 at pc 0x000107cf3013 bp 0x7ffee7f138a0 sp 0x7ffee7f13898
READ of size 4 at 0x617000000438 thread T0
#0 0x107cf3012 in Client::GetStatus() const Client.cpp:159
#1 0x107d2f028 in WebServ::ExecClientEvent(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<int, ISocket*>, std::__1::__tree_node<std::__1::__value_type<int, ISocket*>, void*>*, long> >) WebServ.cpp:185
#2 0x107d2c58c in WebServ::Activate() WebServ.cpp:36
#3 0x107de5cc0 in main main.cpp:15
#4 0x7fff6b10dcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)
0x617000000438 is located 56 bytes inside of 680-byte region [0x617000000400,0x6170000006a8)
freed by thread T0 here:
#0 0x107f85c0d in wrap__ZdlPv+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x55c0d)
#1 0x107cfdf9c in Client::~Client() Client.hpp:19
#2 0x107d30291 in WebServ::ReadClient(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<int, ISocket*>, std::__1::__tree_node<std::__1::__value_type<int, ISocket*>, void*>*, long> >) WebServ.cpp:132
#3 0x107d2f00d in WebServ::ExecClientEvent(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<int, ISocket*>, std::__1::__tree_node<std::__1::__value_type<int, ISocket*>, void*>*, long> >) WebServ.cpp:181
#4 0x107d2c58c in WebServ::Activate() WebServ.cpp:36
#5 0x107de5cc0 in main main.cpp:15
#6 0x7fff6b10dcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)
previously allocated by thread T0 here:
#0 0x107f857ed in wrap__Znwm+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x557ed)
#1 0x107d2e6a6 in WebServ::AcceptSession(std::__1::__map_iterator<std::__1::__tree_iterator<std::__1::__value_type<int, ISocket*>, std::__1::__tree_node<std::__1::__value_type<int, ISocket*>, void*>*, long> >) WebServ.cpp:113
#2 0x107d2c501 in WebServ::Activate() WebServ.cpp:34
#3 0x107de5cc0 in main main.cpp:15
#4 0x7fff6b10dcc8 in start+0x0 (libdyld.dylib:x86_64+0x1acc8)
SUMMARY: AddressSanitizer: heap-use-after-free Client.cpp:159 in Client::GetStatus() const
Shadow bytes around the buggy address:
0x1c2e00000030: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e00000040: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e00000050: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e00000060: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e00000070: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c2e00000080: fd fd fd fd fd fd fd[fd]fd fd fd fd fd fd fd fd
0x1c2e00000090: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e000000a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e000000b0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e000000c0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x1c2e000000d0: fd fd fd fd fd fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
==14623==ABORTING
zsh: abort ./webserv
原因として考えられるのは、クライアントを削除するタイミングだと思います。
以下のように修正するとabortは無くなりました。
リークするもしくは、メモリが無限に増えていく気がするので、よろしくない修正方法だと思います。
根本的な解決をしたいですね。。。
void WebServ::ReadClient(socket_iter it) {
int client_fd = it->first;
Client *client = dynamic_cast<Client *>(sockets_[client_fd]);
int ret;
if ((ret = client->RecvRequest(client_fd)) <= 0) {
/*
close(client_fd);
delete it->second;
sockets_.erase(it);
*/
}
}