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