2 * Copyright (c) 2006 Robert N. M. Watson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
32 #include <sys/resource.h>
34 #include <sys/syscall.h>
47 #define TEST_PATH_LEN 256
48 static char test_path[TEST_PATH_LEN];
53 char *tmpdir = getenv("TMPDIR");
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);
67 * Attempt a shm_open() that should fail with an expected error of 'error'.
70 shm_open_should_fail(const char *path, int flags, mode_t mode, int error)
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);
82 * Attempt a shm_unlink() that should fail with an expected error of 'error'.
85 shm_unlink_should_fail(const char *path, int error)
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);
95 * Open the test object and write '1' to the first byte. Returns valid fd
96 * on success and -1 on failure.
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);
113 atf_tc_fail("shm_open failed; errno=%d", errno);
114 if (ftruncate(fd, getpagesize()) < 0)
115 atf_tc_fail("ftruncate failed; errno=%d", errno);
117 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
119 if (page == MAP_FAILED)
120 atf_tc_fail("mmap failed; errno=%d", errno);
123 if (munmap(page, getpagesize()) < 0)
124 atf_tc_fail("munmap failed; errno=%d", errno);
129 ATF_TC_WITHOUT_HEAD(remap_object);
130 ATF_TC_BODY(remap_object, tc)
135 fd = scribble_object();
137 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
139 if (page == MAP_FAILED)
140 atf_tc_fail("mmap(2) failed; errno=%d", errno);
143 atf_tc_fail("missing data ('%c' != '1')", page[0]);
146 if (munmap(page, getpagesize()) < 0)
147 atf_tc_fail("munmap failed; errno=%d", errno);
149 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
150 "shm_unlink failed; errno=%d", errno);
153 ATF_TC_WITHOUT_HEAD(reopen_object);
154 ATF_TC_BODY(reopen_object, tc)
159 fd = scribble_object();
162 fd = shm_open(test_path, O_RDONLY, 0777);
164 atf_tc_fail("shm_open(2) failed; errno=%d", errno);
166 page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
167 if (page == MAP_FAILED)
168 atf_tc_fail("mmap(2) failed; errno=%d", errno);
171 atf_tc_fail("missing data ('%c' != '1')", page[0]);
173 munmap(page, getpagesize());
175 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
176 "shm_unlink failed; errno=%d", errno);
179 ATF_TC_WITHOUT_HEAD(readonly_mmap_write);
180 ATF_TC_BODY(readonly_mmap_write, tc)
187 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
188 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
190 /* PROT_WRITE should fail with EACCES. */
191 page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
193 if (page != MAP_FAILED)
194 atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
197 atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
201 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
202 "shm_unlink failed; errno=%d", errno);
205 ATF_TC_WITHOUT_HEAD(open_after_link);
206 ATF_TC_BODY(open_after_link, tc)
212 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
213 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
216 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
219 shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
222 ATF_TC_WITHOUT_HEAD(open_invalid_path);
223 ATF_TC_BODY(open_invalid_path, tc)
226 shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
229 ATF_TC_WITHOUT_HEAD(open_write_only);
230 ATF_TC_BODY(open_write_only, tc)
235 shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
238 ATF_TC_WITHOUT_HEAD(open_extra_flags);
239 ATF_TC_BODY(open_extra_flags, tc)
244 shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
247 ATF_TC_WITHOUT_HEAD(open_anon);
248 ATF_TC_BODY(open_anon, tc)
252 fd = shm_open(SHM_ANON, O_RDWR, 0777);
253 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
257 ATF_TC_WITHOUT_HEAD(open_anon_readonly);
258 ATF_TC_BODY(open_anon_readonly, tc)
261 shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
264 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
265 ATF_TC_BODY(open_bad_path_pointer, tc)
268 shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
271 ATF_TC_WITHOUT_HEAD(open_path_too_long);
272 ATF_TC_BODY(open_path_too_long, tc)
276 page = malloc(MAXPATHLEN + 1);
277 memset(page, 'a', MAXPATHLEN);
278 page[MAXPATHLEN] = '\0';
279 shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
283 ATF_TC_WITHOUT_HEAD(open_nonexisting_object);
284 ATF_TC_BODY(open_nonexisting_object, tc)
287 shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
290 ATF_TC_WITHOUT_HEAD(open_create_existing_object);
291 ATF_TC_BODY(open_create_existing_object, tc)
297 fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
298 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
301 shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
304 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
305 "shm_unlink failed; errno=%d", errno);
308 ATF_TC_WITHOUT_HEAD(trunc_resets_object);
309 ATF_TC_BODY(trunc_resets_object, tc)
316 /* Create object and set size to 1024. */
317 fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
318 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
319 ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
320 "ftruncate failed; errno=%d", errno);
321 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
322 "fstat(1) failed; errno=%d", errno);
323 ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
326 /* Open with O_TRUNC which should reset size to 0. */
327 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
328 ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
329 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
330 "fstat(2) failed; errno=%d", errno);
331 ATF_REQUIRE_MSG(sb.st_size == 0,
332 "size was not 0 after truncation: %d", (int)sb.st_size);
334 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
335 "shm_unlink failed; errno=%d", errno);
338 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
339 ATF_TC_BODY(unlink_bad_path_pointer, tc)
342 shm_unlink_should_fail((char *)1024, EFAULT);
345 ATF_TC_WITHOUT_HEAD(unlink_path_too_long);
346 ATF_TC_BODY(unlink_path_too_long, tc)
350 page = malloc(MAXPATHLEN + 1);
351 memset(page, 'a', MAXPATHLEN);
352 page[MAXPATHLEN] = '\0';
353 shm_unlink_should_fail(page, ENAMETOOLONG);
357 ATF_TC_WITHOUT_HEAD(object_resize);
358 ATF_TC_BODY(object_resize, tc)
362 char err_buf[1024], *page;
365 /* Start off with a size of a single page. */
366 fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
368 atf_tc_fail("shm_open failed; errno=%d", errno);
370 if (ftruncate(fd, getpagesize()) < 0)
371 atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
373 if (fstat(fd, &sb) < 0)
374 atf_tc_fail("fstat(1) failed; errno=%d", errno);
376 if (sb.st_size != getpagesize())
377 atf_tc_fail("first resize failed (%d != %d)",
378 (int)sb.st_size, getpagesize());
380 /* Write a '1' to the first byte. */
381 page = mmap(0, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd,
383 if (page == MAP_FAILED)
384 atf_tc_fail("mmap(1)");
388 if (munmap(page, getpagesize()) < 0)
389 atf_tc_fail("munmap(1) failed; errno=%d", errno);
391 /* Grow the object to 2 pages. */
392 if (ftruncate(fd, getpagesize() * 2) < 0)
393 atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
395 if (fstat(fd, &sb) < 0)
396 atf_tc_fail("fstat(2) failed; errno=%d", errno);
398 if (sb.st_size != getpagesize() * 2)
399 atf_tc_fail("second resize failed (%d != %d)",
400 (int)sb.st_size, getpagesize() * 2);
402 /* Check for '1' at the first byte. */
403 page = mmap(0, getpagesize() * 2, PROT_READ|PROT_WRITE, MAP_SHARED,
405 if (page == MAP_FAILED)
406 atf_tc_fail("mmap(2) failed; errno=%d", errno);
409 atf_tc_fail("'%c' != '1'", page[0]);
411 /* Write a '2' at the start of the second page. */
412 page[getpagesize()] = '2';
414 /* Shrink the object back to 1 page. */
415 if (ftruncate(fd, getpagesize()) < 0)
416 atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
418 if (fstat(fd, &sb) < 0)
419 atf_tc_fail("fstat(3) failed; errno=%d", errno);
421 if (sb.st_size != getpagesize())
422 atf_tc_fail("third resize failed (%d != %d)",
423 (int)sb.st_size, getpagesize());
426 * Fork a child process to make sure the second page is no
431 atf_tc_fail("fork failed; errno=%d", errno);
437 /* Don't generate a core dump. */
438 getrlimit(RLIMIT_CORE, &lim);
440 setrlimit(RLIMIT_CORE, &lim);
443 * The previous ftruncate(2) shrunk the backing object
444 * so that this address is no longer valid, so reading
445 * from it should trigger a SIGSEGV.
447 c = page[getpagesize()];
448 fprintf(stderr, "child: page 1: '%c'\n", c);
452 if (wait(&status) < 0)
453 atf_tc_fail("wait failed; errno=%d", errno);
455 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV)
456 atf_tc_fail("child terminated with status %x", status);
458 /* Grow the object back to 2 pages. */
459 if (ftruncate(fd, getpagesize() * 2) < 0)
460 atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
462 if (fstat(fd, &sb) < 0)
463 atf_tc_fail("fstat(2) failed; errno=%d", errno);
465 if (sb.st_size != getpagesize() * 2)
466 atf_tc_fail("fourth resize failed (%d != %d)",
467 (int)sb.st_size, getpagesize());
470 * Note that the mapping at 'page' for the second page is
471 * still valid, and now that the shm object has been grown
472 * back up to 2 pages, there is now memory backing this page
473 * so the read will work. However, the data should be zero
474 * rather than '2' as the old data was thrown away when the
475 * object was shrunk and the new pages when an object are
476 * grown are zero-filled.
478 if (page[getpagesize()] != 0)
479 atf_tc_fail("invalid data at %d: %x != 0",
480 getpagesize(), (int)page[getpagesize()]);
485 /* Signal handler which does nothing. */
487 ignoreit(int sig __unused)
492 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
493 ATF_TC_BODY(shm_functionality_across_fork, tc)
503 #ifndef _POSIX_SHARED_MEMORY_OBJECTS
504 printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
506 printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
507 (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
508 if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
509 printf("***Indicates this feature may be unsupported!\n");
512 scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
513 if (scval == -1 && errno != 0) {
514 atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
517 printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
520 printf("***Indicates this feature is unsupported!\n");
524 scval = sysconf(_SC_PAGESIZE);
525 if (scval == -1 && errno != 0) {
526 atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
527 } else if (scval <= 0 || (size_t)psize != psize) {
528 fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
532 printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
537 desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
539 ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
540 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
541 "shm_unlink failed; errno=%d", errno);
542 ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
543 "ftruncate failed; errno=%d", errno);
545 region = mmap((void *)0, psize, PROT_READ | PROT_WRITE, MAP_SHARED,
547 ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
548 memset(region, '\377', psize);
551 sa.sa_handler = ignoreit;
552 sigemptyset(&sa.sa_mask);
553 ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
554 "sigaction failed; errno=%d", errno);
557 sigaddset(&ss, SIGUSR1);
558 ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
559 "sigprocmask failed; errno=%d", errno);
562 ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
567 for (cp = region; cp < (char *)region + psize; cp++) {
571 if (lseek(desc, 0, SEEK_SET) == -1)
573 for (i = 0; i < psize; i++) {
574 error = read(desc, &c, 1);
582 memset(region, '\151', psize - 2);
583 error = pwrite(desc, region, 2, psize - 2);
586 atf_tc_fail("short write; %d bytes written",
589 atf_tc_fail("shmfd write");
592 waitpid(rv, &status, 0);
594 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
595 printf("Functionality test successful\n");
596 } else if (WIFEXITED(status)) {
597 atf_tc_fail("Child process exited with status %d",
598 WEXITSTATUS(status));
600 atf_tc_fail("Child process terminated with %s",
601 strsignal(WTERMSIG(status)));
609 ATF_TP_ADD_TC(tp, remap_object);
610 ATF_TP_ADD_TC(tp, reopen_object);
611 ATF_TP_ADD_TC(tp, readonly_mmap_write);
612 ATF_TP_ADD_TC(tp, open_after_link);
613 ATF_TP_ADD_TC(tp, open_invalid_path);
614 ATF_TP_ADD_TC(tp, open_write_only);
615 ATF_TP_ADD_TC(tp, open_extra_flags);
616 ATF_TP_ADD_TC(tp, open_anon);
617 ATF_TP_ADD_TC(tp, open_anon_readonly);
618 ATF_TP_ADD_TC(tp, open_bad_path_pointer);
619 ATF_TP_ADD_TC(tp, open_path_too_long);
620 ATF_TP_ADD_TC(tp, open_nonexisting_object);
621 ATF_TP_ADD_TC(tp, open_create_existing_object);
622 ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
623 ATF_TP_ADD_TC(tp, trunc_resets_object);
624 ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
625 ATF_TP_ADD_TC(tp, unlink_path_too_long);
626 ATF_TP_ADD_TC(tp, object_resize);
628 return (atf_no_error());