1 //===-- tsan_fd.cc --------------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 //===----------------------------------------------------------------------===//
14 #include <sanitizer_common/sanitizer_atomic.h>
18 const int kTableSizeL1
= 1024;
19 const int kTableSizeL2
= 1024;
20 const int kTableSize
= kTableSizeL1
* kTableSizeL2
;
33 atomic_uintptr_t tab
[kTableSizeL1
];
34 // Addresses used for synchronization.
41 static FdContext fdctx
;
43 static bool bogusfd(int fd
) {
44 // Apparently a bogus fd value.
45 return fd
< 0 || fd
>= kTableSize
;
48 static FdSync
*allocsync(ThreadState
*thr
, uptr pc
) {
49 FdSync
*s
= (FdSync
*)user_alloc(thr
, pc
, sizeof(FdSync
));
50 atomic_store(&s
->rc
, 1, memory_order_relaxed
);
54 static FdSync
*ref(FdSync
*s
) {
55 if (s
&& atomic_load(&s
->rc
, memory_order_relaxed
) != (u64
)-1)
56 atomic_fetch_add(&s
->rc
, 1, memory_order_relaxed
);
60 static void unref(ThreadState
*thr
, uptr pc
, FdSync
*s
) {
61 if (s
&& atomic_load(&s
->rc
, memory_order_relaxed
) != (u64
)-1) {
62 if (atomic_fetch_sub(&s
->rc
, 1, memory_order_acq_rel
) == 1) {
63 CHECK_NE(s
, &fdctx
.globsync
);
64 CHECK_NE(s
, &fdctx
.filesync
);
65 CHECK_NE(s
, &fdctx
.socksync
);
66 user_free(thr
, pc
, s
);
71 static FdDesc
*fddesc(ThreadState
*thr
, uptr pc
, int fd
) {
73 CHECK_LT(fd
, kTableSize
);
74 atomic_uintptr_t
*pl1
= &fdctx
.tab
[fd
/ kTableSizeL2
];
75 uptr l1
= atomic_load(pl1
, memory_order_consume
);
77 uptr size
= kTableSizeL2
* sizeof(FdDesc
);
78 // We need this to reside in user memory to properly catch races on it.
79 void *p
= user_alloc(thr
, pc
, size
);
80 internal_memset(p
, 0, size
);
81 MemoryResetRange(thr
, (uptr
)&fddesc
, (uptr
)p
, size
);
82 if (atomic_compare_exchange_strong(pl1
, &l1
, (uptr
)p
, memory_order_acq_rel
))
85 user_free(thr
, pc
, p
);
87 return &((FdDesc
*)l1
)[fd
% kTableSizeL2
]; // NOLINT
90 // pd must be already ref'ed.
91 static void init(ThreadState
*thr
, uptr pc
, int fd
, FdSync
*s
) {
92 FdDesc
*d
= fddesc(thr
, pc
, fd
);
93 // As a matter of fact, we don't intercept all close calls.
94 // See e.g. libc __res_iclose().
96 unref(thr
, pc
, d
->sync
);
99 if (flags()->io_sync
== 0) {
101 } else if (flags()->io_sync
== 1) {
103 } else if (flags()->io_sync
== 2) {
105 d
->sync
= &fdctx
.globsync
;
107 d
->creation_tid
= thr
->tid
;
108 d
->creation_stack
= CurrentStackId(thr
, pc
);
109 // To catch races between fd usage and open.
110 MemoryRangeImitateWrite(thr
, pc
, (uptr
)d
, 8);
114 atomic_store(&fdctx
.globsync
.rc
, (u64
)-1, memory_order_relaxed
);
115 atomic_store(&fdctx
.filesync
.rc
, (u64
)-1, memory_order_relaxed
);
116 atomic_store(&fdctx
.socksync
.rc
, (u64
)-1, memory_order_relaxed
);
119 void FdOnFork(ThreadState
*thr
, uptr pc
) {
120 // On fork() we need to reset all fd's, because the child is going
121 // close all them, and that will cause races between previous read/write
123 for (int l1
= 0; l1
< kTableSizeL1
; l1
++) {
124 FdDesc
*tab
= (FdDesc
*)atomic_load(&fdctx
.tab
[l1
], memory_order_relaxed
);
127 for (int l2
= 0; l2
< kTableSizeL2
; l2
++) {
128 FdDesc
*d
= &tab
[l2
];
129 MemoryResetRange(thr
, pc
, (uptr
)d
, 8);
134 bool FdLocation(uptr addr
, int *fd
, int *tid
, u32
*stack
) {
135 for (int l1
= 0; l1
< kTableSizeL1
; l1
++) {
136 FdDesc
*tab
= (FdDesc
*)atomic_load(&fdctx
.tab
[l1
], memory_order_relaxed
);
139 if (addr
>= (uptr
)tab
&& addr
< (uptr
)(tab
+ kTableSizeL2
)) {
140 int l2
= (addr
- (uptr
)tab
) / sizeof(FdDesc
);
141 FdDesc
*d
= &tab
[l2
];
142 *fd
= l1
* kTableSizeL1
+ l2
;
143 *tid
= d
->creation_tid
;
144 *stack
= d
->creation_stack
;
151 void FdAcquire(ThreadState
*thr
, uptr pc
, int fd
) {
154 FdDesc
*d
= fddesc(thr
, pc
, fd
);
156 DPrintf("#%d: FdAcquire(%d) -> %p\n", thr
->tid
, fd
, s
);
157 MemoryRead(thr
, pc
, (uptr
)d
, kSizeLog8
);
159 Acquire(thr
, pc
, (uptr
)s
);
162 void FdRelease(ThreadState
*thr
, uptr pc
, int fd
) {
165 FdDesc
*d
= fddesc(thr
, pc
, fd
);
167 DPrintf("#%d: FdRelease(%d) -> %p\n", thr
->tid
, fd
, s
);
168 MemoryRead(thr
, pc
, (uptr
)d
, kSizeLog8
);
170 Release(thr
, pc
, (uptr
)s
);
173 void FdAccess(ThreadState
*thr
, uptr pc
, int fd
) {
174 DPrintf("#%d: FdAccess(%d)\n", thr
->tid
, fd
);
177 FdDesc
*d
= fddesc(thr
, pc
, fd
);
178 MemoryRead(thr
, pc
, (uptr
)d
, kSizeLog8
);
181 void FdClose(ThreadState
*thr
, uptr pc
, int fd
) {
182 DPrintf("#%d: FdClose(%d)\n", thr
->tid
, fd
);
185 FdDesc
*d
= fddesc(thr
, pc
, fd
);
186 // To catch races between fd usage and close.
187 MemoryWrite(thr
, pc
, (uptr
)d
, kSizeLog8
);
188 // We need to clear it, because if we do not intercept any call out there
189 // that creates fd, we will hit false postives.
190 MemoryResetRange(thr
, pc
, (uptr
)d
, 8);
191 unref(thr
, pc
, d
->sync
);
194 d
->creation_stack
= 0;
197 void FdFileCreate(ThreadState
*thr
, uptr pc
, int fd
) {
198 DPrintf("#%d: FdFileCreate(%d)\n", thr
->tid
, fd
);
201 init(thr
, pc
, fd
, &fdctx
.filesync
);
204 void FdDup(ThreadState
*thr
, uptr pc
, int oldfd
, int newfd
) {
205 DPrintf("#%d: FdDup(%d, %d)\n", thr
->tid
, oldfd
, newfd
);
206 if (bogusfd(oldfd
) || bogusfd(newfd
))
208 // Ignore the case when user dups not yet connected socket.
209 FdDesc
*od
= fddesc(thr
, pc
, oldfd
);
210 MemoryRead(thr
, pc
, (uptr
)od
, kSizeLog8
);
211 FdClose(thr
, pc
, newfd
);
212 init(thr
, pc
, newfd
, ref(od
->sync
));
215 void FdPipeCreate(ThreadState
*thr
, uptr pc
, int rfd
, int wfd
) {
216 DPrintf("#%d: FdCreatePipe(%d, %d)\n", thr
->tid
, rfd
, wfd
);
217 FdSync
*s
= allocsync(thr
, pc
);
218 init(thr
, pc
, rfd
, ref(s
));
219 init(thr
, pc
, wfd
, ref(s
));
223 void FdEventCreate(ThreadState
*thr
, uptr pc
, int fd
) {
224 DPrintf("#%d: FdEventCreate(%d)\n", thr
->tid
, fd
);
227 init(thr
, pc
, fd
, allocsync(thr
, pc
));
230 void FdSignalCreate(ThreadState
*thr
, uptr pc
, int fd
) {
231 DPrintf("#%d: FdSignalCreate(%d)\n", thr
->tid
, fd
);
234 init(thr
, pc
, fd
, 0);
237 void FdInotifyCreate(ThreadState
*thr
, uptr pc
, int fd
) {
238 DPrintf("#%d: FdInotifyCreate(%d)\n", thr
->tid
, fd
);
241 init(thr
, pc
, fd
, 0);
244 void FdPollCreate(ThreadState
*thr
, uptr pc
, int fd
) {
245 DPrintf("#%d: FdPollCreate(%d)\n", thr
->tid
, fd
);
248 init(thr
, pc
, fd
, allocsync(thr
, pc
));
251 void FdSocketCreate(ThreadState
*thr
, uptr pc
, int fd
) {
252 DPrintf("#%d: FdSocketCreate(%d)\n", thr
->tid
, fd
);
255 // It can be a UDP socket.
256 init(thr
, pc
, fd
, &fdctx
.socksync
);
259 void FdSocketAccept(ThreadState
*thr
, uptr pc
, int fd
, int newfd
) {
260 DPrintf("#%d: FdSocketAccept(%d, %d)\n", thr
->tid
, fd
, newfd
);
263 // Synchronize connect->accept.
264 Acquire(thr
, pc
, (uptr
)&fdctx
.connectsync
);
265 init(thr
, pc
, newfd
, &fdctx
.socksync
);
268 void FdSocketConnecting(ThreadState
*thr
, uptr pc
, int fd
) {
269 DPrintf("#%d: FdSocketConnecting(%d)\n", thr
->tid
, fd
);
272 // Synchronize connect->accept.
273 Release(thr
, pc
, (uptr
)&fdctx
.connectsync
);
276 void FdSocketConnect(ThreadState
*thr
, uptr pc
, int fd
) {
277 DPrintf("#%d: FdSocketConnect(%d)\n", thr
->tid
, fd
);
280 init(thr
, pc
, fd
, &fdctx
.socksync
);
283 uptr
File2addr(const char *path
) {
289 uptr
Dir2addr(const char *path
) {
295 } // namespace __tsan