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