1*eabc0478Schristos /* $NetBSD: regress_finalize.c,v 1.7 2024/08/18 20:47:23 christos Exp $ */ 2b8ecfcfeSchristos 3b8ecfcfeSchristos /* 4b8ecfcfeSchristos * Copyright (c) 2013 Niels Provos and Nick Mathewson 5b8ecfcfeSchristos * 6b8ecfcfeSchristos * Redistribution and use in source and binary forms, with or without 7b8ecfcfeSchristos * modification, are permitted provided that the following conditions 8b8ecfcfeSchristos * are met: 9b8ecfcfeSchristos * 1. Redistributions of source code must retain the above copyright 10b8ecfcfeSchristos * notice, this list of conditions and the following disclaimer. 11b8ecfcfeSchristos * 2. Redistributions in binary form must reproduce the above copyright 12b8ecfcfeSchristos * notice, this list of conditions and the following disclaimer in the 13b8ecfcfeSchristos * documentation and/or other materials provided with the distribution. 14b8ecfcfeSchristos * 3. The name of the author may not be used to endorse or promote products 15b8ecfcfeSchristos * derived from this software without specific prior written permission. 16b8ecfcfeSchristos * 17b8ecfcfeSchristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18b8ecfcfeSchristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19b8ecfcfeSchristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20b8ecfcfeSchristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21b8ecfcfeSchristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22b8ecfcfeSchristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23b8ecfcfeSchristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24b8ecfcfeSchristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25b8ecfcfeSchristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26b8ecfcfeSchristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27b8ecfcfeSchristos */ 28b8ecfcfeSchristos 29b8ecfcfeSchristos #include "event2/event-config.h" 307476e6e4Schristos #include "evconfig-private.h" 31b8ecfcfeSchristos #include "tinytest.h" 32b8ecfcfeSchristos #include "tinytest_macros.h" 33b8ecfcfeSchristos #include <stdlib.h> 34b8ecfcfeSchristos 35b8ecfcfeSchristos #include "event2/event.h" 36b8ecfcfeSchristos #include "event2/util.h" 37b8ecfcfeSchristos #include "event-internal.h" 38b8ecfcfeSchristos #include "defer-internal.h" 39b8ecfcfeSchristos 40b8ecfcfeSchristos #include "regress.h" 41b8ecfcfeSchristos #include "regress_thread.h" 42b8ecfcfeSchristos 43b8ecfcfeSchristos static void 44b8ecfcfeSchristos timer_callback(evutil_socket_t fd, short what, void *arg) 45b8ecfcfeSchristos { 46b8ecfcfeSchristos int *int_arg = arg; 47b8ecfcfeSchristos *int_arg += 1; 48b8ecfcfeSchristos (void)fd; 49b8ecfcfeSchristos (void)what; 50b8ecfcfeSchristos } 51b8ecfcfeSchristos static void 52b8ecfcfeSchristos simple_callback(struct event_callback *evcb, void *arg) 53b8ecfcfeSchristos { 54b8ecfcfeSchristos int *int_arg = arg; 55b8ecfcfeSchristos *int_arg += 1; 56b8ecfcfeSchristos (void)evcb; 57b8ecfcfeSchristos } 58b8ecfcfeSchristos static void 59b8ecfcfeSchristos event_finalize_callback_1(struct event *ev, void *arg) 60b8ecfcfeSchristos { 61b8ecfcfeSchristos int *int_arg = arg; 62b8ecfcfeSchristos *int_arg += 100; 63b8ecfcfeSchristos (void)ev; 64b8ecfcfeSchristos } 65b8ecfcfeSchristos static void 66b8ecfcfeSchristos callback_finalize_callback_1(struct event_callback *evcb, void *arg) 67b8ecfcfeSchristos { 68b8ecfcfeSchristos int *int_arg = arg; 69b8ecfcfeSchristos *int_arg += 100; 70b8ecfcfeSchristos (void)evcb; 71b8ecfcfeSchristos } 72b8ecfcfeSchristos 73b8ecfcfeSchristos 74b8ecfcfeSchristos static void 75b8ecfcfeSchristos test_fin_cb_invoked(void *arg) 76b8ecfcfeSchristos { 77b8ecfcfeSchristos struct basic_test_data *data = arg; 78b8ecfcfeSchristos struct event_base *base = data->base; 79b8ecfcfeSchristos 80b8ecfcfeSchristos struct event *ev; 81b8ecfcfeSchristos struct event ev2; 82b8ecfcfeSchristos struct event_callback evcb; 83b8ecfcfeSchristos int cb_called = 0; 84b8ecfcfeSchristos int ev_called = 0; 85b8ecfcfeSchristos 86b8ecfcfeSchristos const struct timeval ten_sec = {10,0}; 87b8ecfcfeSchristos 88b8ecfcfeSchristos event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); 89b8ecfcfeSchristos ev = evtimer_new(base, timer_callback, &ev_called); 90b8ecfcfeSchristos /* Just finalize them; don't bother adding. */ 91b8ecfcfeSchristos event_free_finalize(0, ev, event_finalize_callback_1); 92b8ecfcfeSchristos event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); 93b8ecfcfeSchristos 94b8ecfcfeSchristos event_base_dispatch(base); 95b8ecfcfeSchristos 96b8ecfcfeSchristos tt_int_op(cb_called, ==, 100); 97b8ecfcfeSchristos tt_int_op(ev_called, ==, 100); 98b8ecfcfeSchristos 99b8ecfcfeSchristos ev_called = cb_called = 0; 100b8ecfcfeSchristos event_base_assert_ok_(base); 101b8ecfcfeSchristos 102b8ecfcfeSchristos /* Now try it when they're active. (actually, don't finalize: make 103b8ecfcfeSchristos * sure activation can happen! */ 104b8ecfcfeSchristos ev = evtimer_new(base, timer_callback, &ev_called); 105b8ecfcfeSchristos event_deferred_cb_init_(&evcb, 0, simple_callback, &cb_called); 106b8ecfcfeSchristos 107b8ecfcfeSchristos event_active(ev, EV_TIMEOUT, 1); 108b8ecfcfeSchristos event_callback_activate_(base, &evcb); 109b8ecfcfeSchristos 110b8ecfcfeSchristos event_base_dispatch(base); 111b8ecfcfeSchristos tt_int_op(cb_called, ==, 1); 112b8ecfcfeSchristos tt_int_op(ev_called, ==, 1); 113b8ecfcfeSchristos 114b8ecfcfeSchristos ev_called = cb_called = 0; 115b8ecfcfeSchristos event_base_assert_ok_(base); 116b8ecfcfeSchristos 117b8ecfcfeSchristos /* Great, it worked. Now activate and finalize and make sure only 118b8ecfcfeSchristos * finalizing happens. */ 119b8ecfcfeSchristos event_active(ev, EV_TIMEOUT, 1); 120b8ecfcfeSchristos event_callback_activate_(base, &evcb); 121b8ecfcfeSchristos event_free_finalize(0, ev, event_finalize_callback_1); 122b8ecfcfeSchristos event_callback_finalize_(base, 0, &evcb, callback_finalize_callback_1); 123b8ecfcfeSchristos 124b8ecfcfeSchristos event_base_dispatch(base); 125b8ecfcfeSchristos tt_int_op(cb_called, ==, 100); 126b8ecfcfeSchristos tt_int_op(ev_called, ==, 100); 127b8ecfcfeSchristos 128b8ecfcfeSchristos ev_called = 0; 129b8ecfcfeSchristos 130b8ecfcfeSchristos event_base_assert_ok_(base); 131b8ecfcfeSchristos 132b8ecfcfeSchristos /* Okay, now add but don't have it become active, and make sure *that* 133b8ecfcfeSchristos * works. */ 134b8ecfcfeSchristos ev = evtimer_new(base, timer_callback, &ev_called); 135b8ecfcfeSchristos event_add(ev, &ten_sec); 136b8ecfcfeSchristos event_free_finalize(0, ev, event_finalize_callback_1); 137b8ecfcfeSchristos 138b8ecfcfeSchristos event_base_dispatch(base); 139b8ecfcfeSchristos tt_int_op(ev_called, ==, 100); 140b8ecfcfeSchristos 141b8ecfcfeSchristos ev_called = 0; 142b8ecfcfeSchristos event_base_assert_ok_(base); 143b8ecfcfeSchristos 144b8ecfcfeSchristos /* Now try adding and deleting after finalizing. */ 145b8ecfcfeSchristos ev = evtimer_new(base, timer_callback, &ev_called); 146b8ecfcfeSchristos evtimer_assign(&ev2, base, timer_callback, &ev_called); 147b8ecfcfeSchristos event_add(ev, &ten_sec); 148b8ecfcfeSchristos event_free_finalize(0, ev, event_finalize_callback_1); 149b8ecfcfeSchristos event_finalize(0, &ev2, event_finalize_callback_1); 150b8ecfcfeSchristos 151b8ecfcfeSchristos event_add(&ev2, &ten_sec); 152b8ecfcfeSchristos event_del(ev); 153b8ecfcfeSchristos event_active(&ev2, EV_TIMEOUT, 1); 154b8ecfcfeSchristos 155b8ecfcfeSchristos event_base_dispatch(base); 156b8ecfcfeSchristos tt_int_op(ev_called, ==, 200); 157b8ecfcfeSchristos 158b8ecfcfeSchristos event_base_assert_ok_(base); 159b8ecfcfeSchristos 160b8ecfcfeSchristos end: 161b8ecfcfeSchristos ; 162b8ecfcfeSchristos } 163b8ecfcfeSchristos 164b8ecfcfeSchristos #ifndef EVENT__DISABLE_MM_REPLACEMENT 165b8ecfcfeSchristos static void * 166b8ecfcfeSchristos tfff_malloc(size_t n) 167b8ecfcfeSchristos { 168b8ecfcfeSchristos return malloc(n); 169b8ecfcfeSchristos } 170b8ecfcfeSchristos static void *tfff_p1=NULL, *tfff_p2=NULL; 171b8ecfcfeSchristos static int tfff_p1_freed=0, tfff_p2_freed=0; 172b8ecfcfeSchristos static void 173b8ecfcfeSchristos tfff_free(void *p) 174b8ecfcfeSchristos { 175b8ecfcfeSchristos if (! p) 176b8ecfcfeSchristos return; 177b8ecfcfeSchristos if (p == tfff_p1) 178b8ecfcfeSchristos ++tfff_p1_freed; 179b8ecfcfeSchristos if (p == tfff_p2) 180b8ecfcfeSchristos ++tfff_p2_freed; 181b8ecfcfeSchristos free(p); 182b8ecfcfeSchristos } 183b8ecfcfeSchristos static void * 184b8ecfcfeSchristos tfff_realloc(void *p, size_t sz) 185b8ecfcfeSchristos { 186b8ecfcfeSchristos return realloc(p,sz); 187b8ecfcfeSchristos } 188b8ecfcfeSchristos #endif 189b8ecfcfeSchristos 190b8ecfcfeSchristos static void 191b8ecfcfeSchristos test_fin_free_finalize(void *arg) 192b8ecfcfeSchristos { 193b8ecfcfeSchristos #ifdef EVENT__DISABLE_MM_REPLACEMENT 194b8ecfcfeSchristos tinytest_set_test_skipped_(); 195b8ecfcfeSchristos #else 196b8ecfcfeSchristos struct event_base *base = NULL; 197b8ecfcfeSchristos struct event *ev, *ev2; 198b8ecfcfeSchristos int ev_called = 0; 199b8ecfcfeSchristos int ev2_called = 0; 200b8ecfcfeSchristos 201b8ecfcfeSchristos (void)arg; 202b8ecfcfeSchristos 203b8ecfcfeSchristos event_set_mem_functions(tfff_malloc, tfff_realloc, tfff_free); 204b8ecfcfeSchristos 205b8ecfcfeSchristos base = event_base_new(); 206b8ecfcfeSchristos tt_assert(base); 207b8ecfcfeSchristos 208b8ecfcfeSchristos ev = evtimer_new(base, timer_callback, &ev_called); 209b8ecfcfeSchristos ev2 = evtimer_new(base, timer_callback, &ev2_called); 210b8ecfcfeSchristos tfff_p1 = ev; 211b8ecfcfeSchristos tfff_p2 = ev2; 212b8ecfcfeSchristos event_free_finalize(0, ev, event_finalize_callback_1); 213b8ecfcfeSchristos event_finalize(0, ev2, event_finalize_callback_1); 214b8ecfcfeSchristos 215b8ecfcfeSchristos event_base_dispatch(base); 216b8ecfcfeSchristos 217b8ecfcfeSchristos tt_int_op(ev_called, ==, 100); 218b8ecfcfeSchristos tt_int_op(ev2_called, ==, 100); 219b8ecfcfeSchristos 220b8ecfcfeSchristos event_base_assert_ok_(base); 221b8ecfcfeSchristos tt_int_op(tfff_p1_freed, ==, 1); 222b8ecfcfeSchristos tt_int_op(tfff_p2_freed, ==, 0); 223b8ecfcfeSchristos 224b8ecfcfeSchristos event_free(ev2); 225b8ecfcfeSchristos 226b8ecfcfeSchristos end: 227b8ecfcfeSchristos if (base) 228b8ecfcfeSchristos event_base_free(base); 229b8ecfcfeSchristos #endif 230b8ecfcfeSchristos } 231b8ecfcfeSchristos 232b8ecfcfeSchristos /* For test_fin_within_cb */ 233b8ecfcfeSchristos struct event_and_count { 234b8ecfcfeSchristos struct event *ev; 235b8ecfcfeSchristos struct event *ev2; 236b8ecfcfeSchristos int count; 237b8ecfcfeSchristos }; 238b8ecfcfeSchristos static void 239b8ecfcfeSchristos event_finalize_callback_2(struct event *ev, void *arg) 240b8ecfcfeSchristos { 241b8ecfcfeSchristos struct event_and_count *evc = arg; 242b8ecfcfeSchristos evc->count += 100; 243b8ecfcfeSchristos event_free(ev); 244b8ecfcfeSchristos } 245b8ecfcfeSchristos static void 246b8ecfcfeSchristos timer_callback_2(evutil_socket_t fd, short what, void *arg) 247b8ecfcfeSchristos { 248b8ecfcfeSchristos struct event_and_count *evc = arg; 249b8ecfcfeSchristos event_finalize(0, evc->ev, event_finalize_callback_2); 250b8ecfcfeSchristos event_finalize(0, evc->ev2, event_finalize_callback_2); 251b8ecfcfeSchristos ++ evc->count; 252b8ecfcfeSchristos (void)fd; 253b8ecfcfeSchristos (void)what; 254b8ecfcfeSchristos } 255b8ecfcfeSchristos 256b8ecfcfeSchristos static void 257b8ecfcfeSchristos test_fin_within_cb(void *arg) 258b8ecfcfeSchristos { 259b8ecfcfeSchristos struct basic_test_data *data = arg; 260b8ecfcfeSchristos struct event_base *base = data->base; 261b8ecfcfeSchristos 262b8ecfcfeSchristos struct event_and_count evc1, evc2; 263b8ecfcfeSchristos evc1.count = evc2.count = 0; 264b8ecfcfeSchristos evc2.ev2 = evc1.ev = evtimer_new(base, timer_callback_2, &evc1); 265b8ecfcfeSchristos evc1.ev2 = evc2.ev = evtimer_new(base, timer_callback_2, &evc2); 266b8ecfcfeSchristos 267b8ecfcfeSchristos /* Activate both. The first one will have its callback run, which 268b8ecfcfeSchristos * will finalize both of them, preventing the second one's callback 269b8ecfcfeSchristos * from running. */ 270b8ecfcfeSchristos event_active(evc1.ev, EV_TIMEOUT, 1); 271b8ecfcfeSchristos event_active(evc2.ev, EV_TIMEOUT, 1); 272b8ecfcfeSchristos 273b8ecfcfeSchristos event_base_dispatch(base); 274b8ecfcfeSchristos tt_int_op(evc1.count, ==, 101); 275b8ecfcfeSchristos tt_int_op(evc2.count, ==, 100); 276b8ecfcfeSchristos 277b8ecfcfeSchristos event_base_assert_ok_(base); 278b8ecfcfeSchristos /* Now try with EV_PERSIST events. */ 279b8ecfcfeSchristos evc1.count = evc2.count = 0; 280b8ecfcfeSchristos evc2.ev2 = evc1.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc1); 281b8ecfcfeSchristos evc1.ev2 = evc2.ev = event_new(base, -1, EV_PERSIST, timer_callback_2, &evc2); 282b8ecfcfeSchristos 283b8ecfcfeSchristos event_active(evc1.ev, EV_TIMEOUT, 1); 284b8ecfcfeSchristos event_active(evc2.ev, EV_TIMEOUT, 1); 285b8ecfcfeSchristos 286b8ecfcfeSchristos event_base_dispatch(base); 287b8ecfcfeSchristos tt_int_op(evc1.count, ==, 101); 288b8ecfcfeSchristos tt_int_op(evc2.count, ==, 100); 289b8ecfcfeSchristos 290b8ecfcfeSchristos event_base_assert_ok_(base); 291b8ecfcfeSchristos end: 292b8ecfcfeSchristos ; 293b8ecfcfeSchristos } 294b8ecfcfeSchristos 295*eabc0478Schristos static void 296*eabc0478Schristos event_finalize_callback_free(struct event *ev, void *arg) 297*eabc0478Schristos { 298*eabc0478Schristos struct event_base *base = arg; 299*eabc0478Schristos int err; 300*eabc0478Schristos if (base) { 301*eabc0478Schristos err = event_assign(ev, base, -1, EV_TIMEOUT, NULL, NULL); 302*eabc0478Schristos tt_int_op(err, ==, 0); 303*eabc0478Schristos test_ok += 1; 304*eabc0478Schristos } else { 305*eabc0478Schristos free(ev); 306*eabc0478Schristos test_ok += 1; 307*eabc0478Schristos } 308*eabc0478Schristos 309*eabc0478Schristos end: 310*eabc0478Schristos ; 311*eabc0478Schristos } 312*eabc0478Schristos static void 313*eabc0478Schristos test_fin_debug_use_after_free(void *arg) 314*eabc0478Schristos { 315*eabc0478Schristos struct basic_test_data *data = arg; 316*eabc0478Schristos struct event_base *base = data->base; 317*eabc0478Schristos struct event *ev; 318*eabc0478Schristos 319*eabc0478Schristos tt_ptr_op(ev = event_new(base, -1, EV_TIMEOUT, NULL, base), !=, NULL); 320*eabc0478Schristos tt_int_op(event_add(ev, NULL), ==, 0); 321*eabc0478Schristos tt_int_op(event_finalize(0, ev, event_finalize_callback_free), ==, 0); 322*eabc0478Schristos 323*eabc0478Schristos // Dispatch base to trigger callbacks 324*eabc0478Schristos event_base_dispatch(base); 325*eabc0478Schristos event_base_assert_ok_(base); 326*eabc0478Schristos tt_int_op(test_ok, ==, 1); 327*eabc0478Schristos 328*eabc0478Schristos // Now add again, since we did event_assign in event_finalize_callback_free 329*eabc0478Schristos // This used to fail in event_debug_assert_is_setup_ 330*eabc0478Schristos tt_int_op(event_add(ev, NULL), ==, 0); 331*eabc0478Schristos 332*eabc0478Schristos // Finalize and dispatch again 333*eabc0478Schristos tt_int_op(event_finalize(0, ev, event_finalize_callback_free), ==, 0); 334*eabc0478Schristos event_base_dispatch(base); 335*eabc0478Schristos event_base_assert_ok_(base); 336*eabc0478Schristos tt_int_op(test_ok, ==, 2); 337*eabc0478Schristos 338*eabc0478Schristos end: 339*eabc0478Schristos ; 340*eabc0478Schristos } 341*eabc0478Schristos 342b8ecfcfeSchristos #if 0 343b8ecfcfeSchristos static void 344b8ecfcfeSchristos timer_callback_3(evutil_socket_t *fd, short what, void *arg) 345b8ecfcfeSchristos { 346b8ecfcfeSchristos (void)fd; 347b8ecfcfeSchristos (void)what; 348b8ecfcfeSchristos 349b8ecfcfeSchristos } 350b8ecfcfeSchristos static void 351b8ecfcfeSchristos test_fin_many(void *arg) 352b8ecfcfeSchristos { 353b8ecfcfeSchristos struct basic_test_data *data = arg; 354b8ecfcfeSchristos struct event_base *base = data->base; 355b8ecfcfeSchristos 356b8ecfcfeSchristos struct event *ev1, *ev2; 357b8ecfcfeSchristos struct event_callback evcb1, evcb2; 358b8ecfcfeSchristos int ev1_count = 0, ev2_count = 0; 359b8ecfcfeSchristos int evcb1_count = 0, evcb2_count = 0; 360b8ecfcfeSchristos struct event_callback *array[4]; 361b8ecfcfeSchristos 362b8ecfcfeSchristos int n; 363b8ecfcfeSchristos 364b8ecfcfeSchristos /* First attempt: call finalize_many with no events running */ 365b8ecfcfeSchristos ev1 = evtimer_new(base, timer_callback, &ev1_count); 366b8ecfcfeSchristos ev1 = evtimer_new(base, timer_callback, &ev2_count); 367b8ecfcfeSchristos event_deferred_cb_init_(&evcb1, 0, simple_callback, &evcb1_called); 368b8ecfcfeSchristos event_deferred_cb_init_(&evcb2, 0, simple_callback, &evcb2_called); 369b8ecfcfeSchristos array[0] = &ev1->ev_evcallback; 370b8ecfcfeSchristos array[1] = &ev2->ev_evcallback; 371b8ecfcfeSchristos array[2] = &evcb1; 372b8ecfcfeSchristos array[3] = &evcb2; 373b8ecfcfeSchristos 374b8ecfcfeSchristos 375b8ecfcfeSchristos 376b8ecfcfeSchristos n = event_callback_finalize_many(base, 4, array, 377b8ecfcfeSchristos callback_finalize_callback_1); 378b8ecfcfeSchristos 379b8ecfcfeSchristos } 380b8ecfcfeSchristos #endif 381b8ecfcfeSchristos 382b8ecfcfeSchristos 383b8ecfcfeSchristos #define TEST(name, flags) \ 384b8ecfcfeSchristos { #name, test_fin_##name, (flags), &basic_setup, NULL } 385b8ecfcfeSchristos 386b8ecfcfeSchristos struct testcase_t finalize_testcases[] = { 387b8ecfcfeSchristos 388b8ecfcfeSchristos TEST(cb_invoked, TT_FORK|TT_NEED_BASE), 389b8ecfcfeSchristos TEST(free_finalize, TT_FORK), 390b8ecfcfeSchristos TEST(within_cb, TT_FORK|TT_NEED_BASE), 391*eabc0478Schristos TEST(debug_use_after_free, TT_FORK|TT_NEED_BASE|TT_ENABLE_DEBUG_MODE), 392b8ecfcfeSchristos // TEST(many, TT_FORK|TT_NEED_BASE), 393b8ecfcfeSchristos 394b8ecfcfeSchristos 395b8ecfcfeSchristos END_OF_TESTCASES 396b8ecfcfeSchristos }; 397b8ecfcfeSchristos 398