Esempio n. 1
0
static ssize_t NaClDescIoDescWrite(struct NaClDesc         *vself,
                                   void const              *buf,
                                   size_t                  len) {
  struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;

  return NaClHostDescWrite(self->hd, buf, len);
}
/*
 * Write out kNumFileBytes (a multiple of 64K) bytes of data.
 */
int CreateTestData(struct NaClHostDesc *d) {
  size_t nbytes;
  size_t written = 0;
  ssize_t result;
  static char buffer[4096];

  memset(buffer, 0, sizeof buffer);
  while (written < kNumFileBytes) {
    nbytes = kNumFileBytes - written;
    if (nbytes > sizeof buffer) {
      nbytes = sizeof buffer;
    }
    result = NaClHostDescWrite(d, buffer, nbytes);
    if (result < 0) {
      return (int) result;
    }
    written += result;
  }
  return 0;
}
int SeekPastEndAndWriteTest(struct NaClHostDesc *test_file,
                            struct NaClHostDesc *ro_view,
                            void const *test_params) {
  nacl_host_stat_t stbuf;
  nacl_off64_t new_size;
  ssize_t io_err;
  int err;
  nacl_off64_t seek_result;

  UNREFERENCED_PARAMETER(test_params);
  err = NaClHostDescFstat(test_file, &stbuf);
  if (0 != err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: fstat failed\n");
    return 0;
  }
  new_size = stbuf.st_size + (2 << 16);
  seek_result = NaClHostDescSeek(test_file, new_size, 0);
  if (seek_result != new_size) {
    fprintf(stderr, "SeekPastEndAndWriteTest: seek failed\n");
    return 0;
  }
  io_err = NaClHostDescWrite(test_file, "1", 1);
  if (1 != io_err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: write failed: %"NACL_PRIdS"\n",
            io_err);
  }
  err = NaClHostDescFstat(test_file, &stbuf);
  if (0 != err) {
    fprintf(stderr, "SeekPastEndAndWriteTest: post-write fstat failed\n");
    return 0;
  }
  ASSERT_EQ(stbuf.st_size, new_size + 1);
  err = NaClHostDescFstat(ro_view, &stbuf);
  if (0 != err) {
    fprintf(stderr,
            "SeekPastEndAndWriteTest: post-write ro_view fstat failed\n");
    return 0;
  }
  ASSERT_EQ(stbuf.st_size, new_size + 1);
  return 1;
}
/*
 * Write to |d| |file_bytes| of data from |buffer|, which contains
 * |buffer_size| bytes.  The contents of buffer will be repeated as
 * needed so that the target |file_bytes| is reached.
 */
int WriteData(struct NaClHostDesc *d,
              size_t file_bytes,
              char const *buffer,
              size_t buffer_size) {
  size_t nbytes;
  size_t written = 0;
  ssize_t result;

  while (written < file_bytes) {
    nbytes = file_bytes - written;
    if (nbytes > buffer_size) {
      nbytes = buffer_size;
    }
    result = NaClHostDescWrite(d, buffer, nbytes);
    if (result < 0) {
      return (int) result;
    }
    written += result;
  }
  return 0;
}
void CreateTestFile(struct NaClHostDesc *d_out,
                    char const *pathname,
                    struct TestParams *param) {
  struct NaClHostDesc hd;
  int err;
  nacl_off64_t off;
  size_t desired_write;
  ssize_t bytes_written;

  printf("pathname = %s, perms 0%o\n", pathname, param->file_perms);
  if (0 != (err = NaClHostDescOpen(&hd,
                                   pathname,
                                   NACL_ABI_O_WRONLY |
                                   NACL_ABI_O_CREAT |
                                   NACL_ABI_O_TRUNC,
                                   param->file_perms))) {
    fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
    exit(1);
  }
  if (0 != (err = CreateTestData(&hd))) {
    fprintf(stderr,
            "Could not write test data into test scratch file: NaCl errno %d\n",
            -err);
    exit(1);
  }
  if (NULL != param->test_data_start) {
    off = NaClHostDescSeek(&hd, 0, 0);
    if (off < 0) {
      fprintf(stderr,
              "Could not seek to create test data: NaCl errno %d\n",
              (int) -off);
      exit(1);
    }
    desired_write = param->test_data_size;
    bytes_written = NaClHostDescWrite(&hd,
                                      param->test_data_start,
                                      desired_write);
    if (bytes_written < 0) {
      fprintf(stderr,
              "Could not write specialized test data: NaCl errno %d\n",
              (int) -bytes_written);
      exit(1);
    }
    if ((size_t) bytes_written != desired_write) {
      fprintf(stderr,
              "Error while writing specialized test data:"
              " tried to write %d, actual %d\n",
              (int) desired_write, (int) bytes_written);
      exit(1);
    }
  }
  if (0 != (err = NaClHostDescClose(&hd))) {
    fprintf(stderr,
            "Error while closing test data file, errno %d\n", -err);
    exit(1);
  }
  if (0 != (err = NaClHostDescOpen(d_out,
                                   pathname,
                                   param->open_flags,
                                   param->file_perms))) {
    fprintf(stderr, "Could not open test scratch file: NaCl errno %d\n", -err);
    exit(1);
  }
}
/*
 * mmap MAP_PRIVATE test
 *
 * Make sure that a MAP_PRIVATE view initially sees the changes made
 * in a MAP_SHARED view, but after touching the private view further
 * changes become invisible.
 */
