1//===- FuzzerShmemPosix.cpp - Posix shared memory ---------------*- C++ -* ===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9// SharedMemoryRegion
10//===----------------------------------------------------------------------===//
11#include "FuzzerDefs.h"
12#if LIBFUZZER_POSIX
13
14#include "FuzzerIO.h"
15#include "FuzzerShmem.h"
16
17#include <errno.h>
18#include <fcntl.h>
19#include <semaphore.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <sys/mman.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <unistd.h>
26
27namespace fuzzer {
28
29std::string SharedMemoryRegion::Path(const char *Name) {
30  return DirPlusFile(TmpDir(), Name);
31}
32
33std::string SharedMemoryRegion::SemName(const char *Name, int Idx) {
34  std::string Res(Name);
35  // When passing a name without a leading <slash> character to
36  // sem_open, the behaviour is unspecified in POSIX. Add a leading
37  // <slash> character for the name if there is no such one.
38  if (!Res.empty() && Res[0] != '/')
39    Res.insert(Res.begin(), '/');
40  return Res + (char)('0' + Idx);
41}
42
43bool SharedMemoryRegion::Map(int fd) {
44  Data =
45      (uint8_t *)mmap(0, kShmemSize, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
46  if (Data == (uint8_t*)-1)
47    return false;
48  return true;
49}
50
51bool SharedMemoryRegion::Create(const char *Name) {
52  int fd = open(Path(Name).c_str(), O_CREAT | O_RDWR, 0777);
53  if (fd < 0) return false;
54  if (ftruncate(fd, kShmemSize) < 0) return false;
55  if (!Map(fd))
56    return false;
57  for (int i = 0; i < 2; i++) {
58    sem_unlink(SemName(Name, i).c_str());
59    Semaphore[i] = sem_open(SemName(Name, i).c_str(), O_CREAT, 0644, 0);
60    if (Semaphore[i] == SEM_FAILED)
61      return false;
62  }
63  IAmServer = true;
64  return true;
65}
66
67bool SharedMemoryRegion::Open(const char *Name) {
68  int fd = open(Path(Name).c_str(), O_RDWR);
69  if (fd < 0) return false;
70  struct stat stat_res;
71  if (0 != fstat(fd, &stat_res))
72    return false;
73  assert(stat_res.st_size == kShmemSize);
74  if (!Map(fd))
75    return false;
76  for (int i = 0; i < 2; i++) {
77    Semaphore[i] = sem_open(SemName(Name, i).c_str(), 0);
78    if (Semaphore[i] == SEM_FAILED)
79      return false;
80  }
81  IAmServer = false;
82  return true;
83}
84
85bool SharedMemoryRegion::Destroy(const char *Name) {
86  return 0 == unlink(Path(Name).c_str());
87}
88
89void SharedMemoryRegion::Post(int Idx) {
90  assert(Idx == 0 || Idx == 1);
91  sem_post((sem_t*)Semaphore[Idx]);
92}
93
94void SharedMemoryRegion::Wait(int Idx) {
95  assert(Idx == 0 || Idx == 1);
96  for (int i = 0; i < 10 && sem_wait((sem_t*)Semaphore[Idx]); i++) {
97    // sem_wait may fail if interrupted by a signal.
98    sleep(i);
99    if (i)
100      Printf("%s: sem_wait[%d] failed %s\n", i < 9 ? "WARNING" : "ERROR", i,
101             strerror(errno));
102    if (i == 9) abort();
103  }
104}
105
106}  // namespace fuzzer
107
108#endif  // LIBFUZZER_POSIX
109