1175383Sjhb/*-
2175383Sjhb * Copyright (c) 2006 Robert N. M. Watson
3175383Sjhb * All rights reserved.
4175383Sjhb *
5175383Sjhb * Redistribution and use in source and binary forms, with or without
6175383Sjhb * modification, are permitted provided that the following conditions
7175383Sjhb * are met:
8175383Sjhb * 1. Redistributions of source code must retain the above copyright
9175383Sjhb *    notice, this list of conditions and the following disclaimer.
10175383Sjhb * 2. Redistributions in binary form must reproduce the above copyright
11175383Sjhb *    notice, this list of conditions and the following disclaimer in the
12175383Sjhb *    documentation and/or other materials provided with the distribution.
13175383Sjhb *
14175383Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15175383Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16175383Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17175383Sjhb * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18175383Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19175383Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20175383Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21175383Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22175383Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23175383Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24175383Sjhb * SUCH DAMAGE.
25175383Sjhb */
26175383Sjhb
27175383Sjhb#include <sys/cdefs.h>
28175383Sjhb__FBSDID("$FreeBSD$");
29175383Sjhb
30175383Sjhb#include <sys/param.h>
31175383Sjhb#include <sys/mman.h>
32175383Sjhb#include <sys/resource.h>
33175383Sjhb#include <sys/stat.h>
34175383Sjhb#include <sys/syscall.h>
35175383Sjhb#include <sys/wait.h>
36175383Sjhb
37175383Sjhb#include <errno.h>
38175383Sjhb#include <fcntl.h>
39175383Sjhb#include <stdio.h>
40175383Sjhb#include <stdlib.h>
41175383Sjhb#include <string.h>
42175383Sjhb#include <unistd.h>
43175383Sjhb
44175383Sjhb#include "test.h"
45175383Sjhb
46175383Sjhb#define	TEST_PATH	"/tmp/posixshm_regression_test"
47175383Sjhb
48175383Sjhb/*
49175383Sjhb * Attempt a shm_open() that should fail with an expected error of 'error'.
50175383Sjhb */
51175383Sjhbstatic void
52175383Sjhbshm_open_should_fail(const char *path, int flags, mode_t mode, int error)
53175383Sjhb{
54175383Sjhb	int fd;
55175383Sjhb
56175383Sjhb	fd = shm_open(path, flags, mode);
57175383Sjhb	if (fd >= 0) {
58175383Sjhb		fail_err("shm_open() didn't fail");
59175383Sjhb		close(fd);
60175383Sjhb		return;
61175383Sjhb	}
62175383Sjhb	if (errno != error) {
63175383Sjhb		fail_errno("shm_open");
64175383Sjhb		return;
65175383Sjhb	}
66175383Sjhb	pass();
67175383Sjhb}
68175383Sjhb
69175383Sjhb/*
70175383Sjhb * Attempt a shm_unlink() that should fail with an expected error of 'error'.
71175383Sjhb */
72175383Sjhbstatic void
73175383Sjhbshm_unlink_should_fail(const char *path, int error)
74175383Sjhb{
75175383Sjhb
76175383Sjhb	if (shm_unlink(path) >= 0) {
77175383Sjhb		fail_err("shm_unlink() didn't fail");
78175383Sjhb		return;
79175383Sjhb	}
80175383Sjhb	if (errno != error) {
81175383Sjhb		fail_errno("shm_unlink");
82175383Sjhb		return;
83175383Sjhb	}
84175383Sjhb	pass();
85175383Sjhb}
86175383Sjhb
87175383Sjhb/*
88175383Sjhb * Open the test object and write '1' to the first byte.  Returns valid fd
89175383Sjhb * on success and -1 on failure.
90175383Sjhb */
91175383Sjhbstatic int
92175383Sjhbscribble_object(void)
93175383Sjhb{
94175383Sjhb	char *page;
95175383Sjhb	int fd;
96175383Sjhb
97175383Sjhb	fd = shm_open(TEST_PATH, O_CREAT | O_EXCL | O_RDWR, 0777);
98175383Sjhb	if (fd < 0 && errno == EEXIST) {
99175383Sjhb		if (shm_unlink(TEST_PATH) < 0) {
100175383Sjhb			fail_errno("shm_unlink");
101175383Sjhb			return (-1);
102175383Sjhb		}
103175383Sjhb		fd = shm_open(TEST_PATH, O_CREAT | O_EXCL | O_RDWR, 0777);
104175383Sjhb	}
105175383Sjhb	if (fd < 0) {
106175383Sjhb		fail_errno("shm_open");
107175383Sjhb		return (-1);
108175383Sjhb	}
109175383Sjhb	if (ftruncate(fd, getpagesize()) < 0) {
110175383Sjhb		fail_errno("ftruncate");
111175383Sjhb		close(fd);
112175383Sjhb		shm_unlink(TEST_PATH);
113175383Sjhb		return (-1);
114175383Sjhb	}
115175383Sjhb
116175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
117175383Sjhb	    0);
118175383Sjhb	if (page == MAP_FAILED) {
119175383Sjhb		fail_errno("mmap");
120175383Sjhb		close(fd);
121175383Sjhb		shm_unlink(TEST_PATH);
122175383Sjhb		return (-1);
123175383Sjhb	}
124175383Sjhb
125175383Sjhb	page[0] = '1';
126175383Sjhb
127175383Sjhb	if (munmap(page, getpagesize()) < 0) {
128175383Sjhb		fail_errno("munmap");
129175383Sjhb		close(fd);
130175383Sjhb		shm_unlink(TEST_PATH);
131175383Sjhb		return (-1);
132175383Sjhb	}
133175383Sjhb
134175383Sjhb	return (fd);
135175383Sjhb}
136175383Sjhb
137175383Sjhbstatic void
138175383Sjhbremap_object(void)
139175383Sjhb{
140175383Sjhb	char *page;
141175383Sjhb	int fd;
142175383Sjhb
143175383Sjhb	fd = scribble_object();
144175383Sjhb	if (fd < 0)
145175383Sjhb		return;
146175383Sjhb
147175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
148175383Sjhb	    0);
149175383Sjhb	if (page == MAP_FAILED) {
150175383Sjhb		fail_errno("mmap(2)");
151175383Sjhb		close(fd);
152175383Sjhb		shm_unlink(TEST_PATH);
153175383Sjhb		return;
154175383Sjhb	}
155175383Sjhb
156175383Sjhb	if (page[0] != '1') {
157175383Sjhb		fail_err("missing data");
158175383Sjhb		close(fd);
159175383Sjhb		shm_unlink(TEST_PATH);
160175383Sjhb		return;
161175383Sjhb	}
162175383Sjhb
163175383Sjhb	close(fd);
164175383Sjhb	if (munmap(page, getpagesize()) < 0) {
165175383Sjhb		fail_errno("munmap");
166175383Sjhb		shm_unlink(TEST_PATH);
167175383Sjhb		return;
168175383Sjhb	}
169175383Sjhb
170175383Sjhb	if (shm_unlink(TEST_PATH) < 0) {
171175383Sjhb		fail_errno("shm_unlink");
172175383Sjhb		return;
173175383Sjhb	}
174175383Sjhb
175175383Sjhb	pass();
176175383Sjhb}
177175383SjhbTEST(remap_object, "remap object");
178175383Sjhb
179175383Sjhbstatic void
180175383Sjhbreopen_object(void)
181175383Sjhb{
182175383Sjhb	char *page;
183175383Sjhb	int fd;
184175383Sjhb
185175383Sjhb	fd = scribble_object();
186175383Sjhb	if (fd < 0)
187175383Sjhb		return;
188175383Sjhb	close(fd);
189175383Sjhb
190175383Sjhb	fd = shm_open(TEST_PATH, O_RDONLY, 0777);
191175383Sjhb	if (fd < 0) {
192175383Sjhb		fail_errno("shm_open(2)");
193175383Sjhb		shm_unlink(TEST_PATH);
194175383Sjhb		return;
195175383Sjhb	}
196175383Sjhb	page = mmap(0, getpagesize(), PROT_READ, MAP_SHARED, fd, 0);
197175383Sjhb	if (page == MAP_FAILED) {
198175383Sjhb		fail_errno("mmap(2)");
199175383Sjhb		close(fd);
200175383Sjhb		shm_unlink(TEST_PATH);
201175383Sjhb		return;
202175383Sjhb	}
203175383Sjhb
204175383Sjhb	if (page[0] != '1') {
205175383Sjhb		fail_err("missing data");
206175383Sjhb		munmap(page, getpagesize());
207175383Sjhb		close(fd);
208175383Sjhb		shm_unlink(TEST_PATH);
209175383Sjhb		return;
210175383Sjhb	}
211175383Sjhb
212175383Sjhb	munmap(page, getpagesize());
213175383Sjhb	close(fd);
214175383Sjhb	shm_unlink(TEST_PATH);
215175383Sjhb	pass();
216175383Sjhb}
217175383SjhbTEST(reopen_object, "reopen object");
218175383Sjhb
219175383Sjhbstatic void
220175383Sjhbreadonly_mmap_write(void)
221175383Sjhb{
222175383Sjhb	char *page;
223175383Sjhb	int fd;
224175383Sjhb
225175383Sjhb	fd = shm_open(TEST_PATH, O_RDONLY | O_CREAT, 0777);
226175383Sjhb	if (fd < 0) {
227175383Sjhb		fail_errno("shm_open");
228175383Sjhb		return;
229175383Sjhb	}
230175383Sjhb
231175383Sjhb	/* PROT_WRITE should fail with EACCES. */
232175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
233175383Sjhb	    0);
234175383Sjhb	if (page != MAP_FAILED) {
235175383Sjhb		fail_err("mmap(PROT_WRITE) succeeded");
236175383Sjhb		munmap(page, getpagesize());
237175383Sjhb		close(fd);
238175383Sjhb		shm_unlink(TEST_PATH);
239175383Sjhb		return;
240175383Sjhb	}
241175383Sjhb	if (errno != EACCES) {
242175383Sjhb		fail_errno("mmap");
243175383Sjhb		close(fd);
244175383Sjhb		shm_unlink(TEST_PATH);
245175383Sjhb		return;
246175383Sjhb	}
247175383Sjhb
248175383Sjhb	close(fd);
249175383Sjhb	shm_unlink(TEST_PATH);
250175383Sjhb	pass();
251175383Sjhb}
252175383SjhbTEST(readonly_mmap_write, "RDONLY object");
253175383Sjhb
254175383Sjhbstatic void
255175383Sjhbopen_after_unlink(void)
256175383Sjhb{
257175383Sjhb	int fd;
258175383Sjhb
259175383Sjhb	fd = shm_open(TEST_PATH, O_RDONLY | O_CREAT, 0777);
260175383Sjhb	if (fd < 0) {
261175383Sjhb		fail_errno("shm_open(1)");
262175383Sjhb		return;
263175383Sjhb	}
264175383Sjhb	close(fd);
265175383Sjhb
266175383Sjhb	if (shm_unlink(TEST_PATH) < 0) {
267175383Sjhb		fail_errno("shm_unlink");
268175383Sjhb		return;
269175383Sjhb	}
270175383Sjhb
271175383Sjhb	shm_open_should_fail(TEST_PATH, O_RDONLY, 0777, ENOENT);
272175383Sjhb}
273175383SjhbTEST(open_after_unlink, "open after unlink");
274175383Sjhb
275175383Sjhbstatic void
276175383Sjhbopen_invalid_path(void)
277175383Sjhb{
278175383Sjhb
279175383Sjhb	shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
280175383Sjhb}
281175383SjhbTEST(open_invalid_path, "open invalid path");
282175383Sjhb
283175383Sjhbstatic void
284175383Sjhbopen_write_only(void)
285175383Sjhb{
286175383Sjhb
287175383Sjhb	shm_open_should_fail(TEST_PATH, O_WRONLY, 0777, EINVAL);
288175383Sjhb}
289175383SjhbTEST(open_write_only, "open with O_WRONLY");
290175383Sjhb
291175383Sjhbstatic void
292175383Sjhbopen_extra_flags(void)
293175383Sjhb{
294175383Sjhb
295175383Sjhb	shm_open_should_fail(TEST_PATH, O_RDONLY | O_DIRECT, 0777, EINVAL);
296175383Sjhb}
297175383SjhbTEST(open_extra_flags, "open with extra flags");
298175383Sjhb
299175383Sjhbstatic void
300175383Sjhbopen_anon(void)
301175383Sjhb{
302175383Sjhb	int fd;
303175383Sjhb
304175383Sjhb	fd = shm_open(SHM_ANON, O_RDWR, 0777);
305175383Sjhb	if (fd < 0) {
306175383Sjhb		fail_errno("shm_open");
307175383Sjhb		return;
308175383Sjhb	}
309175383Sjhb	close(fd);
310175383Sjhb	pass();
311175383Sjhb}
312175383SjhbTEST(open_anon, "open anonymous object");
313175383Sjhb
314175383Sjhbstatic void
315175383Sjhbopen_anon_readonly(void)
316175383Sjhb{
317175383Sjhb
318175383Sjhb	shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
319175383Sjhb}
320175383SjhbTEST(open_anon_readonly, "open SHM_ANON with O_RDONLY");
321175383Sjhb
322175383Sjhbstatic void
323175383Sjhbopen_bad_path_pointer(void)
324175383Sjhb{
325175383Sjhb
326175383Sjhb	shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
327175383Sjhb}
328175383SjhbTEST(open_bad_path_pointer, "open bad path pointer");
329175383Sjhb
330175383Sjhbstatic void
331175383Sjhbopen_path_too_long(void)
332175383Sjhb{
333175383Sjhb	char *page;
334175383Sjhb
335175383Sjhb	page = malloc(MAXPATHLEN + 1);
336175383Sjhb	memset(page, 'a', MAXPATHLEN);
337175383Sjhb	page[MAXPATHLEN] = '\0';
338175383Sjhb	shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
339175383Sjhb	free(page);
340175383Sjhb}
341175383SjhbTEST(open_path_too_long, "open pathname too long");
342175383Sjhb
343175383Sjhbstatic void
344175383Sjhbopen_nonexisting_object(void)
345175383Sjhb{
346175383Sjhb
347175383Sjhb	shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
348175383Sjhb}
349175383SjhbTEST(open_nonexisting_object, "open nonexistent object");
350175383Sjhb
351175383Sjhbstatic void
352175383Sjhbexclusive_create_existing_object(void)
353175383Sjhb{
354175383Sjhb	int fd;
355175383Sjhb
356175383Sjhb	fd = shm_open("/tmp/notreallythere", O_RDONLY | O_CREAT, 0777);
357175383Sjhb	if (fd < 0) {
358175383Sjhb		fail_errno("shm_open(O_CREAT)");
359175383Sjhb		return;
360175383Sjhb	}
361175383Sjhb	close(fd);
362175383Sjhb
363175383Sjhb	shm_open_should_fail("/tmp/notreallythere", O_RDONLY | O_CREAT | O_EXCL,
364175383Sjhb	    0777, EEXIST);
365175383Sjhb
366175383Sjhb	shm_unlink("/tmp/notreallythere");
367175383Sjhb}
368175383SjhbTEST(exclusive_create_existing_object, "O_EXCL of existing object");
369175383Sjhb
370175383Sjhbstatic void
371175383Sjhbtrunc_resets_object(void)
372175383Sjhb{
373175383Sjhb	struct stat sb;
374175383Sjhb	int fd;
375175383Sjhb
376175383Sjhb	/* Create object and set size to 1024. */
377175383Sjhb	fd = shm_open(TEST_PATH, O_RDWR | O_CREAT, 0777);
378175383Sjhb	if (fd < 0) {
379175383Sjhb		fail_errno("shm_open(1)");
380175383Sjhb		return;
381175383Sjhb	}
382175383Sjhb	if (ftruncate(fd, 1024) < 0) {
383175383Sjhb		fail_errno("ftruncate");
384175383Sjhb		close(fd);
385175383Sjhb		return;
386175383Sjhb	}
387175383Sjhb	if (fstat(fd, &sb) < 0) {
388175383Sjhb		fail_errno("fstat(1)");
389175383Sjhb		close(fd);
390175383Sjhb		return;
391175383Sjhb	}
392175383Sjhb	if (sb.st_size != 1024) {
393175383Sjhb		fail_err("size %d != 1024", (int)sb.st_size);
394175383Sjhb		close(fd);
395175383Sjhb		return;
396175383Sjhb	}
397175383Sjhb	close(fd);
398175383Sjhb
399175383Sjhb	/* Open with O_TRUNC which should reset size to 0. */
400175383Sjhb	fd = shm_open(TEST_PATH, O_RDWR | O_TRUNC, 0777);
401175383Sjhb	if (fd < 0) {
402175383Sjhb		fail_errno("shm_open(2)");
403175383Sjhb		return;
404175383Sjhb	}
405175383Sjhb	if (fstat(fd, &sb) < 0) {
406175383Sjhb		fail_errno("fstat(2)");
407175383Sjhb		close(fd);
408175383Sjhb		return;
409175383Sjhb	}
410175383Sjhb	if (sb.st_size != 0) {
411175383Sjhb		fail_err("size after O_TRUNC %d != 0", (int)sb.st_size);
412175383Sjhb		close(fd);
413175383Sjhb		return;
414175383Sjhb	}
415175383Sjhb	close(fd);
416175383Sjhb	if (shm_unlink(TEST_PATH) < 0) {
417175383Sjhb		fail_errno("shm_unlink");
418175383Sjhb		return;
419175383Sjhb	}
420175383Sjhb	pass();
421175383Sjhb}
422175383SjhbTEST(trunc_resets_object, "O_TRUNC resets size");
423175383Sjhb
424175383Sjhbstatic void
425175383Sjhbunlink_bad_path_pointer(void)
426175383Sjhb{
427175383Sjhb
428175383Sjhb	shm_unlink_should_fail((char *)1024, EFAULT);
429175383Sjhb}
430175383SjhbTEST(unlink_bad_path_pointer, "unlink bad path pointer");
431175383Sjhb
432175383Sjhbstatic void
433175383Sjhbunlink_path_too_long(void)
434175383Sjhb{
435175383Sjhb	char *page;
436175383Sjhb
437175383Sjhb	page = malloc(MAXPATHLEN + 1);
438175383Sjhb	memset(page, 'a', MAXPATHLEN);
439175383Sjhb	page[MAXPATHLEN] = '\0';
440175383Sjhb	shm_unlink_should_fail(page, ENAMETOOLONG);
441175383Sjhb	free(page);
442175383Sjhb}
443175383SjhbTEST(unlink_path_too_long, "unlink pathname too long");
444175383Sjhb
445175383Sjhbstatic void
446175383Sjhbtest_object_resize(void)
447175383Sjhb{
448175383Sjhb	pid_t pid;
449175383Sjhb	struct stat sb;
450175383Sjhb	char *page;
451175383Sjhb	int fd, status;
452175383Sjhb
453175383Sjhb	/* Start off with a size of a single page. */
454175383Sjhb	fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0777);
455175383Sjhb	if (fd < 0) {
456175383Sjhb		fail_errno("shm_open");
457175383Sjhb		return;
458175383Sjhb	}
459175383Sjhb	if (ftruncate(fd, getpagesize()) < 0) {
460175383Sjhb		fail_errno("ftruncate(1)");
461175383Sjhb		close(fd);
462175383Sjhb		return;
463175383Sjhb	}
464175383Sjhb	if (fstat(fd, &sb) < 0) {
465175383Sjhb		fail_errno("fstat(1)");
466175383Sjhb		close(fd);
467175383Sjhb		return;
468175383Sjhb	}
469175383Sjhb	if (sb.st_size != getpagesize()) {
470175383Sjhb		fail_err("first resize failed");
471175383Sjhb		close(fd);
472175383Sjhb		return;
473175383Sjhb	}
474175383Sjhb
475175383Sjhb	/* Write a '1' to the first byte. */
476175383Sjhb	page = mmap(0, getpagesize(), PROT_READ | PROT_WRITE, MAP_SHARED, fd,
477175383Sjhb	    0);
478175383Sjhb	if (page == MAP_FAILED) {
479175383Sjhb		fail_errno("mmap(1)");
480175383Sjhb		close(fd);
481175383Sjhb		return;
482175383Sjhb	}
483175383Sjhb
484175383Sjhb	page[0] = '1';
485175383Sjhb
486175383Sjhb	if (munmap(page, getpagesize()) < 0) {
487175383Sjhb		fail_errno("munmap(1)");
488175383Sjhb		close(fd);
489175383Sjhb		return;
490175383Sjhb	}
491175383Sjhb
492175383Sjhb	/* Grow the object to 2 pages. */
493175383Sjhb	if (ftruncate(fd, getpagesize() * 2) < 0) {
494175383Sjhb		fail_errno("ftruncate(2)");
495175383Sjhb		close(fd);
496175383Sjhb		return;
497175383Sjhb	}
498175383Sjhb	if (fstat(fd, &sb) < 0) {
499175383Sjhb		fail_errno("fstat(2)");
500175383Sjhb		close(fd);
501175383Sjhb		return;
502175383Sjhb	}
503175383Sjhb	if (sb.st_size != getpagesize() * 2) {
504175383Sjhb		fail_err("second resize failed");
505175383Sjhb		close(fd);
506175383Sjhb		return;
507175383Sjhb	}
508175383Sjhb
509175383Sjhb	/* Check for '1' at the first byte. */
510175383Sjhb	page = mmap(0, getpagesize() * 2, PROT_READ | PROT_WRITE, MAP_SHARED,
511175383Sjhb	    fd, 0);
512175383Sjhb	if (page == MAP_FAILED) {
513175383Sjhb		fail_errno("mmap(2)");
514175383Sjhb		close(fd);
515175383Sjhb		return;
516175383Sjhb	}
517175383Sjhb
518175383Sjhb	if (page[0] != '1') {
519175383Sjhb		fail_err("missing data at 0");
520175383Sjhb		close(fd);
521175383Sjhb		return;
522175383Sjhb	}
523175383Sjhb
524175383Sjhb	/* Write a '2' at the start of the second page. */
525175383Sjhb	page[getpagesize()] = '2';
526175383Sjhb
527175383Sjhb	/* Shrink the object back to 1 page. */
528175383Sjhb	if (ftruncate(fd, getpagesize()) < 0) {
529175383Sjhb		fail_errno("ftruncate(3)");
530175383Sjhb		close(fd);
531175383Sjhb		return;
532175383Sjhb	}
533175383Sjhb	if (fstat(fd, &sb) < 0) {
534175383Sjhb		fail_errno("fstat(3)");
535175383Sjhb		close(fd);
536175383Sjhb		return;
537175383Sjhb	}
538175383Sjhb	if (sb.st_size != getpagesize()) {
539175383Sjhb		fail_err("third resize failed");
540175383Sjhb		close(fd);
541175383Sjhb		return;
542175383Sjhb	}
543175383Sjhb
544175383Sjhb	/*
545175383Sjhb	 * Fork a child process to make sure the second page is no
546175383Sjhb	 * longer valid.
547175383Sjhb	 */
548175383Sjhb	pid = fork();
549175383Sjhb	if (pid < 0) {
550175383Sjhb		fail_errno("fork");
551175383Sjhb		close(fd);
552175383Sjhb		return;
553175383Sjhb	}
554175383Sjhb
555175383Sjhb	if (pid == 0) {
556175383Sjhb		struct rlimit lim;
557175383Sjhb		char c;
558175383Sjhb
559175383Sjhb		/* Don't generate a core dump. */
560175383Sjhb		getrlimit(RLIMIT_CORE, &lim);
561175383Sjhb		lim.rlim_cur = 0;
562175383Sjhb		setrlimit(RLIMIT_CORE, &lim);
563175383Sjhb
564175383Sjhb		/*
565175383Sjhb		 * The previous ftruncate(2) shrunk the backing object
566175383Sjhb		 * so that this address is no longer valid, so reading
567175383Sjhb		 * from it should trigger a SIGSEGV.
568175383Sjhb		 */
569175383Sjhb		c = page[getpagesize()];
570175383Sjhb		fprintf(stderr, "child: page 1: '%c'\n", c);
571175383Sjhb		exit(0);
572175383Sjhb	}
573175383Sjhb	if (wait(&status) < 0) {
574175383Sjhb		fail_errno("wait");
575175383Sjhb		close(fd);
576175383Sjhb		return;
577175383Sjhb	}
578175383Sjhb	if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGSEGV) {
579175383Sjhb		fail_err("child terminated with status %x", status);
580175383Sjhb		close(fd);
581175383Sjhb		return;
582175383Sjhb	}
583175383Sjhb
584175383Sjhb	/* Grow the object back to 2 pages. */
585175383Sjhb	if (ftruncate(fd, getpagesize() * 2) < 0) {
586175383Sjhb		fail_errno("ftruncate(4)");
587175383Sjhb		close(fd);
588175383Sjhb		return;
589175383Sjhb	}
590175383Sjhb	if (fstat(fd, &sb) < 0) {
591175383Sjhb		fail_errno("fstat(4)");
592175383Sjhb		close(fd);
593175383Sjhb		return;
594175383Sjhb	}
595175383Sjhb	if (sb.st_size != getpagesize() * 2) {
596175383Sjhb		fail_err("second resize failed");
597175383Sjhb		close(fd);
598175383Sjhb		return;
599175383Sjhb	}
600175383Sjhb
601175383Sjhb	/*
602175383Sjhb	 * Note that the mapping at 'page' for the second page is
603175383Sjhb	 * still valid, and now that the shm object has been grown
604175383Sjhb	 * back up to 2 pages, there is now memory backing this page
605175383Sjhb	 * so the read will work.  However, the data should be zero
606175383Sjhb	 * rather than '2' as the old data was thrown away when the
607175383Sjhb	 * object was shrunk and the new pages when an object are
608175383Sjhb	 * grown are zero-filled.
609175383Sjhb	 */
610175383Sjhb	if (page[getpagesize()] != 0) {
611175383Sjhb		fail_err("invalid data at %d", getpagesize());
612175383Sjhb		close(fd);
613175383Sjhb		return;
614175383Sjhb	}
615175383Sjhb
616175383Sjhb	close(fd);
617175383Sjhb	pass();
618175383Sjhb}
619175383SjhbTEST(test_object_resize, "object resize");
620175383Sjhb
621175383Sjhbint
622175383Sjhbmain(int argc, char *argv[])
623175383Sjhb{
624175383Sjhb
625175383Sjhb	run_tests();
626175383Sjhb	return (0);
627175383Sjhb}
628