tsan_fd.cpp revision 360784
1133808Spjd//===-- tsan_fd.cpp -------------------------------------------------------===// 2156878Spjd// 3133808Spjd// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4133808Spjd// See https://llvm.org/LICENSE.txt for license information. 5133808Spjd// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6133808Spjd// 7133808Spjd//===----------------------------------------------------------------------===// 8133808Spjd// 9133808Spjd// This file is a part of ThreadSanitizer (TSan), a race detector. 10133808Spjd// 11133808Spjd//===----------------------------------------------------------------------===// 12133808Spjd 13155174Spjd#include "tsan_fd.h" 14133808Spjd#include "tsan_rtl.h" 15133808Spjd#include <sanitizer_common/sanitizer_atomic.h> 16133808Spjd 17133808Spjdnamespace __tsan { 18133808Spjd 19133808Spjdconst int kTableSizeL1 = 1024; 20133808Spjdconst int kTableSizeL2 = 1024; 21133808Spjdconst int kTableSize = kTableSizeL1 * kTableSizeL2; 22133808Spjd 23133808Spjdstruct FdSync { 24133808Spjd atomic_uint64_t rc; 25133808Spjd}; 26133808Spjd 27133808Spjdstruct FdDesc { 28133808Spjd FdSync *sync; 29133808Spjd int creation_tid; 30133808Spjd u32 creation_stack; 31133808Spjd}; 32133808Spjd 33133808Spjdstruct FdContext { 34133808Spjd atomic_uintptr_t tab[kTableSizeL1]; 35133808Spjd // Addresses used for synchronization. 36133808Spjd FdSync globsync; 37133808Spjd FdSync filesync; 38134136Spjd FdSync socksync; 39134136Spjd u64 connectsync; 40134136Spjd}; 41134136Spjd 42134168Spjdstatic FdContext fdctx; 43139295Spjd 44142727Spjdstatic bool bogusfd(int fd) { 45163888Spjd // Apparently a bogus fd value. 46134136Spjd return fd < 0 || fd >= kTableSize; 47163888Spjd} 48133808Spjd 49133808Spjdstatic FdSync *allocsync(ThreadState *thr, uptr pc) { 50133808Spjd FdSync *s = (FdSync*)user_alloc_internal(thr, pc, sizeof(FdSync), 51133808Spjd kDefaultAlignment, false); 52133808Spjd atomic_store(&s->rc, 1, memory_order_relaxed); 53155546Spjd return s; 54133808Spjd} 55133808Spjd 56133808Spjdstatic FdSync *ref(FdSync *s) { 57133808Spjd if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) 58133808Spjd atomic_fetch_add(&s->rc, 1, memory_order_relaxed); 59134124Spjd return s; 60134168Spjd} 61163888Spjd 62134124Spjdstatic void unref(ThreadState *thr, uptr pc, FdSync *s) { 63134168Spjd if (s && atomic_load(&s->rc, memory_order_relaxed) != (u64)-1) { 64163888Spjd if (atomic_fetch_sub(&s->rc, 1, memory_order_acq_rel) == 1) { 65163888Spjd CHECK_NE(s, &fdctx.globsync); 66133808Spjd CHECK_NE(s, &fdctx.filesync); 67133808Spjd CHECK_NE(s, &fdctx.socksync); 68133808Spjd user_free(thr, pc, s, false); 69133808Spjd } 70133808Spjd } 71133808Spjd} 72133808Spjd 73133808Spjdstatic FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) { 74133808Spjd CHECK_GE(fd, 0); 75133808Spjd CHECK_LT(fd, kTableSize); 76133808Spjd atomic_uintptr_t *pl1 = &fdctx.tab[fd / kTableSizeL2]; 77133808Spjd uptr l1 = atomic_load(pl1, memory_order_consume); 78133808Spjd if (l1 == 0) { 79133808Spjd uptr size = kTableSizeL2 * sizeof(FdDesc); 80133808Spjd // We need this to reside in user memory to properly catch races on it. 81133808Spjd void *p = user_alloc_internal(thr, pc, size, kDefaultAlignment, false); 82133808Spjd internal_memset(p, 0, size); 83133808Spjd MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size); 84133808Spjd if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel)) 85133808Spjd l1 = (uptr)p; 86133808Spjd else 87133808Spjd user_free(thr, pc, p, false); 88133808Spjd } 89133808Spjd FdDesc *fds = reinterpret_cast<FdDesc *>(l1); 90133808Spjd return &fds[fd % kTableSizeL2]; 91133808Spjd} 92133808Spjd 93133808Spjd// pd must be already ref'ed. 94133808Spjdstatic void init(ThreadState *thr, uptr pc, int fd, FdSync *s, 95133808Spjd bool write = true) { 96133808Spjd FdDesc *d = fddesc(thr, pc, fd); 97133808Spjd // As a matter of fact, we don't intercept all close calls. 98134168Spjd // See e.g. libc __res_iclose(). 99134168Spjd if (d->sync) { 100134168Spjd unref(thr, pc, d->sync); 101134168Spjd d->sync = 0; 102134168Spjd } 103133808Spjd if (flags()->io_sync == 0) { 104133808Spjd unref(thr, pc, s); 105133808Spjd } else if (flags()->io_sync == 1) { 106134168Spjd d->sync = s; 107134168Spjd } else if (flags()->io_sync == 2) { 108134168Spjd unref(thr, pc, s); 109134168Spjd d->sync = &fdctx.globsync; 110133808Spjd } 111133808Spjd d->creation_tid = thr->tid; 112133808Spjd d->creation_stack = CurrentStackId(thr, pc); 113133808Spjd if (write) { 114133808Spjd // To catch races between fd usage and open. 115133808Spjd MemoryRangeImitateWrite(thr, pc, (uptr)d, 8); 116156612Spjd } else { 117156612Spjd // See the dup-related comment in FdClose. 118133808Spjd MemoryRead(thr, pc, (uptr)d, kSizeLog8); 119156612Spjd } 120156612Spjd} 121156612Spjd 122156612Spjdvoid FdInit() { 123133808Spjd atomic_store(&fdctx.globsync.rc, (u64)-1, memory_order_relaxed); 124133808Spjd atomic_store(&fdctx.filesync.rc, (u64)-1, memory_order_relaxed); 125133808Spjd atomic_store(&fdctx.socksync.rc, (u64)-1, memory_order_relaxed); 126133808Spjd} 127133808Spjd 128133808Spjdvoid FdOnFork(ThreadState *thr, uptr pc) { 129133808Spjd // On fork() we need to reset all fd's, because the child is going 130133808Spjd // close all them, and that will cause races between previous read/write 131133808Spjd // and the close. 132133808Spjd for (int l1 = 0; l1 < kTableSizeL1; l1++) { 133133808Spjd FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed); 134133808Spjd if (tab == 0) 135133808Spjd break; 136133808Spjd for (int l2 = 0; l2 < kTableSizeL2; l2++) { 137133808Spjd FdDesc *d = &tab[l2]; 138133808Spjd MemoryResetRange(thr, pc, (uptr)d, 8); 139133808Spjd } 140133808Spjd } 141133808Spjd} 142133808Spjd 143133808Spjdbool FdLocation(uptr addr, int *fd, int *tid, u32 *stack) { 144133808Spjd for (int l1 = 0; l1 < kTableSizeL1; l1++) { 145133808Spjd FdDesc *tab = (FdDesc*)atomic_load(&fdctx.tab[l1], memory_order_relaxed); 146139295Spjd if (tab == 0) 147133808Spjd break; 148133808Spjd if (addr >= (uptr)tab && addr < (uptr)(tab + kTableSizeL2)) { 149133808Spjd int l2 = (addr - (uptr)tab) / sizeof(FdDesc); 150133808Spjd FdDesc *d = &tab[l2]; 151133808Spjd *fd = l1 * kTableSizeL1 + l2; 152133808Spjd *tid = d->creation_tid; 153133808Spjd *stack = d->creation_stack; 154133808Spjd return true; 155133808Spjd } 156133808Spjd } 157133808Spjd return false; 158133808Spjd} 159133808Spjd 160133808Spjdvoid FdAcquire(ThreadState *thr, uptr pc, int fd) { 161133808Spjd if (bogusfd(fd)) 162133808Spjd return; 163133808Spjd FdDesc *d = fddesc(thr, pc, fd); 164133808Spjd FdSync *s = d->sync; 165133808Spjd DPrintf("#%d: FdAcquire(%d) -> %p\n", thr->tid, fd, s); 166157630Spjd MemoryRead(thr, pc, (uptr)d, kSizeLog8); 167133808Spjd if (s) 168133808Spjd Acquire(thr, pc, (uptr)s); 169133808Spjd} 170133808Spjd 171133808Spjdvoid FdRelease(ThreadState *thr, uptr pc, int fd) { 172139295Spjd if (bogusfd(fd)) 173139671Spjd return; 174139295Spjd FdDesc *d = fddesc(thr, pc, fd); 175139671Spjd FdSync *s = d->sync; 176133808Spjd DPrintf("#%d: FdRelease(%d) -> %p\n", thr->tid, fd, s); 177156612Spjd MemoryRead(thr, pc, (uptr)d, kSizeLog8); 178156612Spjd if (s) 179156612Spjd Release(thr, pc, (uptr)s); 180156612Spjd} 181156612Spjd 182156612Spjdvoid FdAccess(ThreadState *thr, uptr pc, int fd) { 183156612Spjd DPrintf("#%d: FdAccess(%d)\n", thr->tid, fd); 184156612Spjd if (bogusfd(fd)) 185156612Spjd return; 186200821Smav FdDesc *d = fddesc(thr, pc, fd); 187200821Smav MemoryRead(thr, pc, (uptr)d, kSizeLog8); 188200821Smav} 189156612Spjd 190156612Spjdvoid FdClose(ThreadState *thr, uptr pc, int fd, bool write) { 191156612Spjd DPrintf("#%d: FdClose(%d)\n", thr->tid, fd); 192156612Spjd if (bogusfd(fd)) 193156612Spjd return; 194156612Spjd FdDesc *d = fddesc(thr, pc, fd); 195156612Spjd if (write) { 196133808Spjd // To catch races between fd usage and close. 197133808Spjd MemoryWrite(thr, pc, (uptr)d, kSizeLog8); 198133808Spjd } else { 199133808Spjd // This path is used only by dup2/dup3 calls. 200133808Spjd // We do read instead of write because there is a number of legitimate 201133808Spjd // cases where write would lead to false positives: 202133808Spjd // 1. Some software dups a closed pipe in place of a socket before closing 203133808Spjd // the socket (to prevent races actually). 204133808Spjd // 2. Some daemons dup /dev/null in place of stdin/stdout. 205133808Spjd // On the other hand we have not seen cases when write here catches real 206133808Spjd // bugs. 207156612Spjd MemoryRead(thr, pc, (uptr)d, kSizeLog8); 208133808Spjd } 209133808Spjd // We need to clear it, because if we do not intercept any call out there 210133808Spjd // that creates fd, we will hit false postives. 211156612Spjd MemoryResetRange(thr, pc, (uptr)d, 8); 212156612Spjd unref(thr, pc, d->sync); 213156612Spjd d->sync = 0; 214156612Spjd d->creation_tid = 0; 215156612Spjd d->creation_stack = 0; 216156612Spjd} 217156612Spjd 218156612Spjdvoid FdFileCreate(ThreadState *thr, uptr pc, int fd) { 219133808Spjd DPrintf("#%d: FdFileCreate(%d)\n", thr->tid, fd); 220133808Spjd if (bogusfd(fd)) 221133808Spjd return; 222134124Spjd init(thr, pc, fd, &fdctx.filesync); 223133808Spjd} 224133808Spjd 225156612Spjdvoid FdDup(ThreadState *thr, uptr pc, int oldfd, int newfd, bool write) { 226156612Spjd DPrintf("#%d: FdDup(%d, %d)\n", thr->tid, oldfd, newfd); 227156612Spjd if (bogusfd(oldfd) || bogusfd(newfd)) 228156612Spjd return; 229156612Spjd // Ignore the case when user dups not yet connected socket. 230156612Spjd FdDesc *od = fddesc(thr, pc, oldfd); 231156612Spjd MemoryRead(thr, pc, (uptr)od, kSizeLog8); 232133808Spjd FdClose(thr, pc, newfd, write); 233139295Spjd init(thr, pc, newfd, ref(od->sync), write); 234133808Spjd} 235139295Spjd 236133808Spjdvoid FdPipeCreate(ThreadState *thr, uptr pc, int rfd, int wfd) { 237137258Spjd DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr->tid, rfd, wfd); 238155540Spjd FdSync *s = allocsync(thr, pc); 239155540Spjd init(thr, pc, rfd, ref(s)); 240133808Spjd init(thr, pc, wfd, ref(s)); 241133808Spjd unref(thr, pc, s); 242133808Spjd} 243133808Spjd 244133808Spjdvoid FdEventCreate(ThreadState *thr, uptr pc, int fd) { 245148440Spjd DPrintf("#%d: FdEventCreate(%d)\n", thr->tid, fd); 246148440Spjd if (bogusfd(fd)) 247133808Spjd return; 248133808Spjd init(thr, pc, fd, allocsync(thr, pc)); 249133808Spjd} 250133808Spjd 251133808Spjdvoid FdSignalCreate(ThreadState *thr, uptr pc, int fd) { 252157630Spjd DPrintf("#%d: FdSignalCreate(%d)\n", thr->tid, fd); 253157630Spjd if (bogusfd(fd)) 254157630Spjd return; 255157630Spjd init(thr, pc, fd, 0); 256133808Spjd} 257133808Spjd 258139671Spjdvoid FdInotifyCreate(ThreadState *thr, uptr pc, int fd) { 259139671Spjd DPrintf("#%d: FdInotifyCreate(%d)\n", thr->tid, fd); 260139671Spjd if (bogusfd(fd)) 261133808Spjd return; 262133808Spjd init(thr, pc, fd, 0); 263133808Spjd} 264133808Spjd 265133808Spjdvoid FdPollCreate(ThreadState *thr, uptr pc, int fd) { 266133808Spjd DPrintf("#%d: FdPollCreate(%d)\n", thr->tid, fd); 267133808Spjd if (bogusfd(fd)) 268133808Spjd return; 269133808Spjd init(thr, pc, fd, allocsync(thr, pc)); 270133808Spjd} 271133808Spjd 272133808Spjdvoid FdSocketCreate(ThreadState *thr, uptr pc, int fd) { 273133808Spjd DPrintf("#%d: FdSocketCreate(%d)\n", thr->tid, fd); 274133808Spjd if (bogusfd(fd)) 275133808Spjd return; 276139295Spjd // It can be a UDP socket. 277133808Spjd init(thr, pc, fd, &fdctx.socksync); 278133808Spjd} 279133808Spjd 280133808Spjdvoid FdSocketAccept(ThreadState *thr, uptr pc, int fd, int newfd) { 281133808Spjd DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr->tid, fd, newfd); 282133808Spjd if (bogusfd(fd)) 283133808Spjd return; 284142727Spjd // Synchronize connect->accept. 285133808Spjd Acquire(thr, pc, (uptr)&fdctx.connectsync); 286133808Spjd init(thr, pc, newfd, &fdctx.socksync); 287133808Spjd} 288133808Spjd 289133808Spjdvoid FdSocketConnecting(ThreadState *thr, uptr pc, int fd) { 290133808Spjd DPrintf("#%d: FdSocketConnecting(%d)\n", thr->tid, fd); 291133808Spjd if (bogusfd(fd)) 292133808Spjd return; 293133808Spjd // Synchronize connect->accept. 294133808Spjd Release(thr, pc, (uptr)&fdctx.connectsync); 295133808Spjd} 296133808Spjd 297133808Spjdvoid FdSocketConnect(ThreadState *thr, uptr pc, int fd) { 298139295Spjd DPrintf("#%d: FdSocketConnect(%d)\n", thr->tid, fd); 299139295Spjd if (bogusfd(fd)) 300139295Spjd return; 301139295Spjd init(thr, pc, fd, &fdctx.socksync); 302139295Spjd} 303139295Spjd 304139295Spjduptr File2addr(const char *path) { 305139295Spjd (void)path; 306142727Spjd static u64 addr; 307133808Spjd return (uptr)&addr; 308142727Spjd} 309133808Spjd 310142727Spjduptr Dir2addr(const char *path) { 311133808Spjd (void)path; 312133808Spjd static u64 addr; 313139295Spjd return (uptr)&addr; 314133808Spjd} 315133808Spjd 316133808Spjd} // namespace __tsan 317133808Spjd