annotate libsanitizer/sanitizer_common/sanitizer_posix.cc @ 144:8f4e72ab4e11

fix segmentation fault caused by nothing next cur_op to end
author Takahiro SHIMIZU <anatofuz@cr.ie.u-ryukyu.ac.jp>
date Sun, 23 Dec 2018 21:23:56 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 //===-- sanitizer_posix.cc ------------------------------------------------===//
kono
parents:
diff changeset
2 //
kono
parents:
diff changeset
3 // This file is distributed under the University of Illinois Open Source
kono
parents:
diff changeset
4 // License. See LICENSE.TXT for details.
kono
parents:
diff changeset
5 //
kono
parents:
diff changeset
6 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
7 //
kono
parents:
diff changeset
8 // This file is shared between AddressSanitizer and ThreadSanitizer
kono
parents:
diff changeset
9 // run-time libraries and implements POSIX-specific functions from
kono
parents:
diff changeset
10 // sanitizer_posix.h.
kono
parents:
diff changeset
11 //===----------------------------------------------------------------------===//
kono
parents:
diff changeset
12
kono
parents:
diff changeset
13 #include "sanitizer_platform.h"
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 #if SANITIZER_POSIX
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 #include "sanitizer_common.h"
kono
parents:
diff changeset
18 #include "sanitizer_file.h"
kono
parents:
diff changeset
19 #include "sanitizer_libc.h"
kono
parents:
diff changeset
20 #include "sanitizer_posix.h"
kono
parents:
diff changeset
21 #include "sanitizer_procmaps.h"
kono
parents:
diff changeset
22 #include "sanitizer_stacktrace.h"
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 #include <errno.h>
kono
parents:
diff changeset
25 #include <fcntl.h>
kono
parents:
diff changeset
26 #include <signal.h>
kono
parents:
diff changeset
27 #include <sys/mman.h>
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 #if SANITIZER_FREEBSD
kono
parents:
diff changeset
30 // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
kono
parents:
diff changeset
31 // that, it was never implemented. So just define it to zero.
kono
parents:
diff changeset
32 #undef MAP_NORESERVE
kono
parents:
diff changeset
33 #define MAP_NORESERVE 0
kono
parents:
diff changeset
34 #endif
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 namespace __sanitizer {
kono
parents:
diff changeset
37
kono
parents:
diff changeset
38 // ------------- sanitizer_common.h
kono
parents:
diff changeset
39 uptr GetMmapGranularity() {
kono
parents:
diff changeset
40 return GetPageSize();
kono
parents:
diff changeset
41 }
kono
parents:
diff changeset
42
kono
parents:
diff changeset
43 void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
kono
parents:
diff changeset
44 size = RoundUpTo(size, GetPageSizeCached());
kono
parents:
diff changeset
45 uptr res = internal_mmap(nullptr, size,
kono
parents:
diff changeset
46 PROT_READ | PROT_WRITE,
kono
parents:
diff changeset
47 MAP_PRIVATE | MAP_ANON, -1, 0);
kono
parents:
diff changeset
48 int reserrno;
kono
parents:
diff changeset
49 if (UNLIKELY(internal_iserror(res, &reserrno)))
kono
parents:
diff changeset
50 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
kono
parents:
diff changeset
51 IncreaseTotalMmap(size);
kono
parents:
diff changeset
52 return (void *)res;
kono
parents:
diff changeset
53 }
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 void UnmapOrDie(void *addr, uptr size) {
kono
parents:
diff changeset
56 if (!addr || !size) return;
kono
parents:
diff changeset
57 uptr res = internal_munmap(addr, size);
kono
parents:
diff changeset
58 if (UNLIKELY(internal_iserror(res))) {
kono
parents:
diff changeset
59 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
kono
parents:
diff changeset
60 SanitizerToolName, size, size, addr);
kono
parents:
diff changeset
61 CHECK("unable to unmap" && 0);
kono
parents:
diff changeset
62 }
kono
parents:
diff changeset
63 DecreaseTotalMmap(size);
kono
parents:
diff changeset
64 }
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
kono
parents:
diff changeset
67 size = RoundUpTo(size, GetPageSizeCached());
kono
parents:
diff changeset
68 uptr res = internal_mmap(nullptr, size,
kono
parents:
diff changeset
69 PROT_READ | PROT_WRITE,
kono
parents:
diff changeset
70 MAP_PRIVATE | MAP_ANON, -1, 0);
kono
parents:
diff changeset
71 int reserrno;
kono
parents:
diff changeset
72 if (UNLIKELY(internal_iserror(res, &reserrno))) {
kono
parents:
diff changeset
73 if (reserrno == ENOMEM)
kono
parents:
diff changeset
74 return nullptr;
kono
parents:
diff changeset
75 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
kono
parents:
diff changeset
76 }
kono
parents:
diff changeset
77 IncreaseTotalMmap(size);
kono
parents:
diff changeset
78 return (void *)res;
kono
parents:
diff changeset
79 }
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 // We want to map a chunk of address space aligned to 'alignment'.
kono
parents:
diff changeset
82 // We do it by mapping a bit more and then unmapping redundant pieces.
kono
parents:
diff changeset
83 // We probably can do it with fewer syscalls in some OS-dependent way.
kono
parents:
diff changeset
84 void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
kono
parents:
diff changeset
85 const char *mem_type) {
kono
parents:
diff changeset
86 CHECK(IsPowerOfTwo(size));
kono
parents:
diff changeset
87 CHECK(IsPowerOfTwo(alignment));
kono
parents:
diff changeset
88 uptr map_size = size + alignment;
kono
parents:
diff changeset
89 uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
kono
parents:
diff changeset
90 if (UNLIKELY(!map_res))
kono
parents:
diff changeset
91 return nullptr;
kono
parents:
diff changeset
92 uptr map_end = map_res + map_size;
kono
parents:
diff changeset
93 uptr res = map_res;
kono
parents:
diff changeset
94 if (!IsAligned(res, alignment)) {
kono
parents:
diff changeset
95 res = (map_res + alignment - 1) & ~(alignment - 1);
kono
parents:
diff changeset
96 UnmapOrDie((void*)map_res, res - map_res);
kono
parents:
diff changeset
97 }
kono
parents:
diff changeset
98 uptr end = res + size;
kono
parents:
diff changeset
99 if (end != map_end)
kono
parents:
diff changeset
100 UnmapOrDie((void*)end, map_end - end);
kono
parents:
diff changeset
101 return (void*)res;
kono
parents:
diff changeset
102 }
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
kono
parents:
diff changeset
105 uptr PageSize = GetPageSizeCached();
kono
parents:
diff changeset
106 uptr p = internal_mmap(nullptr,
kono
parents:
diff changeset
107 RoundUpTo(size, PageSize),
kono
parents:
diff changeset
108 PROT_READ | PROT_WRITE,
kono
parents:
diff changeset
109 MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
kono
parents:
diff changeset
110 -1, 0);
kono
parents:
diff changeset
111 int reserrno;
kono
parents:
diff changeset
112 if (UNLIKELY(internal_iserror(p, &reserrno)))
kono
parents:
diff changeset
113 ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
kono
parents:
diff changeset
114 IncreaseTotalMmap(size);
kono
parents:
diff changeset
115 return (void *)p;
kono
parents:
diff changeset
116 }
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) {
kono
parents:
diff changeset
119 uptr PageSize = GetPageSizeCached();
kono
parents:
diff changeset
120 uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
kono
parents:
diff changeset
121 RoundUpTo(size, PageSize),
kono
parents:
diff changeset
122 PROT_READ | PROT_WRITE,
kono
parents:
diff changeset
123 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
kono
parents:
diff changeset
124 -1, 0);
kono
parents:
diff changeset
125 int reserrno;
kono
parents:
diff changeset
126 if (UNLIKELY(internal_iserror(p, &reserrno))) {
kono
parents:
diff changeset
127 if (tolerate_enomem && reserrno == ENOMEM)
kono
parents:
diff changeset
128 return nullptr;
kono
parents:
diff changeset
129 char mem_type[40];
kono
parents:
diff changeset
130 internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
kono
parents:
diff changeset
131 fixed_addr);
kono
parents:
diff changeset
132 ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
kono
parents:
diff changeset
133 }
kono
parents:
diff changeset
134 IncreaseTotalMmap(size);
kono
parents:
diff changeset
135 return (void *)p;
kono
parents:
diff changeset
136 }
kono
parents:
diff changeset
137
kono
parents:
diff changeset
138 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
kono
parents:
diff changeset
139 return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/);
kono
parents:
diff changeset
140 }
kono
parents:
diff changeset
141
kono
parents:
diff changeset
142 void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
kono
parents:
diff changeset
143 return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/);
kono
parents:
diff changeset
144 }
kono
parents:
diff changeset
145
kono
parents:
diff changeset
146 bool MprotectNoAccess(uptr addr, uptr size) {
kono
parents:
diff changeset
147 return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
kono
parents:
diff changeset
148 }
kono
parents:
diff changeset
149
kono
parents:
diff changeset
150 bool MprotectReadOnly(uptr addr, uptr size) {
kono
parents:
diff changeset
151 return 0 == internal_mprotect((void *)addr, size, PROT_READ);
kono
parents:
diff changeset
152 }
kono
parents:
diff changeset
153
kono
parents:
diff changeset
154 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
kono
parents:
diff changeset
155 int flags;
kono
parents:
diff changeset
156 switch (mode) {
kono
parents:
diff changeset
157 case RdOnly: flags = O_RDONLY; break;
kono
parents:
diff changeset
158 case WrOnly: flags = O_WRONLY | O_CREAT; break;
kono
parents:
diff changeset
159 case RdWr: flags = O_RDWR | O_CREAT; break;
kono
parents:
diff changeset
160 }
kono
parents:
diff changeset
161 fd_t res = internal_open(filename, flags, 0660);
kono
parents:
diff changeset
162 if (internal_iserror(res, errno_p))
kono
parents:
diff changeset
163 return kInvalidFd;
kono
parents:
diff changeset
164 return res;
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166
kono
parents:
diff changeset
167 void CloseFile(fd_t fd) {
kono
parents:
diff changeset
168 internal_close(fd);
kono
parents:
diff changeset
169 }
kono
parents:
diff changeset
170
kono
parents:
diff changeset
171 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
kono
parents:
diff changeset
172 error_t *error_p) {
kono
parents:
diff changeset
173 uptr res = internal_read(fd, buff, buff_size);
kono
parents:
diff changeset
174 if (internal_iserror(res, error_p))
kono
parents:
diff changeset
175 return false;
kono
parents:
diff changeset
176 if (bytes_read)
kono
parents:
diff changeset
177 *bytes_read = res;
kono
parents:
diff changeset
178 return true;
kono
parents:
diff changeset
179 }
kono
parents:
diff changeset
180
kono
parents:
diff changeset
181 bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
kono
parents:
diff changeset
182 error_t *error_p) {
kono
parents:
diff changeset
183 uptr res = internal_write(fd, buff, buff_size);
kono
parents:
diff changeset
184 if (internal_iserror(res, error_p))
kono
parents:
diff changeset
185 return false;
kono
parents:
diff changeset
186 if (bytes_written)
kono
parents:
diff changeset
187 *bytes_written = res;
kono
parents:
diff changeset
188 return true;
kono
parents:
diff changeset
189 }
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
kono
parents:
diff changeset
192 uptr res = internal_rename(oldpath, newpath);
kono
parents:
diff changeset
193 return !internal_iserror(res, error_p);
kono
parents:
diff changeset
194 }
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
kono
parents:
diff changeset
197 fd_t fd = OpenFile(file_name, RdOnly);
kono
parents:
diff changeset
198 CHECK(fd != kInvalidFd);
kono
parents:
diff changeset
199 uptr fsize = internal_filesize(fd);
kono
parents:
diff changeset
200 CHECK_NE(fsize, (uptr)-1);
kono
parents:
diff changeset
201 CHECK_GT(fsize, 0);
kono
parents:
diff changeset
202 *buff_size = RoundUpTo(fsize, GetPageSizeCached());
kono
parents:
diff changeset
203 uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
kono
parents:
diff changeset
204 return internal_iserror(map) ? nullptr : (void *)map;
kono
parents:
diff changeset
205 }
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
kono
parents:
diff changeset
208 uptr flags = MAP_SHARED;
kono
parents:
diff changeset
209 if (addr) flags |= MAP_FIXED;
kono
parents:
diff changeset
210 uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
kono
parents:
diff changeset
211 int mmap_errno = 0;
kono
parents:
diff changeset
212 if (internal_iserror(p, &mmap_errno)) {
kono
parents:
diff changeset
213 Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
kono
parents:
diff changeset
214 fd, (long long)offset, size, p, mmap_errno);
kono
parents:
diff changeset
215 return nullptr;
kono
parents:
diff changeset
216 }
kono
parents:
diff changeset
217 return (void *)p;
kono
parents:
diff changeset
218 }
kono
parents:
diff changeset
219
kono
parents:
diff changeset
220 static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
kono
parents:
diff changeset
221 uptr start2, uptr end2) {
kono
parents:
diff changeset
222 CHECK(start1 <= end1);
kono
parents:
diff changeset
223 CHECK(start2 <= end2);
kono
parents:
diff changeset
224 return (end1 < start2) || (end2 < start1);
kono
parents:
diff changeset
225 }
kono
parents:
diff changeset
226
kono
parents:
diff changeset
227 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
kono
parents:
diff changeset
228 // When the shadow is mapped only a single thread usually exists (plus maybe
kono
parents:
diff changeset
229 // several worker threads on Mac, which aren't expected to map big chunks of
kono
parents:
diff changeset
230 // memory).
kono
parents:
diff changeset
231 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
kono
parents:
diff changeset
232 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
kono
parents:
diff changeset
233 MemoryMappedSegment segment;
kono
parents:
diff changeset
234 while (proc_maps.Next(&segment)) {
kono
parents:
diff changeset
235 if (segment.start == segment.end) continue; // Empty range.
kono
parents:
diff changeset
236 CHECK_NE(0, segment.end);
kono
parents:
diff changeset
237 if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
kono
parents:
diff changeset
238 range_end))
kono
parents:
diff changeset
239 return false;
kono
parents:
diff changeset
240 }
kono
parents:
diff changeset
241 return true;
kono
parents:
diff changeset
242 }
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 void DumpProcessMap() {
kono
parents:
diff changeset
245 MemoryMappingLayout proc_maps(/*cache_enabled*/true);
kono
parents:
diff changeset
246 const sptr kBufSize = 4095;
kono
parents:
diff changeset
247 char *filename = (char*)MmapOrDie(kBufSize, __func__);
kono
parents:
diff changeset
248 MemoryMappedSegment segment(filename, kBufSize);
kono
parents:
diff changeset
249 Report("Process memory map follows:\n");
kono
parents:
diff changeset
250 while (proc_maps.Next(&segment)) {
kono
parents:
diff changeset
251 Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
kono
parents:
diff changeset
252 segment.filename);
kono
parents:
diff changeset
253 }
kono
parents:
diff changeset
254 Report("End of process memory map.\n");
kono
parents:
diff changeset
255 UnmapOrDie(filename, kBufSize);
kono
parents:
diff changeset
256 }
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 const char *GetPwd() {
kono
parents:
diff changeset
259 return GetEnv("PWD");
kono
parents:
diff changeset
260 }
kono
parents:
diff changeset
261
kono
parents:
diff changeset
262 bool IsPathSeparator(const char c) {
kono
parents:
diff changeset
263 return c == '/';
kono
parents:
diff changeset
264 }
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 bool IsAbsolutePath(const char *path) {
kono
parents:
diff changeset
267 return path != nullptr && IsPathSeparator(path[0]);
kono
parents:
diff changeset
268 }
kono
parents:
diff changeset
269
kono
parents:
diff changeset
270 void ReportFile::Write(const char *buffer, uptr length) {
kono
parents:
diff changeset
271 SpinMutexLock l(mu);
kono
parents:
diff changeset
272 static const char *kWriteError =
kono
parents:
diff changeset
273 "ReportFile::Write() can't output requested buffer!\n";
kono
parents:
diff changeset
274 ReopenIfNecessary();
kono
parents:
diff changeset
275 if (length != internal_write(fd, buffer, length)) {
kono
parents:
diff changeset
276 internal_write(fd, kWriteError, internal_strlen(kWriteError));
kono
parents:
diff changeset
277 Die();
kono
parents:
diff changeset
278 }
kono
parents:
diff changeset
279 }
kono
parents:
diff changeset
280
kono
parents:
diff changeset
281 bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
kono
parents:
diff changeset
282 MemoryMappingLayout proc_maps(/*cache_enabled*/false);
kono
parents:
diff changeset
283 InternalScopedString buff(kMaxPathLength);
kono
parents:
diff changeset
284 MemoryMappedSegment segment(buff.data(), kMaxPathLength);
kono
parents:
diff changeset
285 while (proc_maps.Next(&segment)) {
kono
parents:
diff changeset
286 if (segment.IsExecutable() &&
kono
parents:
diff changeset
287 internal_strcmp(module, segment.filename) == 0) {
kono
parents:
diff changeset
288 *start = segment.start;
kono
parents:
diff changeset
289 *end = segment.end;
kono
parents:
diff changeset
290 return true;
kono
parents:
diff changeset
291 }
kono
parents:
diff changeset
292 }
kono
parents:
diff changeset
293 return false;
kono
parents:
diff changeset
294 }
kono
parents:
diff changeset
295
kono
parents:
diff changeset
296 uptr SignalContext::GetAddress() const {
kono
parents:
diff changeset
297 auto si = static_cast<const siginfo_t *>(siginfo);
kono
parents:
diff changeset
298 return (uptr)si->si_addr;
kono
parents:
diff changeset
299 }
kono
parents:
diff changeset
300
kono
parents:
diff changeset
301 bool SignalContext::IsMemoryAccess() const {
kono
parents:
diff changeset
302 auto si = static_cast<const siginfo_t *>(siginfo);
kono
parents:
diff changeset
303 return si->si_signo == SIGSEGV;
kono
parents:
diff changeset
304 }
kono
parents:
diff changeset
305
kono
parents:
diff changeset
306 int SignalContext::GetType() const {
kono
parents:
diff changeset
307 return static_cast<const siginfo_t *>(siginfo)->si_signo;
kono
parents:
diff changeset
308 }
kono
parents:
diff changeset
309
kono
parents:
diff changeset
310 const char *SignalContext::Describe() const {
kono
parents:
diff changeset
311 switch (GetType()) {
kono
parents:
diff changeset
312 case SIGFPE:
kono
parents:
diff changeset
313 return "FPE";
kono
parents:
diff changeset
314 case SIGILL:
kono
parents:
diff changeset
315 return "ILL";
kono
parents:
diff changeset
316 case SIGABRT:
kono
parents:
diff changeset
317 return "ABRT";
kono
parents:
diff changeset
318 case SIGSEGV:
kono
parents:
diff changeset
319 return "SEGV";
kono
parents:
diff changeset
320 case SIGBUS:
kono
parents:
diff changeset
321 return "BUS";
kono
parents:
diff changeset
322 }
kono
parents:
diff changeset
323 return "UNKNOWN SIGNAL";
kono
parents:
diff changeset
324 }
kono
parents:
diff changeset
325
kono
parents:
diff changeset
326 } // namespace __sanitizer
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 #endif // SANITIZER_POSIX