| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 1 | //===-- sanitizer_mac.cc --------------------------------------------------===// | 
|  | 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 | // | 
|  | 10 | // This file is shared between AddressSanitizer and ThreadSanitizer | 
|  | 11 | // run-time libraries and implements mac-specific functions from | 
|  | 12 | // sanitizer_libc.h. | 
|  | 13 | //===----------------------------------------------------------------------===// | 
|  | 14 |  | 
|  | 15 | #ifdef __APPLE__ | 
| Alexander Potapenko | d895ae9 | 2013-02-06 14:41:15 +0000 | [diff] [blame] | 16 | // Use 64-bit inodes in file operations. ASan does not support OS X 10.5, so | 
|  | 17 | // the clients will most certainly use 64-bit ones as well. | 
|  | 18 | #ifndef _DARWIN_USE_64_BIT_INODE | 
|  | 19 | #define _DARWIN_USE_64_BIT_INODE 1 | 
|  | 20 | #endif | 
|  | 21 | #include <stdio.h> | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 22 |  | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 23 | #include "sanitizer_common.h" | 
| Alexey Samsonov | 5bbf829 | 2012-06-05 14:25:27 +0000 | [diff] [blame] | 24 | #include "sanitizer_internal_defs.h" | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 25 | #include "sanitizer_libc.h" | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 26 | #include "sanitizer_procmaps.h" | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 27 |  | 
| Alexey Samsonov | 0c53a38 | 2012-06-14 14:07:21 +0000 | [diff] [blame] | 28 | #include <crt_externs.h>  // for _NSGetEnviron | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 29 | #include <fcntl.h> | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 30 | #include <mach-o/dyld.h> | 
|  | 31 | #include <mach-o/loader.h> | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 32 | #include <pthread.h> | 
| Alexey Samsonov | 58a3c58 | 2012-06-18 08:44:30 +0000 | [diff] [blame] | 33 | #include <sched.h> | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 34 | #include <sys/mman.h> | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 35 | #include <sys/resource.h> | 
| Alexey Samsonov | dde1f11 | 2012-06-05 07:05:10 +0000 | [diff] [blame] | 36 | #include <sys/stat.h> | 
|  | 37 | #include <sys/types.h> | 
| Alexey Samsonov | 03c8b84 | 2012-06-05 08:32:53 +0000 | [diff] [blame] | 38 | #include <unistd.h> | 
| Dmitry Vyukov | af4b0b0 | 2013-01-14 08:01:58 +0000 | [diff] [blame] | 39 | #include <libkern/OSAtomic.h> | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 40 |  | 
|  | 41 | namespace __sanitizer { | 
|  | 42 |  | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 43 | // ---------------------- sanitizer_libc.h | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 44 | void *internal_mmap(void *addr, size_t length, int prot, int flags, | 
|  | 45 | int fd, u64 offset) { | 
|  | 46 | return mmap(addr, length, prot, flags, fd, offset); | 
|  | 47 | } | 
|  | 48 |  | 
| Alexey Samsonov | 7ac77d6 | 2012-06-05 09:49:25 +0000 | [diff] [blame] | 49 | int internal_munmap(void *addr, uptr length) { | 
|  | 50 | return munmap(addr, length); | 
|  | 51 | } | 
|  | 52 |  | 
| Alexey Samsonov | 03c8b84 | 2012-06-05 08:32:53 +0000 | [diff] [blame] | 53 | int internal_close(fd_t fd) { | 
|  | 54 | return close(fd); | 
|  | 55 | } | 
|  | 56 |  | 
| Alexey Samsonov | 39313b7 | 2013-02-01 15:58:46 +0000 | [diff] [blame] | 57 | fd_t internal_open(const char *filename, int flags) { | 
|  | 58 | return open(filename, flags); | 
|  | 59 | } | 
|  | 60 |  | 
| Alexey Samsonov | 4985b87 | 2013-02-01 16:32:18 +0000 | [diff] [blame] | 61 | fd_t internal_open(const char *filename, int flags, u32 mode) { | 
| Alexey Samsonov | 39313b7 | 2013-02-01 15:58:46 +0000 | [diff] [blame] | 62 | return open(filename, flags, mode); | 
|  | 63 | } | 
|  | 64 |  | 
|  | 65 | fd_t OpenFile(const char *filename, bool write) { | 
|  | 66 | return internal_open(filename, | 
|  | 67 | write ? O_WRONLY | O_CREAT : O_RDONLY, 0660); | 
| Alexey Samsonov | dde1f11 | 2012-06-05 07:05:10 +0000 | [diff] [blame] | 68 | } | 
|  | 69 |  | 
| Alexey Samsonov | 03c8b84 | 2012-06-05 08:32:53 +0000 | [diff] [blame] | 70 | uptr internal_read(fd_t fd, void *buf, uptr count) { | 
|  | 71 | return read(fd, buf, count); | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | uptr internal_write(fd_t fd, const void *buf, uptr count) { | 
|  | 75 | return write(fd, buf, count); | 
|  | 76 | } | 
|  | 77 |  | 
| Alexey Samsonov | 2c5cbd2 | 2013-02-04 10:16:50 +0000 | [diff] [blame] | 78 | int internal_stat(const char *path, void *buf) { | 
| Alexey Samsonov | 576e270 | 2013-02-04 10:31:39 +0000 | [diff] [blame] | 79 | return stat(path, (struct stat *)buf); | 
| Alexey Samsonov | 2c5cbd2 | 2013-02-04 10:16:50 +0000 | [diff] [blame] | 80 | } | 
|  | 81 |  | 
|  | 82 | int internal_lstat(const char *path, void *buf) { | 
| Alexey Samsonov | 576e270 | 2013-02-04 10:31:39 +0000 | [diff] [blame] | 83 | return lstat(path, (struct stat *)buf); | 
| Alexey Samsonov | 2c5cbd2 | 2013-02-04 10:16:50 +0000 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
|  | 86 | int internal_fstat(fd_t fd, void *buf) { | 
| Alexey Samsonov | 576e270 | 2013-02-04 10:31:39 +0000 | [diff] [blame] | 87 | return fstat(fd, (struct stat *)buf); | 
| Alexey Samsonov | 2c5cbd2 | 2013-02-04 10:16:50 +0000 | [diff] [blame] | 88 | } | 
|  | 89 |  | 
| Alexey Samsonov | ca2b5d7 | 2012-06-06 07:30:33 +0000 | [diff] [blame] | 90 | uptr internal_filesize(fd_t fd) { | 
| Alexey Samsonov | ce8d497 | 2012-08-02 10:09:31 +0000 | [diff] [blame] | 91 | struct stat st; | 
| Alexey Samsonov | 2c5cbd2 | 2013-02-04 10:16:50 +0000 | [diff] [blame] | 92 | if (internal_fstat(fd, &st)) | 
| Alexey Samsonov | ca2b5d7 | 2012-06-06 07:30:33 +0000 | [diff] [blame] | 93 | return -1; | 
|  | 94 | return (uptr)st.st_size; | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | int internal_dup2(int oldfd, int newfd) { | 
|  | 98 | return dup2(oldfd, newfd); | 
|  | 99 | } | 
|  | 100 |  | 
| Alexey Samsonov | f6d2125 | 2012-09-05 14:48:24 +0000 | [diff] [blame] | 101 | uptr internal_readlink(const char *path, char *buf, uptr bufsize) { | 
|  | 102 | return readlink(path, buf, bufsize); | 
|  | 103 | } | 
|  | 104 |  | 
| Alexey Samsonov | 58a3c58 | 2012-06-18 08:44:30 +0000 | [diff] [blame] | 105 | int internal_sched_yield() { | 
|  | 106 | return sched_yield(); | 
|  | 107 | } | 
|  | 108 |  | 
| Alexey Samsonov | aadd1f2 | 2013-02-20 13:54:32 +0000 | [diff] [blame] | 109 | void internal__exit(int exitcode) { | 
|  | 110 | _exit(exitcode); | 
|  | 111 | } | 
|  | 112 |  | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 113 | // ----------------- sanitizer_common.h | 
| Alexey Samsonov | ae9b18b | 2012-11-09 14:45:30 +0000 | [diff] [blame] | 114 | bool FileExists(const char *filename) { | 
|  | 115 | struct stat st; | 
|  | 116 | if (stat(filename, &st)) | 
|  | 117 | return false; | 
|  | 118 | // Sanity check: filename is a regular file. | 
|  | 119 | return S_ISREG(st.st_mode); | 
|  | 120 | } | 
|  | 121 |  | 
| Dmitry Vyukov | 56faa55 | 2012-10-02 12:58:14 +0000 | [diff] [blame] | 122 | uptr GetTid() { | 
|  | 123 | return reinterpret_cast<uptr>(pthread_self()); | 
|  | 124 | } | 
|  | 125 |  | 
| Alexey Samsonov | cf4d3a0 | 2012-06-07 07:32:00 +0000 | [diff] [blame] | 126 | void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top, | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 127 | uptr *stack_bottom) { | 
|  | 128 | CHECK(stack_top); | 
|  | 129 | CHECK(stack_bottom); | 
|  | 130 | uptr stacksize = pthread_get_stacksize_np(pthread_self()); | 
|  | 131 | void *stackaddr = pthread_get_stackaddr_np(pthread_self()); | 
|  | 132 | *stack_top = (uptr)stackaddr; | 
| Alexey Samsonov | cf4d3a0 | 2012-06-07 07:32:00 +0000 | [diff] [blame] | 133 | *stack_bottom = *stack_top - stacksize; | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 134 | } | 
|  | 135 |  | 
| Alexey Samsonov | 0c53a38 | 2012-06-14 14:07:21 +0000 | [diff] [blame] | 136 | const char *GetEnv(const char *name) { | 
|  | 137 | char ***env_ptr = _NSGetEnviron(); | 
|  | 138 | CHECK(env_ptr); | 
|  | 139 | char **environ = *env_ptr; | 
|  | 140 | CHECK(environ); | 
|  | 141 | uptr name_len = internal_strlen(name); | 
|  | 142 | while (*environ != 0) { | 
|  | 143 | uptr len = internal_strlen(*environ); | 
|  | 144 | if (len > name_len) { | 
|  | 145 | const char *p = *environ; | 
|  | 146 | if (!internal_memcmp(p, name, name_len) && | 
|  | 147 | p[name_len] == '=') {  // Match. | 
|  | 148 | return *environ + name_len + 1;  // String starting after =. | 
|  | 149 | } | 
|  | 150 | } | 
|  | 151 | environ++; | 
|  | 152 | } | 
|  | 153 | return 0; | 
|  | 154 | } | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 155 |  | 
| Alexey Samsonov | 97ca306 | 2012-09-17 09:12:39 +0000 | [diff] [blame] | 156 | void ReExec() { | 
|  | 157 | UNIMPLEMENTED(); | 
|  | 158 | } | 
|  | 159 |  | 
| Alexander Potapenko | 1746f55 | 2012-12-10 13:10:40 +0000 | [diff] [blame] | 160 | void PrepareForSandboxing() { | 
|  | 161 | // Nothing here for now. | 
|  | 162 | } | 
|  | 163 |  | 
| Alexey Samsonov | 4b1f103 | 2012-06-07 07:13:46 +0000 | [diff] [blame] | 164 | // ----------------- sanitizer_procmaps.h | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 165 |  | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 166 | MemoryMappingLayout::MemoryMappingLayout() { | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 167 | Reset(); | 
|  | 168 | } | 
|  | 169 |  | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 170 | MemoryMappingLayout::~MemoryMappingLayout() { | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 171 | } | 
|  | 172 |  | 
|  | 173 | // More information about Mach-O headers can be found in mach-o/loader.h | 
|  | 174 | // Each Mach-O image has a header (mach_header or mach_header_64) starting with | 
|  | 175 | // a magic number, and a list of linker load commands directly following the | 
|  | 176 | // header. | 
|  | 177 | // A load command is at least two 32-bit words: the command type and the | 
|  | 178 | // command size in bytes. We're interested only in segment load commands | 
|  | 179 | // (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped | 
|  | 180 | // into the task's address space. | 
|  | 181 | // The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or | 
|  | 182 | // segment_command_64 correspond to the memory address, memory size and the | 
|  | 183 | // file offset of the current memory segment. | 
|  | 184 | // Because these fields are taken from the images as is, one needs to add | 
|  | 185 | // _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime. | 
|  | 186 |  | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 187 | void MemoryMappingLayout::Reset() { | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 188 | // Count down from the top. | 
|  | 189 | // TODO(glider): as per man 3 dyld, iterating over the headers with | 
|  | 190 | // _dyld_image_count is thread-unsafe. We need to register callbacks for | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 191 | // adding and removing images which will invalidate the MemoryMappingLayout | 
|  | 192 | // state. | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 193 | current_image_ = _dyld_image_count(); | 
|  | 194 | current_load_cmd_count_ = -1; | 
|  | 195 | current_load_cmd_addr_ = 0; | 
|  | 196 | current_magic_ = 0; | 
| Alexander Potapenko | 77c0ac2 | 2012-10-02 15:42:24 +0000 | [diff] [blame] | 197 | current_filetype_ = 0; | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 198 | } | 
|  | 199 |  | 
| Alexander Potapenko | 7811425 | 2012-12-01 02:39:45 +0000 | [diff] [blame] | 200 | // static | 
|  | 201 | void MemoryMappingLayout::CacheMemoryMappings() { | 
|  | 202 | // No-op on Mac for now. | 
|  | 203 | } | 
|  | 204 |  | 
|  | 205 | void MemoryMappingLayout::LoadFromCache() { | 
|  | 206 | // No-op on Mac for now. | 
|  | 207 | } | 
|  | 208 |  | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 209 | // Next and NextSegmentLoad were inspired by base/sysinfo.cc in | 
|  | 210 | // Google Perftools, http://code.google.com/p/google-perftools. | 
|  | 211 |  | 
|  | 212 | // NextSegmentLoad scans the current image for the next segment load command | 
|  | 213 | // and returns the start and end addresses and file offset of the corresponding | 
|  | 214 | // segment. | 
|  | 215 | // Note that the segment addresses are not necessarily sorted. | 
|  | 216 | template<u32 kLCSegment, typename SegmentCommand> | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 217 | bool MemoryMappingLayout::NextSegmentLoad( | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 218 | uptr *start, uptr *end, uptr *offset, | 
|  | 219 | char filename[], uptr filename_size) { | 
|  | 220 | const char* lc = current_load_cmd_addr_; | 
|  | 221 | current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize; | 
|  | 222 | if (((const load_command *)lc)->cmd == kLCSegment) { | 
|  | 223 | const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_); | 
|  | 224 | const SegmentCommand* sc = (const SegmentCommand *)lc; | 
|  | 225 | if (start) *start = sc->vmaddr + dlloff; | 
|  | 226 | if (end) *end = sc->vmaddr + sc->vmsize + dlloff; | 
| Alexander Potapenko | 77c0ac2 | 2012-10-02 15:42:24 +0000 | [diff] [blame] | 227 | if (offset) { | 
|  | 228 | if (current_filetype_ == /*MH_EXECUTE*/ 0x2) { | 
|  | 229 | *offset = sc->vmaddr; | 
|  | 230 | } else { | 
|  | 231 | *offset = sc->fileoff; | 
|  | 232 | } | 
|  | 233 | } | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 234 | if (filename) { | 
|  | 235 | internal_strncpy(filename, _dyld_get_image_name(current_image_), | 
|  | 236 | filename_size); | 
|  | 237 | } | 
|  | 238 | return true; | 
|  | 239 | } | 
|  | 240 | return false; | 
|  | 241 | } | 
|  | 242 |  | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 243 | bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset, | 
|  | 244 | char filename[], uptr filename_size) { | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 245 | for (; current_image_ >= 0; current_image_--) { | 
|  | 246 | const mach_header* hdr = _dyld_get_image_header(current_image_); | 
|  | 247 | if (!hdr) continue; | 
|  | 248 | if (current_load_cmd_count_ < 0) { | 
|  | 249 | // Set up for this image; | 
|  | 250 | current_load_cmd_count_ = hdr->ncmds; | 
|  | 251 | current_magic_ = hdr->magic; | 
| Alexander Potapenko | 77c0ac2 | 2012-10-02 15:42:24 +0000 | [diff] [blame] | 252 | current_filetype_ = hdr->filetype; | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 253 | switch (current_magic_) { | 
|  | 254 | #ifdef MH_MAGIC_64 | 
|  | 255 | case MH_MAGIC_64: { | 
|  | 256 | current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64); | 
|  | 257 | break; | 
|  | 258 | } | 
|  | 259 | #endif | 
|  | 260 | case MH_MAGIC: { | 
|  | 261 | current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header); | 
|  | 262 | break; | 
|  | 263 | } | 
|  | 264 | default: { | 
|  | 265 | continue; | 
|  | 266 | } | 
|  | 267 | } | 
|  | 268 | } | 
|  | 269 |  | 
|  | 270 | for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) { | 
|  | 271 | switch (current_magic_) { | 
|  | 272 | // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64. | 
|  | 273 | #ifdef MH_MAGIC_64 | 
|  | 274 | case MH_MAGIC_64: { | 
|  | 275 | if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>( | 
|  | 276 | start, end, offset, filename, filename_size)) | 
|  | 277 | return true; | 
|  | 278 | break; | 
|  | 279 | } | 
|  | 280 | #endif | 
|  | 281 | case MH_MAGIC: { | 
|  | 282 | if (NextSegmentLoad<LC_SEGMENT, struct segment_command>( | 
|  | 283 | start, end, offset, filename, filename_size)) | 
|  | 284 | return true; | 
|  | 285 | break; | 
|  | 286 | } | 
|  | 287 | } | 
|  | 288 | } | 
|  | 289 | // If we get here, no more load_cmd's in this image talk about | 
|  | 290 | // segments.  Go on to the next image. | 
|  | 291 | } | 
|  | 292 | return false; | 
|  | 293 | } | 
|  | 294 |  | 
| Alexey Samsonov | cc62211 | 2012-08-27 13:48:48 +0000 | [diff] [blame] | 295 | bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset, | 
|  | 296 | char filename[], | 
|  | 297 | uptr filename_size) { | 
| Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 298 | return IterateForObjectNameAndOffset(addr, offset, filename, filename_size); | 
|  | 299 | } | 
|  | 300 |  | 
| Dmitry Vyukov | f22982b | 2013-01-14 07:51:39 +0000 | [diff] [blame] | 301 | BlockingMutex::BlockingMutex(LinkerInitialized) { | 
|  | 302 | // We assume that OS_SPINLOCK_INIT is zero | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | void BlockingMutex::Lock() { | 
|  | 306 | CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_)); | 
| Kostya Serebryany | 459df6f | 2013-02-26 12:59:06 +0000 | [diff] [blame] | 307 | CHECK_EQ(OS_SPINLOCK_INIT, 0); | 
|  | 308 | CHECK_NE(owner_, (uptr)pthread_self()); | 
| Dmitry Vyukov | f22982b | 2013-01-14 07:51:39 +0000 | [diff] [blame] | 309 | OSSpinLockLock((OSSpinLock*)&opaque_storage_); | 
|  | 310 | CHECK(!owner_); | 
|  | 311 | owner_ = (uptr)pthread_self(); | 
|  | 312 | } | 
|  | 313 |  | 
|  | 314 | void BlockingMutex::Unlock() { | 
|  | 315 | CHECK(owner_ == (uptr)pthread_self()); | 
|  | 316 | owner_ = 0; | 
|  | 317 | OSSpinLockUnlock((OSSpinLock*)&opaque_storage_); | 
|  | 318 | } | 
|  | 319 |  | 
| Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 320 | }  // namespace __sanitizer | 
|  | 321 |  | 
|  | 322 | #endif  // __APPLE__ |