Botan 1.10.17
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
24namespace Botan {
25
26namespace {
27
28/*
29* MemoryMapping_Allocator Exception
30*/
31class 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*/
43void* 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*/
123void 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}
#define MAP_FAILED
Definition mmap_mem.cpp:21
#define MAP_NOSYNC