Botan  1.10.16
mmap_mem.cpp
Go to the documentation of this file.
1 /*
2 * Memory Mapping Allocator
3 * (C) 1999-2010 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/internal/mmap_mem.h>
9 #include <vector>
10 #include <cstring>
11 
12 #include <sys/types.h>
13 #include <sys/mman.h>
14 #include <sys/stat.h>
15 #include <unistd.h>
16 #include <stdlib.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 
20 #ifndef MAP_FAILED
21  #define MAP_FAILED -1
22 #endif
23 
24 namespace Botan {
25 
26 namespace {
27 
28 /*
29 * MemoryMapping_Allocator Exception
30 */
31 class BOTAN_DLL MemoryMapping_Failed : public Exception
32  {
33  public:
34  MemoryMapping_Failed(const std::string& msg) :
35  Exception("MemoryMapping_Allocator: " + msg) {}
36  };
37 
38 }
39 
40 /*
41 * Memory Map a File into Memory
42 */
43 void* MemoryMapping_Allocator::alloc_block(size_t n)
44  {
45  class TemporaryFile
46  {
47  public:
48  int get_fd() const { return fd; }
49 
50  TemporaryFile(const std::string& base)
51  {
52  const std::string mkstemp_template = base + "XXXXXX";
53 
54  std::vector<char> filepath(mkstemp_template.begin(),
55  mkstemp_template.end());
56  filepath.push_back(0); // add terminating NULL
57 
58  mode_t old_umask = ::umask(077);
59  fd = ::mkstemp(&filepath[0]);
60  ::umask(old_umask);
61 
62  if(fd == -1)
63  throw MemoryMapping_Failed("Temporary file allocation failed");
64 
65  if(::unlink(&filepath[0]) != 0)
66  throw MemoryMapping_Failed("Could not unlink temporary file");
67  }
68 
69  ~TemporaryFile()
70  {
71  /*
72  * We can safely close here, because post-mmap the file
73  * will continue to exist until the mmap is unmapped from
74  * our address space upon deallocation (or process exit).
75  */
76  fd != -1 && ::close(fd);
77  }
78  private:
79  int fd;
80  };
81 
82  TemporaryFile file("/tmp/botan_");
83 
84  if(file.get_fd() == -1)
85  throw MemoryMapping_Failed("Could not create file");
86 
87  std::vector<byte> zeros(4096);
88 
89  size_t remaining = n;
90 
91  while(remaining)
92  {
93  const size_t write_try = std::min(zeros.size(), remaining);
94 
95  ssize_t wrote_got = ::write(file.get_fd(),
96  &zeros[0],
97  write_try);
98 
99  if(wrote_got == -1 && errno != EINTR)
100  throw MemoryMapping_Failed("Could not write to file");
101 
102  remaining -= wrote_got;
103  }
104 
105 #ifndef MAP_NOSYNC
106  #define MAP_NOSYNC 0
107 #endif
108 
109  void* ptr = ::mmap(0, n,
110  PROT_READ | PROT_WRITE,
111  MAP_SHARED | MAP_NOSYNC,
112  file.get_fd(), 0);
113 
114  if(ptr == static_cast<void*>(MAP_FAILED))
115  throw MemoryMapping_Failed("Could not map file");
116 
117  return ptr;
118  }
119 
120 /*
121 * Remove a Memory Mapping
122 */
123 void MemoryMapping_Allocator::dealloc_block(void* ptr, size_t n)
124  {
125  if(ptr == 0)
126  return;
127 
128  const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 };
129 
130  // The char* casts are for Solaris, args are void* on most other systems
131 
132  for(size_t i = 0; i != sizeof(PATTERNS); ++i)
133  {
134  std::memset(ptr, PATTERNS[i], n);
135 
136  if(::msync(static_cast<char*>(ptr), n, MS_SYNC))
137  throw MemoryMapping_Failed("Sync operation failed");
138  }
139 
140  if(::munmap(static_cast<char*>(ptr), n))
141  throw MemoryMapping_Failed("Could not unmap file");
142  }
143 
144 }
unsigned char byte
Definition: types.h:22
#define MAP_FAILED
Definition: mmap_mem.cpp:21
#define MAP_NOSYNC
std::runtime_error Exception
Definition: exceptn.h:19
T min(T a, T b)
Definition: ct_utils.h:127