Skip to content

Deadlock in ares_queue_wait_empty #742

@johnthacker

Description

@johnthacker

while (ares__llist_len(channel->all_queries)) {
if (timeout_ms < 0) {
ares__thread_cond_wait(channel->cond_empty, channel->lock);
} else {
struct timeval tv_remaining;
struct timeval tv_now = ares__tvnow();
unsigned long tms;
ares__timeval_remaining(&tv_remaining, &tv_now, &tout);
tms = (unsigned long)((tv_remaining.tv_sec * 1000) +
(tv_remaining.tv_usec / 1000));
if (tms == 0) {
status = ARES_ETIMEOUT;
} else {
status =
ares__thread_cond_timedwait(channel->cond_empty, channel->lock, tms);
}
}
}

There's nothing to cancel or timeout or server the pending requests and break out of the loop in the tms == 0 case. If the timeout is short enough that it expires while, e.g., waiting to obtain the mutex, then while the status is set to ARES_ETIMEOUT, the mutex isn't released (unlike the other branches which call ares__thread_cond_timedwait, which releases the mutex while waiting), and so the event thread when calling ares_process_fd cannot obtain the channel lock, channel->all_queries never decreases and the while loop never exits.

I believe the intention is to simply return ARES_ETIMEOUT and let the caller decide to perhaps call ares_cancel, though I'm not sure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions