mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
Bug 1053: Fix crash when download ends prematurely.
Call stacks reported by valgrind: ==14702== at 0x80DD791: read_from_socket (socket.c:945) ==14702== by 0x8104D0C: read_more_http_data (http.c:1180) ==14702== by 0x81052FE: read_http_data (http.c:1388) ==14702== by 0x80DD69B: read_select (socket.c:910) ==14702== by 0x80D27AA: select_loop (select.c:307) ==14702== by 0x80D1ADE: main (main.c:358) ==14702== Address 0x4F4E598 is 56 bytes inside a block of size 81 free'd ==14702== at 0x402210F: free (vg_replace_malloc.c:233) ==14702== by 0x812BED8: debug_mem_free (memdebug.c:484) ==14702== by 0x80D7C82: done_connection (connection.c:479) ==14702== by 0x80D8A44: abort_connection (connection.c:769) ==14702== by 0x80D99CE: cancel_download (connection.c:1053) ==14702== by 0x8110EB6: abort_download (download.c:143) ==14702== by 0x81115BC: download_data_store (download.c:337) ==14702== by 0x8111AFB: download_data (download.c:446) ==14702== by 0x80D7B33: notify_connection_callbacks (connection.c:458) ==14702== by 0x80D781E: set_connection_state (connection.c:388) ==14702== by 0x80D7132: set_connection_socket_state (connection.c:234) ==14702== by 0x80DD78D: read_from_socket (socket.c:943) read_from_socket() attempted to read socket->fd in order to set handlers on it, but the socket had already been freed. Incidentally, socket->fd was -1, which would have resulted in an assertion failure if valgrind hadn't caught the bug first. To fix this, add a list of weak references to sockets. read_from_socket() registers a weak reference on entry and unregisters it before exit. done_socket() breaks any weak references to the specified socket. read_from_socket() then checks whether the weak reference was broken, and doesn't access the socket any more if so.
This commit is contained in:
parent
bda58a124a
commit
00f5831812
@ -69,6 +69,16 @@ struct connect_info {
|
||||
struct uri *uri; /* For updating the blacklist. */
|
||||
};
|
||||
|
||||
/** For detecting whether a struct socket has been deleted while a
|
||||
* function was using it. */
|
||||
struct socket_weak_ref {
|
||||
LIST_HEAD(struct socket_weak_ref);
|
||||
|
||||
/** done_socket() resets this to NULL. */
|
||||
struct socket *socket;
|
||||
};
|
||||
|
||||
static INIT_LIST_OF(struct socket_weak_ref, socket_weak_refs);
|
||||
|
||||
/* To enable logging of tranfers, for debugging purposes. */
|
||||
#if 0
|
||||
@ -143,6 +153,8 @@ init_socket(void *conn, struct socket_operations *ops)
|
||||
void
|
||||
done_socket(struct socket *socket)
|
||||
{
|
||||
struct socket_weak_ref *ref;
|
||||
|
||||
close_socket(socket);
|
||||
|
||||
if (socket->connect_info)
|
||||
@ -150,6 +162,11 @@ done_socket(struct socket *socket)
|
||||
|
||||
mem_free_set(&socket->read_buffer, NULL);
|
||||
mem_free_set(&socket->write_buffer, NULL);
|
||||
|
||||
foreach(ref, socket_weak_refs) {
|
||||
if (ref->socket == socket)
|
||||
ref->socket = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -935,13 +952,26 @@ void
|
||||
read_from_socket(struct socket *socket, struct read_buffer *buffer,
|
||||
struct connection_state state, socket_read_T done)
|
||||
{
|
||||
const int is_buffer_new = (buffer != socket->read_buffer);
|
||||
struct socket_weak_ref ref;
|
||||
select_handler_T write_handler;
|
||||
|
||||
ref.socket = socket;
|
||||
add_to_list(socket_weak_refs, &ref);
|
||||
|
||||
buffer->done = done;
|
||||
|
||||
socket->ops->set_timeout(socket, connection_state(0));
|
||||
socket->ops->set_state(socket, state);
|
||||
|
||||
del_from_list(&ref);
|
||||
if (ref.socket == NULL) {
|
||||
/* socket->ops->set_state deleted the socket. */
|
||||
if (is_buffer_new)
|
||||
mem_free(buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (socket->read_buffer && buffer != socket->read_buffer)
|
||||
mem_free(socket->read_buffer);
|
||||
socket->read_buffer = buffer;
|
||||
|
Loading…
Reference in New Issue
Block a user