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