tsan_fd.cc 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. //===-- tsan_fd.cc --------------------------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // This file is a part of ThreadSanitizer (TSan), a race detector.
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #include "tsan_fd.h"
  12. #include "tsan_rtl.h"
  13. #include <sanitizer_common/sanitizer_atomic.h>
  14. namespace __tsan {
  15. const int kTableSizeL1 = 1024;
  16. const int kTableSizeL2 = 1024;
  17. const int kTableSize = kTableSizeL1 * kTableSizeL2;
  18. struct FdSync {
  19. atomic_uint64_t rc;
  20. };
  21. struct FdDesc {
  22. FdSync *sync;
  23. int creation_tid;
  24. u32 creation_stack;
  25. };
  26. struct FdContext {
  27. atomic_uintptr_t tab[kTableSizeL1];
  28. // Addresses used for synchronization.
  29. FdSync globsync;
  30. FdSync filesync;
  31. FdSync socksync;
  32. u64 connectsync;
  33. };
  34. static FdContext fdctx;
  35. static bool bogusfd(int fd) {
  36. // Apparently a bogus fd value.
  37. return fd < 0 || fd >= kTableSize;
  38. }
  39. static FdSync *allocsync(ThreadState *thr, uptr pc) {
  40. FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
  41. false);
  42. atomic_store(&s->rc, 1, memory_order_relaxed);
  43. return s;
  44. }
  45. static FdSync *ref(FdSync *s) {
  46. if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1)
  47. atomic_fetch_add(&s->rc, 1, memory_order_relaxed);
  48. return s;
  49. }
  50. static void unref(ThreadState *thr, uptr pc, FdSync *s) {
  51. if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) {
  52. if (atomic_fetch_sub(&s->rc, 1, memory_order_acq_rel) == 1) {
  53. CHECK_NE(s, &fdctx.globsync);
  54. CHECK_NE(s, &fdctx.filesync);
  55. CHECK_NE(s, &fdctx.socksync);
  56. user_free(thr, pc, s, false);
  57. }
  58. }
  59. }
  60. static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
  61. CHECK_GE(fd, 0);
  62. CHECK_LT(fd, kTableSize);
  63. atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2];
  64. uptr l1 = atomic_load(pl1, memory_order_consume);
  65. if (l1 == 0) {
  66. uptr size = kTableSizeL2 * sizeof(FdDesc);
  67. // We need this to reside in user memory to properly catch races on it.
  68. void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
  69. internal_memset(p, 0, size);
  70. MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
  71. if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
  72. l1 = (uptr)p;
  73. else
  74. user_free(thr, pc, p, false);
  75. }
  76. return &((FdDesc*)l1)[fd % kTableSizeL2]; // NOLINT
  77. }
  78. // pd must be already ref'ed.
  79. static void init(ThreadState *thr, uptr pc, int fd, FdSync *s) {
  80. FdDesc *d = fddesc(thr, pc, fd);
  81. // As a matter of fact, we don't intercept all close calls.
  82. // See e.g. libc __res_iclose().
  83. if (d->sync) {
  84. unref(thr, pc, d->sync);
  85. d->sync = 0;
  86. }
  87. if (flags()->io_sync == 0) {
  88. unref(thr, pc, s);
  89. } else if (flags()->io_sync == 1) {
  90. d->sync = s;
  91. } else if (flags()->io_sync == 2) {
  92. unref(thr, pc, s);
  93. d->sync = &fdctx.globsync;
  94. }
  95. d->creation_tid = thr->tid;
  96. d->creation_stack = CurrentStackId(thr, pc);
  97. // To catch races between fd usage and open.
  98. MemoryRangeImitateWrite(thr, pc, (uptr)d, 8);
  99. }
  100. void FdInit() {
  101. atomic_store(&fdctx.globsync.rc, (u64)-1, memory_order_relaxed);
  102. atomic_store(&fdctx.filesync.rc, (u64)-1, memory_order_relaxed);
  103. atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed);
  104. }
  105. void FdOnFork(ThreadState *thr, uptr pc) {
  106. // On fork() we need to reset all fd's, because the child is going
  107. // close all them, and that will cause races between previous read/write
  108. // and the close.
  109. for (int l1 = 0; l1 < kTableSizeL1; l1++) {
  110. FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
  111. if (tab == 0)
  112. break;
  113. for (int l2 = 0; l2 < kTableSizeL2; l2++) {
  114. FdDesc *d = &tab[l2];
  115. MemoryResetRange(thr, pc, (uptr)d, 8);
  116. }
  117. }
  118. }
  119. bool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) {
  120. for (int l1 = 0; l1 < kTableSizeL1; l1++) {
  121. FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed);
  122. if (tab == 0)
  123. break;
  124. if (addr >= (uptr)tab && addr < (uptr)(tab + kTableSizeL2)) {
  125. int l2 = (addr - (uptr)tab) / sizeof(FdDesc);
  126. FdDesc *d = &tab[l2];
  127. *fd = l1 * kTableSizeL1 + l2;
  128. *tid = d->creation_tid;
  129. *stack = d->creation_stack;
  130. return true;
  131. }
  132. }
  133. return false;
  134. }
  135. void FdAcquire(ThreadState *thr, uptr pc, int fd) {
  136. if (bogusfd(fd))
  137. return;
  138. FdDesc *d = fddesc(thr, pc, fd);
  139. FdSync *s = d->sync;
  140. DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s);
  141. MemoryRead(thr, pc, (uptr)d, kSizeLog8);
  142. if (s)
  143. Acquire(thr, pc, (uptr)s);
  144. }
  145. void FdRelease(ThreadState *thr, uptr pc, int fd) {
  146. if (bogusfd(fd))
  147. return;
  148. FdDesc *d = fddesc(thr, pc, fd);
  149. FdSync *s = d->sync;
  150. DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s);
  151. MemoryRead(thr, pc, (uptr)d, kSizeLog8);
  152. if (s)
  153. Release(thr, pc, (uptr)s);
  154. }
  155. void FdAccess(ThreadState *thr, uptr pc, int fd) {
  156. DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd);
  157. if (bogusfd(fd))
  158. return;
  159. FdDesc *d = fddesc(thr, pc, fd);
  160. MemoryRead(thr, pc, (uptr)d, kSizeLog8);
  161. }
  162. void FdClose(ThreadState *thr, uptr pc, int fd) {
  163. DPrintf("#%d: FdClose(%d)\n", thr->tid, fd);
  164. if (bogusfd(fd))
  165. return;
  166. FdDesc *d = fddesc(thr, pc, fd);
  167. // To catch races between fd usage and close.
  168. MemoryWrite(thr, pc, (uptr)d, kSizeLog8);
  169. // We need to clear it, because if we do not intercept any call out there
  170. // that creates fd, we will hit false postives.
  171. MemoryResetRange(thr, pc, (uptr)d, 8);
  172. unref(thr, pc, d->sync);
  173. d->sync = 0;
  174. d->creation_tid = 0;
  175. d->creation_stack = 0;
  176. }
  177. void FdFileCreate(ThreadState *thr, uptr pc, int fd) {
  178. DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd);
  179. if (bogusfd(fd))
  180. return;
  181. init(thr, pc, fd, &fdctx.filesync);
  182. }
  183. void FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd) {
  184. DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd);
  185. if (bogusfd(oldfd) || bogusfd(newfd))
  186. return;
  187. // Ignore the case when user dups not yet connected socket.
  188. FdDesc *od = fddesc(thr, pc, oldfd);
  189. MemoryRead(thr, pc, (uptr)od, kSizeLog8);
  190. FdClose(thr, pc, newfd);
  191. init(thr, pc, newfd, ref(od->sync));
  192. }
  193. void FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) {
  194. DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd);
  195. FdSync *s = allocsync(thr, pc);
  196. init(thr, pc, rfd, ref(s));
  197. init(thr, pc, wfd, ref(s));
  198. unref(thr, pc, s);
  199. }
  200. void FdEventCreate(ThreadState *thr, uptr pc, int fd) {
  201. DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd);
  202. if (bogusfd(fd))
  203. return;
  204. init(thr, pc, fd, allocsync(thr, pc));
  205. }
  206. void FdSignalCreate(ThreadState *thr, uptr pc, int fd) {
  207. DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd);
  208. if (bogusfd(fd))
  209. return;
  210. init(thr, pc, fd, 0);
  211. }
  212. void FdInotifyCreate(ThreadState *thr, uptr pc, int fd) {
  213. DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd);
  214. if (bogusfd(fd))
  215. return;
  216. init(thr, pc, fd, 0);
  217. }
  218. void FdPollCreate(ThreadState *thr, uptr pc, int fd) {
  219. DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd);
  220. if (bogusfd(fd))
  221. return;
  222. init(thr, pc, fd, allocsync(thr, pc));
  223. }
  224. void FdSocketCreate(ThreadState *thr, uptr pc, int fd) {
  225. DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd);
  226. if (bogusfd(fd))
  227. return;
  228. // It can be a UDP socket.
  229. init(thr, pc, fd, &fdctx.socksync);
  230. }
  231. void FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) {
  232. DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd);
  233. if (bogusfd(fd))
  234. return;
  235. // Synchronize connect->accept.
  236. Acquire(thr, pc, (uptr)&fdctx.connectsync);
  237. init(thr, pc, newfd, &fdctx.socksync);
  238. }
  239. void FdSocketConnecting(ThreadState *thr, uptr pc, int fd) {
  240. DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd);
  241. if (bogusfd(fd))
  242. return;
  243. // Synchronize connect->accept.
  244. Release(thr, pc, (uptr)&fdctx.connectsync);
  245. }
  246. void FdSocketConnect(ThreadState *thr, uptr pc, int fd) {
  247. DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd);
  248. if (bogusfd(fd))
  249. return;
  250. init(thr, pc, fd, &fdctx.socksync);
  251. }
  252. uptr File2addr(const char *path) {
  253. (void)path;
  254. static u64 addr;
  255. return (uptr)&addr;
  256. }
  257. uptr Dir2addr(const char *path) {
  258. (void)path;
  259. static u64 addr;
  260. return (uptr)&addr;
  261. }
  262. } // namespace __tsan