int map_private_test(struct NaClHostDesc *d, void *test_specifics) {
  struct MapPrivateSpecifics *params =
      (struct MapPrivateSpecifics *) test_specifics;
  struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
  uintptr_t view1;
  uintptr_t view2;
  nacl_off64_t off;
  ssize_t bytes_written;
  char *v1ptr;
  char *v2ptr;

  if ((uintptr_t) -4095 <
      (view1 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_SHARED,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view1 map failed, errno %d\n",
            -(int) view1);
    return 1;
  }

  NaClLog(2, "map_private_test: view1 = 0x%"NACL_PRIxPTR"\n", view1);

  if ((uintptr_t) -4095 <
      (view2 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_PRIVATE,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view2 map failed, errno %d\n",
            -(int) view2);
    return 1;
  }

  NaClLog(2, "map_private_test: view2 = 0x%"NACL_PRIxPTR"\n", view2);

  v1ptr = (char *) view1;
  v2ptr = (char *) view2;

  CHECK(v1ptr[0] == '\0');
  CHECK(v2ptr[0] == '\0');
  if (params->shm_not_write) {
    NaClLog(2, "map_private_test: changing via shm view\n");
    v1ptr[0] = 'x';  /* write through shared view */
  } else {
    NaClLog(2, "map_private_test: changing via write interface\n");
    off = NaClHostDescSeek(d, 0, 0);
    if (off < 0) {
      fprintf(stderr, "Could not seek: NaCl errno %d\n", (int) -off);
      return 1;
    }
    bytes_written = NaClHostDescWrite(d, "x", 1);
    if (1 != bytes_written) {
      fprintf(stderr, "Could not write: NaCl errno %d\n", (int) -bytes_written);
      return 1;
    }
  }
#if NACL_LINUX || NACL_WINDOWS
  /*
   * Most OSes have this behavior: a PRIVATE mapping is copy-on-write,
   * but the COW occurs when the fault occurs on that mapping, not
   * other mappings; otherwise, the page tables just point the system
   * to the buffer cache (or, if evicted, a stub entry that permits
   * faulting in the page).  So, a write through a writable file
   * descriptor or a SHARED mapping would modify the buffer cache, and
   * the PRIVATE mapping would see such changes until a fault occurs.
   */
  CHECK(v2ptr[0] == 'x');  /* visible! */
#elif NACL_OSX
  /*
   * On OSX, however, the underlying Mach primitives provide
   * bidirectional COW.
   */
  CHECK(v2ptr[0] == '\0');  /* NOT visible! */
#else
# error "Unsupported OS"
#endif

  v2ptr[0] = 'z';  /* COW fault */
  v1ptr[0] = 'y';
  CHECK(v2ptr[0] == 'z'); /* private! */

  CHECK(v1ptr[0x400] == '\0');
  v2ptr[0x400] = 'y';
  CHECK(v1ptr[0x400] == '\0');

  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));

  return 0;
}