posixshm_test.c revision 289437
1/*-
2 * Copyright (c) 2006 Robert N. M. Watson
3 * All rights reserved.
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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: user/ngie/more-tests2/tests/sys/posixshm/posixshm_test.c 289437 2015-10-17 03:13:22Z ngie $");
29
30#include <sys/param.h>
31#include <sys/mman.h>
32#include <sys/resource.h>
33#include <sys/stat.h>
34#include <sys/syscall.h>
35#include <sys/wait.h>
36
37#include <errno.h>
38#include <fcntl.h>
39#include <signal.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include <atf-c.h>
46
47#define	TEST_PATH_LEN	256
48static char test_path[TEST_PATH_LEN];
49
50static void
51gen_test_path(void)
52{
53	char *tmpdir = getenv("TMPDIR");
54
55	if (tmpdir == NULL)
56		tmpdir = "/tmp";
57
58	snprintf(test_path, sizeof(test_path), "%s/tmp.XXXXXX", tmpdir);
59	test_path[sizeof(test_path) - 1] = '\0';
60	ATF_REQUIRE_MSG(mkstemp(test_path) != -1,
61	    "mkstemp failed; errno=%d", errno);
62	ATF_REQUIRE_MSG(unlink(test_path) == 0,
63	    "unlink failed; errno=%d", errno);
64}
65
66/*
67 * Attempt a shm_open() that should fail with an expected error of 'error'.
68 */
69static void
70shm_open_should_fail(const char *path, int flags, mode_t mode, int error)
71{
72	int fd;
73
74	fd = shm_open(path, flags, mode);
75	ATF_CHECK_MSG(fd == -1, "shm_open didn't fail");
76	ATF_CHECK_MSG(error == errno,
77	    "shm_open didn't fail with expected errno; errno=%d; expected "
78	    "errno=%d", errno, error);
79}
80
81/*
82 * Attempt a shm_unlink() that should fail with an expected error of 'error'.
83 */
84static void
85shm_unlink_should_fail(const char *path, int error)
86{
87
88	ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail");
89	ATF_CHECK_MSG(error == errno,
90	    "shm_unlink didn't fail with expected errno; errno=%d; expected "
91	    "errno=%d", errno, error);
92}
93
94/*
95 * Open the test object and write '1' to the first byte.  Returns valid fd
96 * on success and -1 on failure.
97 */
98static int
99scribble_object(void)
100{
101	char *page;
102	int fd;
103
104	gen_test_path();
105
106	fd = shm_open(test_path, O_CREAT|O_EXCL|O_RDWR, 0777);
107	if (fd < 0 && errno == EEXIST) {
108		if (shm_unlink(test_path) < 0)
109			atf_tc_fail("shm_unlink");
110		fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777);
111	}
112	if (fd < 0)
113		atf_tc_fail("shm_open");
114	if (ftruncate(fd, getpagesize()) < 0)
115		atf_tc_fail("ftruncate");
116
117	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
118	    0);
119	if (page == MAP_FAILED)
120		atf_tc_fail("mmap");
121
122	page[0] = '1';
123	if (munmap(page, getpagesize()) < 0)
124		atf_tc_fail("munmap");
125
126	return (fd);
127}
128
129ATF_TC_WITHOUT_HEAD(remap_object);
130ATF_TC_BODY(remap_object, tc)
131{
132	char *page;
133	int fd;
134
135	fd = scribble_object();
136
137	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
138	    0);
139	if (page == MAP_FAILED) {
140		atf_tc_fail("mmap(2)");
141		close(fd);
142		shm_unlink(test_path);
143		return;
144	}
145
146	if (page[0] != '1') {
147		atf_tc_fail("missing data");
148		close(fd);
149		shm_unlink(test_path);
150		return;
151	}
152
153	close(fd);
154	if (munmap(page, getpagesize()) < 0) {
155		atf_tc_fail("munmap");
156		shm_unlink(test_path);
157		return;
158	}
159
160	if (shm_unlink(test_path) < 0) {
161		atf_tc_fail("shm_unlink");
162		return;
163	}
164
165}
166
167ATF_TC_WITHOUT_HEAD(reopen_object);
168ATF_TC_BODY(reopen_object, tc)
169{
170	char *page;
171	int fd;
172
173	fd = scribble_object();
174	close(fd);
175
176	fd = shm_open(test_path, O_RDONLY, 0777);
177	if (fd < 0) {
178		atf_tc_fail("shm_open(2)");
179		shm_unlink(test_path);
180		return;
181	}
182	page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
183	if (page == MAP_FAILED) {
184		atf_tc_fail("mmap(2)");
185		close(fd);
186		shm_unlink(test_path);
187		return;
188	}
189
190	if (page[0] != '1') {
191		atf_tc_fail("missing data");
192		munmap(page, getpagesize());
193		close(fd);
194		shm_unlink(test_path);
195		return;
196	}
197
198	munmap(page, getpagesize());
199	close(fd);
200	shm_unlink(test_path);
201}
202
203ATF_TC_WITHOUT_HEAD(readonly_mmap_write);
204ATF_TC_BODY(readonly_mmap_write, tc)
205{
206	char *page;
207	int fd;
208
209	gen_test_path();
210
211	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
212	if (fd < 0) {
213		atf_tc_fail("shm_open");
214		return;
215	}
216
217	/* PROT_WRITE should fail with EACCES. */
218	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
219	    0);
220	if (page != MAP_FAILED) {
221		atf_tc_fail("mmap(PROT_WRITE) succeeded");
222		munmap(page, getpagesize());
223		close(fd);
224		shm_unlink(test_path);
225		return;
226	}
227	if (errno != EACCES) {
228		atf_tc_fail("mmap");
229		close(fd);
230		shm_unlink(test_path);
231		return;
232	}
233
234	close(fd);
235	shm_unlink(test_path);
236}
237
238ATF_TC_WITHOUT_HEAD(open_after_link);
239ATF_TC_BODY(open_after_link, tc)
240{
241	int fd;
242
243	gen_test_path();
244
245	fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
246	if (fd < 0) {
247		atf_tc_fail("shm_open(1)");
248		return;
249	}
250	close(fd);
251
252	if (shm_unlink(test_path) < 0) {
253		atf_tc_fail("shm_unlink");
254		return;
255	}
256
257	shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
258}
259
260ATF_TC_WITHOUT_HEAD(open_invalid_path);
261ATF_TC_BODY(open_invalid_path, tc)
262{
263
264	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
265}
266
267ATF_TC_WITHOUT_HEAD(open_write_only);
268ATF_TC_BODY(open_write_only, tc)
269{
270
271	gen_test_path();
272
273	shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
274}
275
276ATF_TC_WITHOUT_HEAD(open_extra_flags);
277ATF_TC_BODY(open_extra_flags, tc)
278{
279
280	gen_test_path();
281
282	shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
283}
284
285ATF_TC_WITHOUT_HEAD(open_anon);
286ATF_TC_BODY(open_anon, tc)
287{
288	int fd;
289
290	fd = shm_open(SHM_ANON, O_RDWR, 0777);
291	if (fd < 0) {
292		atf_tc_fail("shm_open");
293		return;
294	}
295	close(fd);
296}
297
298ATF_TC_WITHOUT_HEAD(open_anon_readonly);
299ATF_TC_BODY(open_anon_readonly, tc)
300{
301
302	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
303}
304
305ATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
306ATF_TC_BODY(open_bad_path_pointer, tc)
307{
308
309	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
310}
311
312ATF_TC_WITHOUT_HEAD(open_path_too_long);
313ATF_TC_BODY(open_path_too_long, tc)
314{
315	char *page;
316
317	page = malloc(MAXPATHLEN + 1);
318	memset(page, 'a', MAXPATHLEN);
319	page[MAXPATHLEN] = '\0';
320	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
321	free(page);
322}
323
324ATF_TC_WITHOUT_HEAD(open_nonexisting_object);
325ATF_TC_BODY(open_nonexisting_object, tc)
326{
327
328	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
329}
330
331ATF_TC_WITHOUT_HEAD(open_create_existing_object);
332ATF_TC_BODY(open_create_existing_object, tc)
333{
334	int fd;
335
336	gen_test_path();
337
338	fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
339	ATF_REQUIRE_MSG(fd != -1, "shm_open(O_CREAT) failed; errno=%d", errno);
340	close(fd);
341
342	shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
343	    0777, EEXIST);
344
345	shm_unlink("shm_object");
346}
347
348ATF_TC_WITHOUT_HEAD(trunc_resets_object);
349ATF_TC_BODY(trunc_resets_object, tc)
350{
351	struct stat sb;
352	int fd;
353
354	gen_test_path();
355
356	/* Create object and set size to 1024. */
357	fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
358	if (fd < 0) {
359		atf_tc_fail("shm_open(1)");
360		return;
361	}
362	if (ftruncate(fd, 1024) < 0) {
363		atf_tc_fail("ftruncate");
364		close(fd);
365		return;
366	}
367	if (fstat(fd, &sb) < 0) {
368		atf_tc_fail("fstat(1)");
369		close(fd);
370		return;
371	}
372	if (sb.st_size != 1024) {
373		atf_tc_fail("size %d != 1024", (int)sb.st_size);
374		close(fd);
375		return;
376	}
377	close(fd);
378
379	/* Open with O_TRUNC which should reset size to 0. */
380	fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
381	if (fd < 0) {
382		atf_tc_fail("shm_open(2)");
383		return;
384	}
385	if (fstat(fd, &sb) < 0) {
386		atf_tc_fail("fstat(2)");
387		close(fd);
388		return;
389	}
390	if (sb.st_size != 0) {
391		atf_tc_fail("size after O_TRUNC %d != 0", (int)sb.st_size);
392		close(fd);
393		return;
394	}
395	close(fd);
396	if (shm_unlink(test_path) < 0) {
397		atf_tc_fail("shm_unlink");
398		return;
399	}
400}
401
402ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
403ATF_TC_BODY(unlink_bad_path_pointer, tc)
404{
405
406	shm_unlink_should_fail((char *)1024, EFAULT);
407}
408
409ATF_TC_WITHOUT_HEAD(unlink_path_too_long);
410ATF_TC_BODY(unlink_path_too_long, tc)
411{
412	char *page;
413
414	page = malloc(MAXPATHLEN + 1);
415	memset(page, 'a', MAXPATHLEN);
416	page[MAXPATHLEN] = '\0';
417	shm_unlink_should_fail(page, ENAMETOOLONG);
418	free(page);
419}
420
421ATF_TC_WITHOUT_HEAD(object_resize);
422ATF_TC_BODY(object_resize, tc)
423{
424	pid_t pid;
425	struct stat sb;
426	char *page;
427	int fd, status;
428
429	/* Start off with a size of a single page. */
430	fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0777);
431	if (fd < 0) {
432		atf_tc_fail("shm_open");
433		return;
434	}
435	if (ftruncate(fd, getpagesize()) < 0) {
436		atf_tc_fail("ftruncate(1)");
437		close(fd);
438		return;
439	}
440	if (fstat(fd, &sb) < 0) {
441		atf_tc_fail("fstat(1)");
442		close(fd);
443		return;
444	}
445	if (sb.st_size != getpagesize()) {
446		atf_tc_fail("first resize failed");
447		close(fd);
448		return;
449	}
450
451	/* Write a '1' to the first byte. */
452	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
453	    0);
454	if (page == MAP_FAILED) {
455		atf_tc_fail("mmap(1)");
456		close(fd);
457		return;
458	}
459
460	page[0] = '1';
461
462	if (munmap(page, getpagesize()) < 0) {
463		atf_tc_fail("munmap(1)");
464		close(fd);
465		return;
466	}
467
468	/* Grow the object to 2 pages. */
469	if (ftruncate(fd, getpagesize() * 2) < 0) {
470		atf_tc_fail("ftruncate(2)");
471		close(fd);
472		return;
473	}
474	if (fstat(fd, &sb) < 0) {
475		atf_tc_fail("fstat(2)");
476		close(fd);
477		return;
478	}
479	if (sb.st_size != getpagesize() * 2) {
480		atf_tc_fail("second resize failed");
481		close(fd);
482		return;
483	}
484
485	/* Check for '1' at the first byte. */
486	page = mmap(0, getpagesize() * 2, PROT_READ | PROT_WRITE, MAP_SHARED,
487	    fd, 0);
488	if (page == MAP_FAILED) {
489		atf_tc_fail("mmap(2)");
490		close(fd);
491		return;
492	}
493
494	if (page[0] != '1') {
495		atf_tc_fail("missing data at 0");
496		close(fd);
497		return;
498	}
499
500	/* Write a '2' at the start of the second page. */
501	page[getpagesize()] = '2';
502
503	/* Shrink the object back to 1 page. */
504	if (ftruncate(fd, getpagesize()) < 0) {
505		atf_tc_fail("ftruncate(3)");
506		close(fd);
507		return;
508	}
509	if (fstat(fd, &sb) < 0) {
510		atf_tc_fail("fstat(3)");
511		close(fd);
512		return;
513	}
514	if (sb.st_size != getpagesize()) {
515		atf_tc_fail("third resize failed");
516		close(fd);
517		return;
518	}
519
520	/*
521	 * Fork a child process to make sure the second page is no
522	 * longer valid.
523	 */
524	pid = fork();
525	if (pid < 0) {
526		atf_tc_fail("fork");
527		close(fd);
528		return;
529	}
530
531	if (pid == 0) {
532		struct rlimit lim;
533		char c;
534
535		/* Don't generate a core dump. */
536		getrlimit(RLIMIT_CORE, &lim);
537		lim.rlim_cur = 0;
538		setrlimit(RLIMIT_CORE, &lim);
539
540		/*
541		 * The previous ftruncate(2) shrunk the backing object
542		 * so that this address is no longer valid, so reading
543		 * from it should trigger a SIGSEGV.
544		 */
545		c = page[getpagesize()];
546		fprintf(stderr, "child: page 1: '%c'\n", c);
547		exit(0);
548	}
549	if (wait(&status) < 0) {
550		atf_tc_fail("wait");
551		close(fd);
552		return;
553	}
554	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) {
555		atf_tc_fail("child terminated with status %x", status);
556		close(fd);
557		return;
558	}
559
560	/* Grow the object back to 2 pages. */
561	if (ftruncate(fd, getpagesize() * 2) < 0) {
562		atf_tc_fail("ftruncate(4)");
563		close(fd);
564		return;
565	}
566	if (fstat(fd, &sb) < 0) {
567		atf_tc_fail("fstat(4)");
568		close(fd);
569		return;
570	}
571	if (sb.st_size != getpagesize() * 2) {
572		atf_tc_fail("second resize failed");
573		close(fd);
574		return;
575	}
576
577	/*
578	 * Note that the mapping at 'page' for the second page is
579	 * still valid, and now that the shm object has been grown
580	 * back up to 2 pages, there is now memory backing this page
581	 * so the read will work.  However, the data should be zero
582	 * rather than '2' as the old data was thrown away when the
583	 * object was shrunk and the new pages when an object are
584	 * grown are zero-filled.
585	 */
586	if (page[getpagesize()] != 0) {
587		atf_tc_fail("invalid data at %d", getpagesize());
588		close(fd);
589		return;
590	}
591
592	close(fd);
593}
594
595/* Signal handler which does nothing. */
596static void
597ignoreit(int sig __unused)
598{
599	;
600}
601
602ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
603ATF_TC_BODY(shm_functionality_across_fork, tc)
604{
605	char *cp, c;
606	int error, desc, rv;
607	long scval;
608	sigset_t ss;
609	struct sigaction sa;
610	void *region;
611	size_t i, psize;
612
613#ifndef _POSIX_SHARED_MEMORY_OBJECTS
614	printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
615#else
616	printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
617	       (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
618	if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
619		printf("***Indicates this feature may be unsupported!\n");
620#endif
621	errno = 0;
622	scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
623	if (scval == -1 && errno != 0) {
624		atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
625		    "errno=%d", errno);
626	} else {
627		printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
628		       scval);
629		if (scval == -1)
630			printf("***Indicates this feature is unsupported!\n");
631	}
632
633	errno = 0;
634	scval = sysconf(_SC_PAGESIZE);
635	if (scval == -1 && errno != 0) {
636		atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
637	} else if (scval <= 0 || (size_t)psize != psize) {
638		fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
639		    scval);
640		psize = 4096;
641	} else {
642		printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
643		psize = scval;
644	}
645
646	gen_test_path();
647	desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
648
649	ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
650	ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
651	    "shm_unlink failed; errno=%d", errno);
652	ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
653	    "ftruncate failed; errno=%d", errno);
654
655	region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
656		      desc, (off_t)0);
657	ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
658	memset(region, '\377', psize);
659
660	sa.sa_flags = 0;
661	sa.sa_handler = ignoreit;
662	sigemptyset(&sa.sa_mask);
663	ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
664	    "sigaction failed; errno=%d", errno);
665
666	sigemptyset(&ss);
667	sigaddset(&ss, SIGUSR1);
668	ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
669	    "sigprocmask failed; errno=%d", errno);
670
671	rv = fork();
672	ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
673	if (rv == 0) {
674		sigemptyset(&ss);
675		sigsuspend(&ss);
676
677		for (cp = region; cp < (char *)region + psize; cp++) {
678			if (*cp != '\151')
679				_exit(1);
680		}
681		if (lseek(desc, 0, SEEK_SET) == -1)
682			_exit(1);
683		for (i = 0; i < psize; i++) {
684			error = read(desc, &c, 1);
685			if (c != '\151')
686				_exit(1);
687		}
688		_exit(0);
689	} else {
690		int status;
691
692		memset(region, '\151', psize - 2);
693		error = pwrite(desc, region, 2, psize - 2);
694		if (error != 2) {
695			if (error >= 0)
696				atf_tc_fail("short write; %d bytes written",
697				    error);
698			else
699				atf_tc_fail("shmfd write");
700		}
701		kill(rv, SIGUSR1);
702		waitpid(rv, &status, 0);
703
704		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
705			printf("Functionality test successful\n");
706		} else if (WIFEXITED(status)) {
707			atf_tc_fail("Child process exited with status %d",
708			    WEXITSTATUS(status));
709		} else {
710			atf_tc_fail("Child process terminated with %s",
711			    strsignal(WTERMSIG(status)));
712		}
713	}
714}
715
716ATF_TP_ADD_TCS(tp)
717{
718
719	ATF_TP_ADD_TC(tp, remap_object);
720	ATF_TP_ADD_TC(tp, reopen_object);
721	ATF_TP_ADD_TC(tp, readonly_mmap_write);
722	ATF_TP_ADD_TC(tp, open_after_link);
723	ATF_TP_ADD_TC(tp, open_invalid_path);
724	ATF_TP_ADD_TC(tp, open_write_only);
725	ATF_TP_ADD_TC(tp, open_extra_flags);
726	ATF_TP_ADD_TC(tp, open_anon);
727	ATF_TP_ADD_TC(tp, open_anon_readonly);
728	ATF_TP_ADD_TC(tp, open_bad_path_pointer);
729	ATF_TP_ADD_TC(tp, open_path_too_long);
730	ATF_TP_ADD_TC(tp, open_nonexisting_object);
731	ATF_TP_ADD_TC(tp, open_create_existing_object);
732	ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
733	ATF_TP_ADD_TC(tp, trunc_resets_object);
734	ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
735	ATF_TP_ADD_TC(tp, unlink_path_too_long);
736	ATF_TP_ADD_TC(tp, object_resize);
737
738	return (atf_no_error());
739}
740