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