1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

Erase progress.timer before calling progress.timer_func

Previously, each progress timer function registered with
start_update_progress() was directly used as the timer function of
progress.timer, so it was responsible of erasing the expired timer ID
from that member.  Failing to do this could result in heap corruption.
The progress timer functions normally fulfilled the requirement by
calling update_progress(), but one such function upload_stat_timer()
had to erase the timer ID on its own too.

Now instead, there is a wrapper function progress_timeout(), which
progress.c sets as the timer function of progress.timer.  This wrapper
erases the expired timer ID from progress.timer and then calls the
progress timer function registered with start_update_progress().  So
the progress timer function is no longer responsible of erasing the
timer ID and there's no risk that it could fail to do that in some
error situation.

This commit introduces a new risk though.  Previously, if the struct
progress was freed while the timer was running, the (progress) timer
function would still be called, and it would be able to detect that
the progress pointer is NULL and recover from this situation.  Now,
the timer function progress_timeout() has a pointer to the struct
progress and will dereference that pointer without being able to check
whether the structure has been freed.  Fortunately, done_progress()
asserts that the timer is not running, so this should not occur.
This commit is contained in:
Kalle Olavi Niemitalo 2008-06-15 11:25:33 +03:00 committed by Kalle Olavi Niemitalo
parent 1d5405e34e
commit d6fd2ac31f
3 changed files with 24 additions and 25 deletions

View File

@ -327,37 +327,26 @@ update_connection_progress(struct connection *conn)
update_progress(conn->progress, conn->received, conn->est_length, conn->from); update_progress(conn->progress, conn->received, conn->est_length, conn->from);
} }
/** Progress timer callback for @a conn->progress. As explained in /** Progress timer callback for @a conn->progress. */
* start_update_progress(), this function must erase the expired timer
* ID from @a conn->progress->timer. */
static void static void
stat_timer(struct connection *conn) stat_timer(struct connection *conn)
{ {
update_connection_progress(conn); update_connection_progress(conn);
/* The expired timer ID has now been erased. */
notify_connection_callbacks(conn); notify_connection_callbacks(conn);
} }
/** Progress timer callback for @a conn->upload_progress. As explained /** Progress timer callback for @a conn->upload_progress. */
* in start_update_progress(), this function must erase the expired timer
* ID from @a conn->upload_progress->timer. */
static void static void
upload_stat_timer(struct connection *conn) upload_stat_timer(struct connection *conn)
{ {
struct http_connection_info *http = conn->info; struct http_connection_info *http = conn->info;
assert(conn->http_upload_progress); assert(conn->http_upload_progress);
if_assert_failed return;
assert(http); assert(http);
if_assert_failed { if_assert_failed return;
conn->http_upload_progress->timer = TIMER_ID_UNDEF;
/* The expired timer ID has now been erased. */
return;
}
update_progress(conn->http_upload_progress, http->post.uploaded, update_progress(conn->http_upload_progress, http->post.uploaded,
http->post.total_upload_length, http->post.uploaded); http->post.total_upload_length, http->post.uploaded);
/* The expired timer ID has now been erased. */
notify_connection_callbacks(conn); notify_connection_callbacks(conn);
} }

View File

@ -45,8 +45,20 @@ done_progress(struct progress *progress)
mem_free(progress); mem_free(progress);
} }
/* Called from the timer callback of @progress->timer. This function /** Timer callback for progress.timer. As explained in install_timer(),
* erases the expired timer ID on behalf of the actual callback. */ * this function must erase the expired timer ID from all variables. */
static void
progress_timeout(void *progress_voidptr)
{
struct progress *const progress = progress_voidptr;
progress->timer = TIMER_ID_UNDEF;
/* The expired timer ID has now been erased. */
progress->timer_func(progress->timer_func_data);
}
/* Usually called from the timer callback of @progress->timer. */
void void
update_progress(struct progress *progress, off_t loaded, off_t size, off_t pos) update_progress(struct progress *progress, off_t loaded, off_t size, off_t pos)
{ {
@ -89,13 +101,14 @@ update_progress(struct progress *progress, off_t loaded, off_t size, off_t pos)
timeval_from_seconds(&progress->estimated_time, timeval_from_seconds(&progress->estimated_time,
(progress->size - progress->pos) / progress->average_speed); (progress->size - progress->pos) / progress->average_speed);
install_timer(&progress->timer, SPD_DISP_TIME, progress->timer_func, progress->timer_func_data); install_timer(&progress->timer, SPD_DISP_TIME,
/* The expired timer ID has now been erased. */ progress_timeout, progress);
} }
/* As in @install_timer, @timer_func should erase the expired timer ID /*! Unlike in install_timer(), @a timer_func need not erase the
* from @progress->timer. The usual way to ensure this is to make * expired timer ID from @a progress->timer. update_progress()
* @timer_func call @update_progress, which sets a new timer. */ * installs the timer with a wrapper function that takes care of
* erasing the timer ID. */
void void
start_update_progress(struct progress *progress, void (*timer_func)(void *), start_update_progress(struct progress *progress, void (*timer_func)(void *),
void *timer_func_data) void *timer_func_data)

View File

@ -186,9 +186,7 @@ update_bittorrent_connection_state(struct connection *conn)
} }
} }
/* Progress timer callback for @bittorrent->upload_progress. As /* Progress timer callback for @bittorrent->upload_progress. */
* explained in @start_update_progress, this function must erase the
* expired timer ID from @bittorrent->upload_progress->timer. */
static void static void
update_bittorrent_connection_upload(void *data) update_bittorrent_connection_upload(void *data)
{ {
@ -198,7 +196,6 @@ update_bittorrent_connection_upload(void *data)
bittorrent->uploaded, bittorrent->uploaded,
bittorrent->downloaded, bittorrent->downloaded,
bittorrent->uploaded); bittorrent->uploaded);
/* The expired timer ID has now been erased. */
} }
void void