aboutsummaryrefslogtreecommitdiff
path: root/src/set
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2013-11-22 17:42:03 +0000
committerFlorian Dold <florian.dold@gmail.com>2013-11-22 17:42:03 +0000
commit88a06244dbb4cf6fa1e14e43addb6ea448bbcb55 (patch)
tree70d2ec247fa3e7974ff533266091fbe8340abc73 /src/set
parent91a07647c19ff8de90a93aec16d760dbe87699d7 (diff)
downloadgnunet-88a06244dbb4cf6fa1e14e43addb6ea448bbcb55.tar.gz
gnunet-88a06244dbb4cf6fa1e14e43addb6ea448bbcb55.zip
fixed a bug where a set handle was used after free
Diffstat (limited to 'src/set')
-rw-r--r--src/set/set_api.c128
1 files changed, 84 insertions, 44 deletions
diff --git a/src/set/set_api.c b/src/set/set_api.c
index 3c90e74d0..555acf048 100644
--- a/src/set/set_api.c
+++ b/src/set/set_api.c
@@ -362,6 +362,85 @@ handle_client_listener_error (void *cls, enum GNUNET_MQ_Error error)
362} 362}
363 363
364 364
365/**
366 * Destroy the set handle if no operations are left, mark the set
367 * for destruction otherwise.
368 *
369 * @param set set handle to destroy
370 */
371static int
372set_destroy (struct GNUNET_SET_Handle *set)
373{
374 if (NULL != set->ops_head)
375 {
376 set->destroy_requested = GNUNET_YES;
377 return GNUNET_NO;
378 }
379 GNUNET_CLIENT_disconnect (set->client);
380 set->client = NULL;
381 GNUNET_MQ_destroy (set->mq);
382 set->mq = NULL;
383 GNUNET_free (set);
384 return GNUNET_YES;
385}
386
387
388
389
390/**
391 * Cancel the given set operation. We need to send an explicit cancel message,
392 * as all operations one one set communicate using one handle.
393 *
394 * In contrast to GNUNET_SET_operation_cancel, this function indicates whether
395 * the set of the operation has been destroyed because all operations are done and
396 * the set's destruction was requested before.
397 *
398 * @param oh set operation to cancel
399 * @return GNUNET_YES if the set of the operation was destroyed
400 */
401static int
402set_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
403{
404 int ret = GNUNET_NO;
405
406 if (NULL != oh->conclude_mqm)
407 GNUNET_MQ_discard (oh->conclude_mqm);
408
409 /* is the operation already commited? */
410 if (NULL != oh->set)
411 {
412 struct GNUNET_SET_OperationHandle *h_assoc;
413 struct GNUNET_MQ_Envelope *mqm;
414
415 GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
416 h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
417 GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
418 mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
419 GNUNET_MQ_send (oh->set->mq, mqm);
420
421 if (GNUNET_YES == oh->set->destroy_requested)
422 ret = set_destroy (oh->set);
423 }
424
425 GNUNET_free (oh);
426
427 return ret;
428}
429
430
431/**
432 * Cancel the given set operation. We need to send an explicit cancel message,
433 * as all operations one one set communicate using one handle.
434 *
435 * @param oh set operation to cancel
436 */
437void
438GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
439{
440 (void) set_operation_cancel (oh);
441}
442
443
365static void 444static void
366handle_client_set_error (void *cls, enum GNUNET_MQ_Error error) 445handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
367{ 446{
@@ -372,9 +451,9 @@ handle_client_set_error (void *cls, enum GNUNET_MQ_Error error)
372 if (NULL != set->ops_head->result_cb) 451 if (NULL != set->ops_head->result_cb)
373 set->ops_head->result_cb (set->ops_head->result_cls, NULL, 452 set->ops_head->result_cb (set->ops_head->result_cls, NULL,
374 GNUNET_SET_STATUS_FAILURE); 453 GNUNET_SET_STATUS_FAILURE);
375 GNUNET_SET_operation_cancel (set->ops_head); 454 if (GNUNET_YES == set_operation_cancel (set->ops_head))
455 return; /* stop if the set is destroyed */
376 } 456 }
377
378 set->invalid = GNUNET_YES; 457 set->invalid = GNUNET_YES;
379} 458}
380 459
@@ -496,20 +575,13 @@ GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
496 575
497/** 576/**
498 * Destroy the set handle, and free all associated resources. 577 * Destroy the set handle, and free all associated resources.
578 *
579 * @param set set handle to destroy
499 */ 580 */
500void 581void
501GNUNET_SET_destroy (struct GNUNET_SET_Handle *set) 582GNUNET_SET_destroy (struct GNUNET_SET_Handle *set)
502{ 583{
503 if (NULL != set->ops_head) 584 (void) set_destroy (set);
504 {
505 set->destroy_requested = GNUNET_YES;
506 return;
507 }
508 GNUNET_CLIENT_disconnect (set->client);
509 set->client = NULL;
510 GNUNET_MQ_destroy (set->mq);
511 set->mq = NULL;
512 GNUNET_free (set);
513} 585}
514 586
515 587
@@ -689,38 +761,6 @@ GNUNET_SET_accept (struct GNUNET_SET_Request *request,
689 761
690 762
691/** 763/**
692 * Cancel the given set operation. We need to send an explicit cancel message,
693 * as all operations one one set communicate using one handle.
694 *
695 * @param oh set operation to cancel
696 */
697void
698GNUNET_SET_operation_cancel (struct GNUNET_SET_OperationHandle *oh)
699{
700 if (NULL != oh->conclude_mqm)
701 GNUNET_MQ_discard (oh->conclude_mqm);
702
703 /* is the operation already commited? */
704 if (NULL != oh->set)
705 {
706 struct GNUNET_SET_OperationHandle *h_assoc;
707 struct GNUNET_MQ_Envelope *mqm;
708
709 GNUNET_CONTAINER_DLL_remove (oh->set->ops_head, oh->set->ops_tail, oh);
710 h_assoc = GNUNET_MQ_assoc_remove (oh->set->mq, oh->request_id);
711 GNUNET_assert ((h_assoc == NULL) || (h_assoc == oh));
712 mqm = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SET_CANCEL);
713 GNUNET_MQ_send (oh->set->mq, mqm);
714
715 if (GNUNET_YES == oh->set->destroy_requested)
716 GNUNET_SET_destroy (oh->set);
717 }
718
719 GNUNET_free (oh);
720}
721
722
723/**
724 * Commit a set to be used with a set operation. 764 * Commit a set to be used with a set operation.
725 * This function is called once we have fully constructed 765 * This function is called once we have fully constructed
726 * the set that we want to use for the operation. At this 766 * the set that we want to use for the operation. At this