[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] Re: libevent-2.0.8-rc/evdns.c:2672: Assertion (req)->handle && (req)->handle->current_req == (req) failed in evdns_cancel_request



On Wed, Nov 3, 2010 at 10:44 PM, Denis Bilenko <denis.bilenko@xxxxxxxxx> wrote:
> On Thu, Nov 4, 2010 at 1:24 AM, Nick Mathewson <nickm@xxxxxxxxxxxxx> wrote:
>>> You free req->handle and then access it.
>>
>> Ugh.  What if we move "req->handle->current_req =NULL" to *above* that "if" ?
>
> Still crashes.

Assuming that it now crashes in a different place from where it used
to crash -- that is, at ASSERT_VALID_REQUEST in evdns_cancel, I've got
an updated patch, attached below.  Third time is maybe the charm.

I'm also attaching a quick-and-dirty stress-test program I used to
provoke the crash, and to verify that the fix works.  If the fix
doesn't work for you, see if you can hack up this test program (or
write your own program) to make the failure reproducible?

thanks,
-- 
Nick
#include <event2/dns.h>
#include <event2/dns_struct.h>
#include <event2/event.h>
#include <event2/event_struct.h>

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>

struct request_status {
  int magic;
  struct event_base *base;
  struct evdns_base *dns_base;
  struct evdns_request *request;
  struct event cancel_event;
  int canceled;
};

#define MAGIC 0x1234abcd

int pending = 0;

void
cancel_request_cb(evutil_socket_t fd, short what, void *arg)
{
  struct request_status *status = arg;

  assert(status->magic == MAGIC);
  evdns_cancel_request(status->dns_base, status->request);

  status->canceled = 1;
}

void
server_cb(struct evdns_server_request *req, void *arg)
{
  ev_uint32_t answer = 0x7f000001;
  assert(req->nquestions);
  evdns_server_request_add_a_reply(req, req->questions[0]->name, 1,
                                   &answer, 100);
  evdns_server_request_respond(req, 0);
}

void
answer_cb(int result, char type, int count, int ttl, void *addresses, void *arg)
{
  struct request_status *status = arg;
  struct event_base *base = status->base;
  assert(status->magic == MAGIC);
  if (result == DNS_ERR_CANCEL) {
    assert(status->canceled);
  }
  event_del(&status->cancel_event);

  memset(status, 0xf0, sizeof(*status));
  free(status);

  if (--pending <= 0)
    event_base_loopexit(base, NULL);
}

void
launch(struct event_base *base, struct evdns_base *dns_base)
{
  struct request_status *status = calloc(1,sizeof(*status));
  struct timeval tv = { 0, 1001 };
  status->magic = MAGIC;
  status->base = base;
  status->dns_base = dns_base;
  event_assign(&status->cancel_event, base, -1, 0, cancel_request_cb, status);
  status->request = evdns_base_resolve_ipv4(
                          dns_base, "foobar.bazquux.example.com", 0,
                          answer_cb, status);
  event_add(&status->cancel_event, &tv);
  ++pending;
}

int
main(int c, char **v)
{
  int i;
  struct event_base *base;
  struct evdns_base *dns_base;
  struct evdns_server_port *server;
  evutil_socket_t fd;
  struct sockaddr_in sin;
  struct sockaddr_storage ss;
  socklen_t slen;

  base = event_base_new();
  dns_base = evdns_base_new(base, 0);

  memset(&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
  sin.sin_port = 0;
  sin.sin_addr.s_addr = htonl(0x7f000001);
  if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("socket");
    return 1;
  }
  evutil_make_socket_nonblocking(fd);
  if (bind(fd, (struct sockaddr*)&sin, sizeof(sin))<0) {
    perror("bind");
    return 1;
  }
  server = evdns_add_server_port_with_base(base, fd, 0, server_cb, base);

  memset(&ss, 0, sizeof(ss));
  slen = sizeof(ss);
  if (getsockname(fd, (struct sockaddr*)&ss, &slen)<0) {
    perror("getsockname");
    return 1;
  }
  evdns_base_nameserver_sockaddr_add(dns_base, (struct sockaddr*)&ss, slen, 0);

  for (i = 0; i < 1000; ++i) {
    launch(base, dns_base);
  }

  event_base_dispatch(base);

  return 0;
}

Attachment: 0001-Don-t-free-evdns_request-handles-until-after-the-cal.patch_v2
Description: Binary data