xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- dfsan.cpp ---------------------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric //
9*68d75effSDimitry Andric // This file is a part of DataFlowSanitizer.
10*68d75effSDimitry Andric //
11*68d75effSDimitry Andric // This file defines the custom functions listed in done_abilist.txt.
12*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
13*68d75effSDimitry Andric 
14*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
15*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
16*68d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
17*68d75effSDimitry Andric 
18*68d75effSDimitry Andric #include "dfsan/dfsan.h"
19*68d75effSDimitry Andric 
20*68d75effSDimitry Andric #include <arpa/inet.h>
21*68d75effSDimitry Andric #include <assert.h>
22*68d75effSDimitry Andric #include <ctype.h>
23*68d75effSDimitry Andric #include <dlfcn.h>
24*68d75effSDimitry Andric #include <link.h>
25*68d75effSDimitry Andric #include <poll.h>
26*68d75effSDimitry Andric #include <pthread.h>
27*68d75effSDimitry Andric #include <pwd.h>
28*68d75effSDimitry Andric #include <sched.h>
29*68d75effSDimitry Andric #include <signal.h>
30*68d75effSDimitry Andric #include <stdarg.h>
31*68d75effSDimitry Andric #include <stdint.h>
32*68d75effSDimitry Andric #include <stdio.h>
33*68d75effSDimitry Andric #include <stdlib.h>
34*68d75effSDimitry Andric #include <string.h>
35*68d75effSDimitry Andric #include <sys/resource.h>
36*68d75effSDimitry Andric #include <sys/select.h>
37*68d75effSDimitry Andric #include <sys/stat.h>
38*68d75effSDimitry Andric #include <sys/time.h>
39*68d75effSDimitry Andric #include <sys/types.h>
40*68d75effSDimitry Andric #include <time.h>
41*68d75effSDimitry Andric #include <unistd.h>
42*68d75effSDimitry Andric 
43*68d75effSDimitry Andric using namespace __dfsan;
44*68d75effSDimitry Andric 
45*68d75effSDimitry Andric #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
46*68d75effSDimitry Andric   do {                                                                         \
47*68d75effSDimitry Andric     if (f)                                                                     \
48*68d75effSDimitry Andric       f(__VA_ARGS__);                                                          \
49*68d75effSDimitry Andric   } while (false)
50*68d75effSDimitry Andric #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
51*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
52*68d75effSDimitry Andric 
53*68d75effSDimitry Andric extern "C" {
54*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
55*68d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
56*68d75effSDimitry Andric             dfsan_label buf_label, dfsan_label *ret_label) {
57*68d75effSDimitry Andric   int ret = stat(path, buf);
58*68d75effSDimitry Andric   if (ret == 0)
59*68d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
60*68d75effSDimitry Andric   *ret_label = 0;
61*68d75effSDimitry Andric   return ret;
62*68d75effSDimitry Andric }
63*68d75effSDimitry Andric 
64*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
65*68d75effSDimitry Andric                                                dfsan_label fd_label,
66*68d75effSDimitry Andric                                                dfsan_label buf_label,
67*68d75effSDimitry Andric                                                dfsan_label *ret_label) {
68*68d75effSDimitry Andric   int ret = fstat(fd, buf);
69*68d75effSDimitry Andric   if (ret == 0)
70*68d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
71*68d75effSDimitry Andric   *ret_label = 0;
72*68d75effSDimitry Andric   return ret;
73*68d75effSDimitry Andric }
74*68d75effSDimitry Andric 
75*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
76*68d75effSDimitry Andric                                                   dfsan_label s_label,
77*68d75effSDimitry Andric                                                   dfsan_label c_label,
78*68d75effSDimitry Andric                                                   dfsan_label *ret_label) {
79*68d75effSDimitry Andric   for (size_t i = 0;; ++i) {
80*68d75effSDimitry Andric     if (s[i] == c || s[i] == 0) {
81*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
82*68d75effSDimitry Andric         *ret_label = s_label;
83*68d75effSDimitry Andric       } else {
84*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
85*68d75effSDimitry Andric                                  dfsan_union(s_label, c_label));
86*68d75effSDimitry Andric       }
87*68d75effSDimitry Andric       return s[i] == 0 ? nullptr : const_cast<char *>(s+i);
88*68d75effSDimitry Andric     }
89*68d75effSDimitry Andric   }
90*68d75effSDimitry Andric }
91*68d75effSDimitry Andric 
92*68d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
93*68d75effSDimitry Andric                               const void *s1, const void *s2, size_t n,
94*68d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
95*68d75effSDimitry Andric                               dfsan_label n_label)
96*68d75effSDimitry Andric 
97*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
98*68d75effSDimitry Andric                                                 size_t n, dfsan_label s1_label,
99*68d75effSDimitry Andric                                                 dfsan_label s2_label,
100*68d75effSDimitry Andric                                                 dfsan_label n_label,
101*68d75effSDimitry Andric                                                 dfsan_label *ret_label) {
102*68d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
103*68d75effSDimitry Andric                              s1_label, s2_label, n_label);
104*68d75effSDimitry Andric   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
105*68d75effSDimitry Andric   for (size_t i = 0; i != n; ++i) {
106*68d75effSDimitry Andric     if (cs1[i] != cs2[i]) {
107*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
108*68d75effSDimitry Andric         *ret_label = 0;
109*68d75effSDimitry Andric       } else {
110*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
111*68d75effSDimitry Andric                                  dfsan_read_label(cs2, i + 1));
112*68d75effSDimitry Andric       }
113*68d75effSDimitry Andric       return cs1[i] - cs2[i];
114*68d75effSDimitry Andric     }
115*68d75effSDimitry Andric   }
116*68d75effSDimitry Andric 
117*68d75effSDimitry Andric   if (flags().strict_data_dependencies) {
118*68d75effSDimitry Andric     *ret_label = 0;
119*68d75effSDimitry Andric   } else {
120*68d75effSDimitry Andric     *ret_label = dfsan_union(dfsan_read_label(cs1, n),
121*68d75effSDimitry Andric                              dfsan_read_label(cs2, n));
122*68d75effSDimitry Andric   }
123*68d75effSDimitry Andric   return 0;
124*68d75effSDimitry Andric }
125*68d75effSDimitry Andric 
126*68d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
127*68d75effSDimitry Andric                               const char *s1, const char *s2,
128*68d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label)
129*68d75effSDimitry Andric 
130*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
131*68d75effSDimitry Andric                                                 dfsan_label s1_label,
132*68d75effSDimitry Andric                                                 dfsan_label s2_label,
133*68d75effSDimitry Andric                                                 dfsan_label *ret_label) {
134*68d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
135*68d75effSDimitry Andric                              s1_label, s2_label);
136*68d75effSDimitry Andric   for (size_t i = 0;; ++i) {
137*68d75effSDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
138*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
139*68d75effSDimitry Andric         *ret_label = 0;
140*68d75effSDimitry Andric       } else {
141*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
142*68d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
143*68d75effSDimitry Andric       }
144*68d75effSDimitry Andric       return s1[i] - s2[i];
145*68d75effSDimitry Andric     }
146*68d75effSDimitry Andric   }
147*68d75effSDimitry Andric   return 0;
148*68d75effSDimitry Andric }
149*68d75effSDimitry Andric 
150*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
151*68d75effSDimitry Andric __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
152*68d75effSDimitry Andric                   dfsan_label s2_label, dfsan_label *ret_label) {
153*68d75effSDimitry Andric   for (size_t i = 0;; ++i) {
154*68d75effSDimitry Andric     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0) {
155*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
156*68d75effSDimitry Andric         *ret_label = 0;
157*68d75effSDimitry Andric       } else {
158*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
159*68d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
160*68d75effSDimitry Andric       }
161*68d75effSDimitry Andric       return s1[i] - s2[i];
162*68d75effSDimitry Andric     }
163*68d75effSDimitry Andric   }
164*68d75effSDimitry Andric   return 0;
165*68d75effSDimitry Andric }
166*68d75effSDimitry Andric 
167*68d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
168*68d75effSDimitry Andric                               const char *s1, const char *s2, size_t n,
169*68d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
170*68d75effSDimitry Andric                               dfsan_label n_label)
171*68d75effSDimitry Andric 
172*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
173*68d75effSDimitry Andric                                                  size_t n, dfsan_label s1_label,
174*68d75effSDimitry Andric                                                  dfsan_label s2_label,
175*68d75effSDimitry Andric                                                  dfsan_label n_label,
176*68d75effSDimitry Andric                                                  dfsan_label *ret_label) {
177*68d75effSDimitry Andric   if (n == 0) {
178*68d75effSDimitry Andric     *ret_label = 0;
179*68d75effSDimitry Andric     return 0;
180*68d75effSDimitry Andric   }
181*68d75effSDimitry Andric 
182*68d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
183*68d75effSDimitry Andric                              n, s1_label, s2_label, n_label);
184*68d75effSDimitry Andric 
185*68d75effSDimitry Andric   for (size_t i = 0;; ++i) {
186*68d75effSDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
187*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
188*68d75effSDimitry Andric         *ret_label = 0;
189*68d75effSDimitry Andric       } else {
190*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
191*68d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
192*68d75effSDimitry Andric       }
193*68d75effSDimitry Andric       return s1[i] - s2[i];
194*68d75effSDimitry Andric     }
195*68d75effSDimitry Andric   }
196*68d75effSDimitry Andric   return 0;
197*68d75effSDimitry Andric }
198*68d75effSDimitry Andric 
199*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
200*68d75effSDimitry Andric __dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
201*68d75effSDimitry Andric                    dfsan_label s1_label, dfsan_label s2_label,
202*68d75effSDimitry Andric                    dfsan_label n_label, dfsan_label *ret_label) {
203*68d75effSDimitry Andric   if (n == 0) {
204*68d75effSDimitry Andric     *ret_label = 0;
205*68d75effSDimitry Andric     return 0;
206*68d75effSDimitry Andric   }
207*68d75effSDimitry Andric 
208*68d75effSDimitry Andric   for (size_t i = 0;; ++i) {
209*68d75effSDimitry Andric     if (tolower(s1[i]) != tolower(s2[i]) || s1[i] == 0 || s2[i] == 0 ||
210*68d75effSDimitry Andric         i == n - 1) {
211*68d75effSDimitry Andric       if (flags().strict_data_dependencies) {
212*68d75effSDimitry Andric         *ret_label = 0;
213*68d75effSDimitry Andric       } else {
214*68d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
215*68d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
216*68d75effSDimitry Andric       }
217*68d75effSDimitry Andric       return s1[i] - s2[i];
218*68d75effSDimitry Andric     }
219*68d75effSDimitry Andric   }
220*68d75effSDimitry Andric   return 0;
221*68d75effSDimitry Andric }
222*68d75effSDimitry Andric 
223*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
224*68d75effSDimitry Andric                                                   dfsan_label nmemb_label,
225*68d75effSDimitry Andric                                                   dfsan_label size_label,
226*68d75effSDimitry Andric                                                   dfsan_label *ret_label) {
227*68d75effSDimitry Andric   void *p = calloc(nmemb, size);
228*68d75effSDimitry Andric   dfsan_set_label(0, p, nmemb * size);
229*68d75effSDimitry Andric   *ret_label = 0;
230*68d75effSDimitry Andric   return p;
231*68d75effSDimitry Andric }
232*68d75effSDimitry Andric 
233*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t
234*68d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
235*68d75effSDimitry Andric   size_t ret = strlen(s);
236*68d75effSDimitry Andric   if (flags().strict_data_dependencies) {
237*68d75effSDimitry Andric     *ret_label = 0;
238*68d75effSDimitry Andric   } else {
239*68d75effSDimitry Andric     *ret_label = dfsan_read_label(s, ret + 1);
240*68d75effSDimitry Andric   }
241*68d75effSDimitry Andric   return ret;
242*68d75effSDimitry Andric }
243*68d75effSDimitry Andric 
244*68d75effSDimitry Andric 
245*68d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
246*68d75effSDimitry Andric   dfsan_label *sdest = shadow_for(dest);
247*68d75effSDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
248*68d75effSDimitry Andric   internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
249*68d75effSDimitry Andric   return internal_memcpy(dest, src, n);
250*68d75effSDimitry Andric }
251*68d75effSDimitry Andric 
252*68d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
253*68d75effSDimitry Andric   internal_memset(s, c, n);
254*68d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
255*68d75effSDimitry Andric }
256*68d75effSDimitry Andric 
257*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
258*68d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
259*68d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
260*68d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
261*68d75effSDimitry Andric   *ret_label = dest_label;
262*68d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
263*68d75effSDimitry Andric }
264*68d75effSDimitry Andric 
265*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
266*68d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
267*68d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
268*68d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
269*68d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
270*68d75effSDimitry Andric   *ret_label = s_label;
271*68d75effSDimitry Andric   return s;
272*68d75effSDimitry Andric }
273*68d75effSDimitry Andric 
274*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
275*68d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
276*68d75effSDimitry Andric   size_t len = strlen(s);
277*68d75effSDimitry Andric   void *p = malloc(len+1);
278*68d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
279*68d75effSDimitry Andric   *ret_label = 0;
280*68d75effSDimitry Andric   return static_cast<char *>(p);
281*68d75effSDimitry Andric }
282*68d75effSDimitry Andric 
283*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
284*68d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
285*68d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
286*68d75effSDimitry Andric                dfsan_label *ret_label) {
287*68d75effSDimitry Andric   size_t len = strlen(s2);
288*68d75effSDimitry Andric   if (len < n) {
289*68d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
290*68d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
291*68d75effSDimitry Andric   } else {
292*68d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
293*68d75effSDimitry Andric   }
294*68d75effSDimitry Andric 
295*68d75effSDimitry Andric   *ret_label = s1_label;
296*68d75effSDimitry Andric   return s1;
297*68d75effSDimitry Andric }
298*68d75effSDimitry Andric 
299*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
300*68d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
301*68d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
302*68d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
303*68d75effSDimitry Andric              dfsan_label *ret_label) {
304*68d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
305*68d75effSDimitry Andric   if (ret > 0)
306*68d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
307*68d75effSDimitry Andric   *ret_label = 0;
308*68d75effSDimitry Andric   return ret;
309*68d75effSDimitry Andric }
310*68d75effSDimitry Andric 
311*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
312*68d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
313*68d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
314*68d75effSDimitry Andric              dfsan_label count_label,
315*68d75effSDimitry Andric              dfsan_label *ret_label) {
316*68d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
317*68d75effSDimitry Andric   if (ret > 0)
318*68d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
319*68d75effSDimitry Andric   *ret_label = 0;
320*68d75effSDimitry Andric   return ret;
321*68d75effSDimitry Andric }
322*68d75effSDimitry Andric 
323*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
324*68d75effSDimitry Andric                                                        struct timespec *tp,
325*68d75effSDimitry Andric                                                        dfsan_label clk_id_label,
326*68d75effSDimitry Andric                                                        dfsan_label tp_label,
327*68d75effSDimitry Andric                                                        dfsan_label *ret_label) {
328*68d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
329*68d75effSDimitry Andric   if (ret == 0)
330*68d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
331*68d75effSDimitry Andric   *ret_label = 0;
332*68d75effSDimitry Andric   return ret;
333*68d75effSDimitry Andric }
334*68d75effSDimitry Andric 
335*68d75effSDimitry Andric static void unpoison(const void *ptr, uptr size) {
336*68d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
337*68d75effSDimitry Andric }
338*68d75effSDimitry Andric 
339*68d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
340*68d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
341*68d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
342*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
343*68d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
344*68d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
345*68d75effSDimitry Andric   void *handle = dlopen(filename, flag);
346*68d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
347*68d75effSDimitry Andric   if (map)
348*68d75effSDimitry Andric     ForEachMappedRegion(map, unpoison);
349*68d75effSDimitry Andric   *ret_label = 0;
350*68d75effSDimitry Andric   return handle;
351*68d75effSDimitry Andric }
352*68d75effSDimitry Andric 
353*68d75effSDimitry Andric struct pthread_create_info {
354*68d75effSDimitry Andric   void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
355*68d75effSDimitry Andric   void *start_routine;
356*68d75effSDimitry Andric   void *arg;
357*68d75effSDimitry Andric };
358*68d75effSDimitry Andric 
359*68d75effSDimitry Andric static void *pthread_create_cb(void *p) {
360*68d75effSDimitry Andric   pthread_create_info pci(*(pthread_create_info *)p);
361*68d75effSDimitry Andric   free(p);
362*68d75effSDimitry Andric   dfsan_label ret_label;
363*68d75effSDimitry Andric   return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
364*68d75effSDimitry Andric                                       &ret_label);
365*68d75effSDimitry Andric }
366*68d75effSDimitry Andric 
367*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
368*68d75effSDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
369*68d75effSDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
370*68d75effSDimitry Andric                                       dfsan_label *),
371*68d75effSDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
372*68d75effSDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
373*68d75effSDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label) {
374*68d75effSDimitry Andric   pthread_create_info *pci =
375*68d75effSDimitry Andric       (pthread_create_info *)malloc(sizeof(pthread_create_info));
376*68d75effSDimitry Andric   pci->start_routine_trampoline = start_routine_trampoline;
377*68d75effSDimitry Andric   pci->start_routine = start_routine;
378*68d75effSDimitry Andric   pci->arg = arg;
379*68d75effSDimitry Andric   int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
380*68d75effSDimitry Andric   if (rv != 0)
381*68d75effSDimitry Andric     free(pci);
382*68d75effSDimitry Andric   *ret_label = 0;
383*68d75effSDimitry Andric   return rv;
384*68d75effSDimitry Andric }
385*68d75effSDimitry Andric 
386*68d75effSDimitry Andric struct dl_iterate_phdr_info {
387*68d75effSDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
388*68d75effSDimitry Andric                              size_t size, void *data, dfsan_label info_label,
389*68d75effSDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
390*68d75effSDimitry Andric                              dfsan_label *ret_label);
391*68d75effSDimitry Andric   void *callback;
392*68d75effSDimitry Andric   void *data;
393*68d75effSDimitry Andric };
394*68d75effSDimitry Andric 
395*68d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
396*68d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
397*68d75effSDimitry Andric   dfsan_set_label(0, *info);
398*68d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
399*68d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
400*68d75effSDimitry Andric   dfsan_set_label(
401*68d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
402*68d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
403*68d75effSDimitry Andric   dfsan_label ret_label;
404*68d75effSDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
405*68d75effSDimitry Andric                                    0, &ret_label);
406*68d75effSDimitry Andric }
407*68d75effSDimitry Andric 
408*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
409*68d75effSDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
410*68d75effSDimitry Andric                                size_t size, void *data, dfsan_label info_label,
411*68d75effSDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
412*68d75effSDimitry Andric                                dfsan_label *ret_label),
413*68d75effSDimitry Andric     void *callback, void *data, dfsan_label callback_label,
414*68d75effSDimitry Andric     dfsan_label data_label, dfsan_label *ret_label) {
415*68d75effSDimitry Andric   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
416*68d75effSDimitry Andric   *ret_label = 0;
417*68d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
418*68d75effSDimitry Andric }
419*68d75effSDimitry Andric 
420*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
421*68d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
422*68d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
423*68d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
424*68d75effSDimitry Andric   if (ret) {
425*68d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
426*68d75effSDimitry Andric                     strlen(buf) + 1);
427*68d75effSDimitry Andric     *ret_label = buf_label;
428*68d75effSDimitry Andric   } else {
429*68d75effSDimitry Andric     *ret_label = 0;
430*68d75effSDimitry Andric   }
431*68d75effSDimitry Andric   return ret;
432*68d75effSDimitry Andric }
433*68d75effSDimitry Andric 
434*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
435*68d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
436*68d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
437*68d75effSDimitry Andric                    dfsan_label *ret_label) {
438*68d75effSDimitry Andric   char *ret = fgets(s, size, stream);
439*68d75effSDimitry Andric   if (ret) {
440*68d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
441*68d75effSDimitry Andric     *ret_label = s_label;
442*68d75effSDimitry Andric   } else {
443*68d75effSDimitry Andric     *ret_label = 0;
444*68d75effSDimitry Andric   }
445*68d75effSDimitry Andric   return ret;
446*68d75effSDimitry Andric }
447*68d75effSDimitry Andric 
448*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
449*68d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
450*68d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
451*68d75effSDimitry Andric   char *ret = getcwd(buf, size);
452*68d75effSDimitry Andric   if (ret) {
453*68d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
454*68d75effSDimitry Andric     *ret_label = buf_label;
455*68d75effSDimitry Andric   } else {
456*68d75effSDimitry Andric     *ret_label = 0;
457*68d75effSDimitry Andric   }
458*68d75effSDimitry Andric   return ret;
459*68d75effSDimitry Andric }
460*68d75effSDimitry Andric 
461*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
462*68d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
463*68d75effSDimitry Andric   char *ret = get_current_dir_name();
464*68d75effSDimitry Andric   if (ret) {
465*68d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
466*68d75effSDimitry Andric   }
467*68d75effSDimitry Andric   *ret_label = 0;
468*68d75effSDimitry Andric   return ret;
469*68d75effSDimitry Andric }
470*68d75effSDimitry Andric 
471*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
472*68d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
473*68d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
474*68d75effSDimitry Andric   int ret = gethostname(name, len);
475*68d75effSDimitry Andric   if (ret == 0) {
476*68d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
477*68d75effSDimitry Andric   }
478*68d75effSDimitry Andric   *ret_label = 0;
479*68d75effSDimitry Andric   return ret;
480*68d75effSDimitry Andric }
481*68d75effSDimitry Andric 
482*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
483*68d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
484*68d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
485*68d75effSDimitry Andric                      dfsan_label *ret_label) {
486*68d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
487*68d75effSDimitry Andric   if (ret == 0) {
488*68d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
489*68d75effSDimitry Andric   }
490*68d75effSDimitry Andric   *ret_label = 0;
491*68d75effSDimitry Andric   return ret;
492*68d75effSDimitry Andric }
493*68d75effSDimitry Andric 
494*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
495*68d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
496*68d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
497*68d75effSDimitry Andric   int ret = getrusage(who, usage);
498*68d75effSDimitry Andric   if (ret == 0) {
499*68d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
500*68d75effSDimitry Andric   }
501*68d75effSDimitry Andric   *ret_label = 0;
502*68d75effSDimitry Andric   return ret;
503*68d75effSDimitry Andric }
504*68d75effSDimitry Andric 
505*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
506*68d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
507*68d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
508*68d75effSDimitry Andric   char *ret = strcpy(dest, src);  // NOLINT
509*68d75effSDimitry Andric   if (ret) {
510*68d75effSDimitry Andric     internal_memcpy(shadow_for(dest), shadow_for(src),
511*68d75effSDimitry Andric                     sizeof(dfsan_label) * (strlen(src) + 1));
512*68d75effSDimitry Andric   }
513*68d75effSDimitry Andric   *ret_label = dst_label;
514*68d75effSDimitry Andric   return ret;
515*68d75effSDimitry Andric }
516*68d75effSDimitry Andric 
517*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
518*68d75effSDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
519*68d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
520*68d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
521*68d75effSDimitry Andric   char *tmp_endptr;
522*68d75effSDimitry Andric   long int ret = strtol(nptr, &tmp_endptr, base);
523*68d75effSDimitry Andric   if (endptr) {
524*68d75effSDimitry Andric     *endptr = tmp_endptr;
525*68d75effSDimitry Andric   }
526*68d75effSDimitry Andric   if (tmp_endptr > nptr) {
527*68d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
528*68d75effSDimitry Andric     *ret_label = dfsan_union(
529*68d75effSDimitry Andric         base_label,
530*68d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
531*68d75effSDimitry Andric   } else {
532*68d75effSDimitry Andric     *ret_label = 0;
533*68d75effSDimitry Andric   }
534*68d75effSDimitry Andric   return ret;
535*68d75effSDimitry Andric }
536*68d75effSDimitry Andric 
537*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
538*68d75effSDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr,
539*68d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
540*68d75effSDimitry Andric                        dfsan_label *ret_label) {
541*68d75effSDimitry Andric   char *tmp_endptr;
542*68d75effSDimitry Andric   double ret = strtod(nptr, &tmp_endptr);
543*68d75effSDimitry Andric   if (endptr) {
544*68d75effSDimitry Andric     *endptr = tmp_endptr;
545*68d75effSDimitry Andric   }
546*68d75effSDimitry Andric   if (tmp_endptr > nptr) {
547*68d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
548*68d75effSDimitry Andric     *ret_label = dfsan_read_label(
549*68d75effSDimitry Andric         nptr,
550*68d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
551*68d75effSDimitry Andric   } else {
552*68d75effSDimitry Andric     *ret_label = 0;
553*68d75effSDimitry Andric   }
554*68d75effSDimitry Andric   return ret;
555*68d75effSDimitry Andric }
556*68d75effSDimitry Andric 
557*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
558*68d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
559*68d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
560*68d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
561*68d75effSDimitry Andric   char *tmp_endptr;
562*68d75effSDimitry Andric   long long int ret = strtoll(nptr, &tmp_endptr, base);
563*68d75effSDimitry Andric   if (endptr) {
564*68d75effSDimitry Andric     *endptr = tmp_endptr;
565*68d75effSDimitry Andric   }
566*68d75effSDimitry Andric   if (tmp_endptr > nptr) {
567*68d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
568*68d75effSDimitry Andric     *ret_label = dfsan_union(
569*68d75effSDimitry Andric         base_label,
570*68d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
571*68d75effSDimitry Andric   } else {
572*68d75effSDimitry Andric     *ret_label = 0;
573*68d75effSDimitry Andric   }
574*68d75effSDimitry Andric   return ret;
575*68d75effSDimitry Andric }
576*68d75effSDimitry Andric 
577*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
578*68d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
579*68d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
580*68d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
581*68d75effSDimitry Andric   char *tmp_endptr;
582*68d75effSDimitry Andric   unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
583*68d75effSDimitry Andric   if (endptr) {
584*68d75effSDimitry Andric     *endptr = tmp_endptr;
585*68d75effSDimitry Andric   }
586*68d75effSDimitry Andric   if (tmp_endptr > nptr) {
587*68d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
588*68d75effSDimitry Andric     *ret_label = dfsan_union(
589*68d75effSDimitry Andric         base_label,
590*68d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
591*68d75effSDimitry Andric   } else {
592*68d75effSDimitry Andric     *ret_label = 0;
593*68d75effSDimitry Andric   }
594*68d75effSDimitry Andric   return ret;
595*68d75effSDimitry Andric }
596*68d75effSDimitry Andric 
597*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
598*68d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
599*68d75effSDimitry Andric                                        dfsan_label nptr_label,
600*68d75effSDimitry Andric                                        int base, dfsan_label endptr_label,
601*68d75effSDimitry Andric                                        dfsan_label base_label,
602*68d75effSDimitry Andric                                        dfsan_label *ret_label) {
603*68d75effSDimitry Andric   char *tmp_endptr;
604*68d75effSDimitry Andric   long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
605*68d75effSDimitry Andric   if (endptr) {
606*68d75effSDimitry Andric     *endptr = tmp_endptr;
607*68d75effSDimitry Andric   }
608*68d75effSDimitry Andric   if (tmp_endptr > nptr) {
609*68d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
610*68d75effSDimitry Andric     *ret_label = dfsan_union(
611*68d75effSDimitry Andric         base_label,
612*68d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
613*68d75effSDimitry Andric   } else {
614*68d75effSDimitry Andric     *ret_label = 0;
615*68d75effSDimitry Andric   }
616*68d75effSDimitry Andric   return ret;
617*68d75effSDimitry Andric }
618*68d75effSDimitry Andric 
619*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
620*68d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
621*68d75effSDimitry Andric   time_t ret = time(t);
622*68d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
623*68d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
624*68d75effSDimitry Andric   }
625*68d75effSDimitry Andric   *ret_label = 0;
626*68d75effSDimitry Andric   return ret;
627*68d75effSDimitry Andric }
628*68d75effSDimitry Andric 
629*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
630*68d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
631*68d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
632*68d75effSDimitry Andric                      dfsan_label *ret_label) {
633*68d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
634*68d75effSDimitry Andric   if (ret == 1) {
635*68d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
636*68d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
637*68d75effSDimitry Andric   }
638*68d75effSDimitry Andric   *ret_label = 0;
639*68d75effSDimitry Andric   return ret;
640*68d75effSDimitry Andric }
641*68d75effSDimitry Andric 
642*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
643*68d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
644*68d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
645*68d75effSDimitry Andric                               dfsan_label *ret_label) {
646*68d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
647*68d75effSDimitry Andric   if (ret) {
648*68d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
649*68d75effSDimitry Andric                     sizeof(struct tm));
650*68d75effSDimitry Andric     *ret_label = result_label;
651*68d75effSDimitry Andric   } else {
652*68d75effSDimitry Andric     *ret_label = 0;
653*68d75effSDimitry Andric   }
654*68d75effSDimitry Andric   return ret;
655*68d75effSDimitry Andric }
656*68d75effSDimitry Andric 
657*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
658*68d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
659*68d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
660*68d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
661*68d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
662*68d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
663*68d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
664*68d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
665*68d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
666*68d75effSDimitry Andric   if (ret == 0) {
667*68d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
668*68d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
669*68d75effSDimitry Andric   }
670*68d75effSDimitry Andric   *ret_label = 0;
671*68d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
672*68d75effSDimitry Andric   return ret;
673*68d75effSDimitry Andric }
674*68d75effSDimitry Andric 
675*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
676*68d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
677*68d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
678*68d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
679*68d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
680*68d75effSDimitry Andric   if (ret >= 0) {
681*68d75effSDimitry Andric     for (; nfds > 0; --nfds) {
682*68d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
683*68d75effSDimitry Andric     }
684*68d75effSDimitry Andric   }
685*68d75effSDimitry Andric   *ret_label = 0;
686*68d75effSDimitry Andric   return ret;
687*68d75effSDimitry Andric }
688*68d75effSDimitry Andric 
689*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
690*68d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
691*68d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
692*68d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
693*68d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
694*68d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
695*68d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
696*68d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
697*68d75effSDimitry Andric   // undefined.
698*68d75effSDimitry Andric   if (readfds) {
699*68d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
700*68d75effSDimitry Andric   }
701*68d75effSDimitry Andric   if (writefds) {
702*68d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
703*68d75effSDimitry Andric   }
704*68d75effSDimitry Andric   if (exceptfds) {
705*68d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
706*68d75effSDimitry Andric   }
707*68d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
708*68d75effSDimitry Andric   *ret_label = 0;
709*68d75effSDimitry Andric   return ret;
710*68d75effSDimitry Andric }
711*68d75effSDimitry Andric 
712*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
713*68d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
714*68d75effSDimitry Andric                              dfsan_label pid_label,
715*68d75effSDimitry Andric                              dfsan_label cpusetsize_label,
716*68d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
717*68d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
718*68d75effSDimitry Andric   if (ret == 0) {
719*68d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
720*68d75effSDimitry Andric   }
721*68d75effSDimitry Andric   *ret_label = 0;
722*68d75effSDimitry Andric   return ret;
723*68d75effSDimitry Andric }
724*68d75effSDimitry Andric 
725*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
726*68d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
727*68d75effSDimitry Andric                        dfsan_label *ret_label) {
728*68d75effSDimitry Andric   int ret = sigemptyset(set);
729*68d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
730*68d75effSDimitry Andric   return ret;
731*68d75effSDimitry Andric }
732*68d75effSDimitry Andric 
733*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
734*68d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
735*68d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
736*68d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
737*68d75effSDimitry Andric                      dfsan_label *ret_label) {
738*68d75effSDimitry Andric   int ret = sigaction(signum, act, oldact);
739*68d75effSDimitry Andric   if (oldact) {
740*68d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
741*68d75effSDimitry Andric   }
742*68d75effSDimitry Andric   *ret_label = 0;
743*68d75effSDimitry Andric   return ret;
744*68d75effSDimitry Andric }
745*68d75effSDimitry Andric 
746*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
747*68d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
748*68d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
749*68d75effSDimitry Andric                         dfsan_label *ret_label) {
750*68d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
751*68d75effSDimitry Andric   if (tv) {
752*68d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
753*68d75effSDimitry Andric   }
754*68d75effSDimitry Andric   if (tz) {
755*68d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
756*68d75effSDimitry Andric   }
757*68d75effSDimitry Andric   *ret_label = 0;
758*68d75effSDimitry Andric   return ret;
759*68d75effSDimitry Andric }
760*68d75effSDimitry Andric 
761*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
762*68d75effSDimitry Andric                                                   dfsan_label s_label,
763*68d75effSDimitry Andric                                                   dfsan_label c_label,
764*68d75effSDimitry Andric                                                   dfsan_label n_label,
765*68d75effSDimitry Andric                                                   dfsan_label *ret_label) {
766*68d75effSDimitry Andric   void *ret = memchr(s, c, n);
767*68d75effSDimitry Andric   if (flags().strict_data_dependencies) {
768*68d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
769*68d75effSDimitry Andric   } else {
770*68d75effSDimitry Andric     size_t len =
771*68d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
772*68d75effSDimitry Andric             : n;
773*68d75effSDimitry Andric     *ret_label =
774*68d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
775*68d75effSDimitry Andric   }
776*68d75effSDimitry Andric   return ret;
777*68d75effSDimitry Andric }
778*68d75effSDimitry Andric 
779*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
780*68d75effSDimitry Andric                                                    dfsan_label s_label,
781*68d75effSDimitry Andric                                                    dfsan_label c_label,
782*68d75effSDimitry Andric                                                    dfsan_label *ret_label) {
783*68d75effSDimitry Andric   char *ret = strrchr(s, c);
784*68d75effSDimitry Andric   if (flags().strict_data_dependencies) {
785*68d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
786*68d75effSDimitry Andric   } else {
787*68d75effSDimitry Andric     *ret_label =
788*68d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
789*68d75effSDimitry Andric                     dfsan_union(s_label, c_label));
790*68d75effSDimitry Andric   }
791*68d75effSDimitry Andric 
792*68d75effSDimitry Andric   return ret;
793*68d75effSDimitry Andric }
794*68d75effSDimitry Andric 
795*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
796*68d75effSDimitry Andric                                                   dfsan_label haystack_label,
797*68d75effSDimitry Andric                                                   dfsan_label needle_label,
798*68d75effSDimitry Andric                                                   dfsan_label *ret_label) {
799*68d75effSDimitry Andric   char *ret = strstr(haystack, needle);
800*68d75effSDimitry Andric   if (flags().strict_data_dependencies) {
801*68d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
802*68d75effSDimitry Andric   } else {
803*68d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
804*68d75effSDimitry Andric     *ret_label =
805*68d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
806*68d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
807*68d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
808*68d75effSDimitry Andric   }
809*68d75effSDimitry Andric 
810*68d75effSDimitry Andric   return ret;
811*68d75effSDimitry Andric }
812*68d75effSDimitry Andric 
813*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
814*68d75effSDimitry Andric                                                    struct timespec *rem,
815*68d75effSDimitry Andric                                                    dfsan_label req_label,
816*68d75effSDimitry Andric                                                    dfsan_label rem_label,
817*68d75effSDimitry Andric                                                    dfsan_label *ret_label) {
818*68d75effSDimitry Andric   int ret = nanosleep(req, rem);
819*68d75effSDimitry Andric   *ret_label = 0;
820*68d75effSDimitry Andric   if (ret == -1) {
821*68d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
822*68d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
823*68d75effSDimitry Andric   }
824*68d75effSDimitry Andric   return ret;
825*68d75effSDimitry Andric }
826*68d75effSDimitry Andric 
827*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
828*68d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
829*68d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
830*68d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
831*68d75effSDimitry Andric                   dfsan_label *ret_label) {
832*68d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
833*68d75effSDimitry Andric   *ret_label = 0;
834*68d75effSDimitry Andric   if (ret == 0) {
835*68d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
836*68d75effSDimitry Andric   }
837*68d75effSDimitry Andric   return ret;
838*68d75effSDimitry Andric }
839*68d75effSDimitry Andric 
840*68d75effSDimitry Andric // Type of the trampoline function passed to the custom version of
841*68d75effSDimitry Andric // dfsan_set_write_callback.
842*68d75effSDimitry Andric typedef void (*write_trampoline_t)(
843*68d75effSDimitry Andric     void *callback,
844*68d75effSDimitry Andric     int fd, const void *buf, ssize_t count,
845*68d75effSDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
846*68d75effSDimitry Andric 
847*68d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
848*68d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
849*68d75effSDimitry Andric static struct {
850*68d75effSDimitry Andric   write_trampoline_t write_callback_trampoline = nullptr;
851*68d75effSDimitry Andric   void *write_callback = nullptr;
852*68d75effSDimitry Andric } write_callback_info;
853*68d75effSDimitry Andric 
854*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void
855*68d75effSDimitry Andric __dfsw_dfsan_set_write_callback(
856*68d75effSDimitry Andric     write_trampoline_t write_callback_trampoline,
857*68d75effSDimitry Andric     void *write_callback,
858*68d75effSDimitry Andric     dfsan_label write_callback_label,
859*68d75effSDimitry Andric     dfsan_label *ret_label) {
860*68d75effSDimitry Andric   write_callback_info.write_callback_trampoline = write_callback_trampoline;
861*68d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
862*68d75effSDimitry Andric }
863*68d75effSDimitry Andric 
864*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
865*68d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
866*68d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
867*68d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
868*68d75effSDimitry Andric   if (write_callback_info.write_callback) {
869*68d75effSDimitry Andric     write_callback_info.write_callback_trampoline(
870*68d75effSDimitry Andric         write_callback_info.write_callback,
871*68d75effSDimitry Andric         fd, buf, count,
872*68d75effSDimitry Andric         fd_label, buf_label, count_label);
873*68d75effSDimitry Andric   }
874*68d75effSDimitry Andric 
875*68d75effSDimitry Andric   *ret_label = 0;
876*68d75effSDimitry Andric   return write(fd, buf, count);
877*68d75effSDimitry Andric }
878*68d75effSDimitry Andric } // namespace __dfsan
879*68d75effSDimitry Andric 
880*68d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
881*68d75effSDimitry Andric typedef int dfsan_label_va;
882*68d75effSDimitry Andric 
883*68d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
884*68d75effSDimitry Andric // '%.3f').
885*68d75effSDimitry Andric struct Formatter {
886*68d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
887*68d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
888*68d75effSDimitry Andric         width(-1) {}
889*68d75effSDimitry Andric 
890*68d75effSDimitry Andric   int format() {
891*68d75effSDimitry Andric     char *tmp_fmt = build_format_string();
892*68d75effSDimitry Andric     int retval =
893*68d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
894*68d75effSDimitry Andric                  0 /* used only to avoid warnings */);
895*68d75effSDimitry Andric     free(tmp_fmt);
896*68d75effSDimitry Andric     return retval;
897*68d75effSDimitry Andric   }
898*68d75effSDimitry Andric 
899*68d75effSDimitry Andric   template <typename T> int format(T arg) {
900*68d75effSDimitry Andric     char *tmp_fmt = build_format_string();
901*68d75effSDimitry Andric     int retval;
902*68d75effSDimitry Andric     if (width >= 0) {
903*68d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
904*68d75effSDimitry Andric                         tmp_fmt, width, arg);
905*68d75effSDimitry Andric     } else {
906*68d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
907*68d75effSDimitry Andric                         tmp_fmt, arg);
908*68d75effSDimitry Andric     }
909*68d75effSDimitry Andric     free(tmp_fmt);
910*68d75effSDimitry Andric     return retval;
911*68d75effSDimitry Andric   }
912*68d75effSDimitry Andric 
913*68d75effSDimitry Andric   char *build_format_string() {
914*68d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
915*68d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
916*68d75effSDimitry Andric     assert(new_fmt);
917*68d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
918*68d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
919*68d75effSDimitry Andric     return new_fmt;
920*68d75effSDimitry Andric   }
921*68d75effSDimitry Andric 
922*68d75effSDimitry Andric   char *str_cur() { return str + str_off; }
923*68d75effSDimitry Andric 
924*68d75effSDimitry Andric   size_t num_written_bytes(int retval) {
925*68d75effSDimitry Andric     if (retval < 0) {
926*68d75effSDimitry Andric       return 0;
927*68d75effSDimitry Andric     }
928*68d75effSDimitry Andric 
929*68d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
930*68d75effSDimitry Andric     if (num_avail == 0) {
931*68d75effSDimitry Andric       return 0;
932*68d75effSDimitry Andric     }
933*68d75effSDimitry Andric 
934*68d75effSDimitry Andric     size_t num_written = retval;
935*68d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
936*68d75effSDimitry Andric     // truncated.
937*68d75effSDimitry Andric     if (num_written >= num_avail) {
938*68d75effSDimitry Andric       num_written -= num_avail;
939*68d75effSDimitry Andric     }
940*68d75effSDimitry Andric 
941*68d75effSDimitry Andric     return num_written;
942*68d75effSDimitry Andric   }
943*68d75effSDimitry Andric 
944*68d75effSDimitry Andric   char *str;
945*68d75effSDimitry Andric   size_t str_off;
946*68d75effSDimitry Andric   size_t size;
947*68d75effSDimitry Andric   const char *fmt_start;
948*68d75effSDimitry Andric   const char *fmt_cur;
949*68d75effSDimitry Andric   int width;
950*68d75effSDimitry Andric };
951*68d75effSDimitry Andric 
952*68d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
953*68d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
954*68d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
955*68d75effSDimitry Andric // the return value vsnprintf would return.
956*68d75effSDimitry Andric //
957*68d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
958*68d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
959*68d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
960*68d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
961*68d75effSDimitry Andric // propagate labels more precisely.
962*68d75effSDimitry Andric //
963*68d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
964*68d75effSDimitry Andric // positional arguments.
965*68d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
966*68d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
967*68d75effSDimitry Andric                          va_list ap) {
968*68d75effSDimitry Andric   Formatter formatter(str, fmt, size);
969*68d75effSDimitry Andric 
970*68d75effSDimitry Andric   while (*formatter.fmt_cur) {
971*68d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
972*68d75effSDimitry Andric     formatter.width = -1;
973*68d75effSDimitry Andric     int retval = 0;
974*68d75effSDimitry Andric 
975*68d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
976*68d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
977*68d75effSDimitry Andric       // of the string.
978*68d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
979*68d75effSDimitry Andric            ++formatter.fmt_cur) {}
980*68d75effSDimitry Andric       retval = formatter.format();
981*68d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
982*68d75effSDimitry Andric                       formatter.num_written_bytes(retval));
983*68d75effSDimitry Andric     } else {
984*68d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
985*68d75effSDimitry Andric       // specifier or the end of the string.
986*68d75effSDimitry Andric       bool end_fmt = false;
987*68d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
988*68d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
989*68d75effSDimitry Andric         case 'd':
990*68d75effSDimitry Andric         case 'i':
991*68d75effSDimitry Andric         case 'o':
992*68d75effSDimitry Andric         case 'u':
993*68d75effSDimitry Andric         case 'x':
994*68d75effSDimitry Andric         case 'X':
995*68d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
996*68d75effSDimitry Andric           case 'h':
997*68d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
998*68d75effSDimitry Andric             // an int).
999*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
1000*68d75effSDimitry Andric             break;
1001*68d75effSDimitry Andric           case 'l':
1002*68d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
1003*68d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
1004*68d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
1005*68d75effSDimitry Andric             } else {
1006*68d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
1007*68d75effSDimitry Andric             }
1008*68d75effSDimitry Andric             break;
1009*68d75effSDimitry Andric           case 'q':
1010*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
1011*68d75effSDimitry Andric             break;
1012*68d75effSDimitry Andric           case 'j':
1013*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
1014*68d75effSDimitry Andric             break;
1015*68d75effSDimitry Andric           case 'z':
1016*68d75effSDimitry Andric           case 't':
1017*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
1018*68d75effSDimitry Andric             break;
1019*68d75effSDimitry Andric           default:
1020*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
1021*68d75effSDimitry Andric           }
1022*68d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
1023*68d75effSDimitry Andric                           formatter.num_written_bytes(retval));
1024*68d75effSDimitry Andric           end_fmt = true;
1025*68d75effSDimitry Andric           break;
1026*68d75effSDimitry Andric 
1027*68d75effSDimitry Andric         case 'a':
1028*68d75effSDimitry Andric         case 'A':
1029*68d75effSDimitry Andric         case 'e':
1030*68d75effSDimitry Andric         case 'E':
1031*68d75effSDimitry Andric         case 'f':
1032*68d75effSDimitry Andric         case 'F':
1033*68d75effSDimitry Andric         case 'g':
1034*68d75effSDimitry Andric         case 'G':
1035*68d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
1036*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
1037*68d75effSDimitry Andric           } else {
1038*68d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
1039*68d75effSDimitry Andric           }
1040*68d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
1041*68d75effSDimitry Andric                           formatter.num_written_bytes(retval));
1042*68d75effSDimitry Andric           end_fmt = true;
1043*68d75effSDimitry Andric           break;
1044*68d75effSDimitry Andric 
1045*68d75effSDimitry Andric         case 'c':
1046*68d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
1047*68d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
1048*68d75effSDimitry Andric                           formatter.num_written_bytes(retval));
1049*68d75effSDimitry Andric           end_fmt = true;
1050*68d75effSDimitry Andric           break;
1051*68d75effSDimitry Andric 
1052*68d75effSDimitry Andric         case 's': {
1053*68d75effSDimitry Andric           char *arg = va_arg(ap, char *);
1054*68d75effSDimitry Andric           retval = formatter.format(arg);
1055*68d75effSDimitry Andric           va_labels++;
1056*68d75effSDimitry Andric           internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
1057*68d75effSDimitry Andric                           sizeof(dfsan_label) *
1058*68d75effSDimitry Andric                               formatter.num_written_bytes(retval));
1059*68d75effSDimitry Andric           end_fmt = true;
1060*68d75effSDimitry Andric           break;
1061*68d75effSDimitry Andric         }
1062*68d75effSDimitry Andric 
1063*68d75effSDimitry Andric         case 'p':
1064*68d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
1065*68d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
1066*68d75effSDimitry Andric                           formatter.num_written_bytes(retval));
1067*68d75effSDimitry Andric           end_fmt = true;
1068*68d75effSDimitry Andric           break;
1069*68d75effSDimitry Andric 
1070*68d75effSDimitry Andric         case 'n': {
1071*68d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
1072*68d75effSDimitry Andric           *ptr = (int)formatter.str_off;
1073*68d75effSDimitry Andric           va_labels++;
1074*68d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
1075*68d75effSDimitry Andric           end_fmt = true;
1076*68d75effSDimitry Andric           break;
1077*68d75effSDimitry Andric         }
1078*68d75effSDimitry Andric 
1079*68d75effSDimitry Andric         case '%':
1080*68d75effSDimitry Andric           retval = formatter.format();
1081*68d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
1082*68d75effSDimitry Andric                           formatter.num_written_bytes(retval));
1083*68d75effSDimitry Andric           end_fmt = true;
1084*68d75effSDimitry Andric           break;
1085*68d75effSDimitry Andric 
1086*68d75effSDimitry Andric         case '*':
1087*68d75effSDimitry Andric           formatter.width = va_arg(ap, int);
1088*68d75effSDimitry Andric           va_labels++;
1089*68d75effSDimitry Andric           break;
1090*68d75effSDimitry Andric 
1091*68d75effSDimitry Andric         default:
1092*68d75effSDimitry Andric           break;
1093*68d75effSDimitry Andric         }
1094*68d75effSDimitry Andric       }
1095*68d75effSDimitry Andric     }
1096*68d75effSDimitry Andric 
1097*68d75effSDimitry Andric     if (retval < 0) {
1098*68d75effSDimitry Andric       return retval;
1099*68d75effSDimitry Andric     }
1100*68d75effSDimitry Andric 
1101*68d75effSDimitry Andric     formatter.fmt_cur++;
1102*68d75effSDimitry Andric     formatter.str_off += retval;
1103*68d75effSDimitry Andric   }
1104*68d75effSDimitry Andric 
1105*68d75effSDimitry Andric   *ret_label = 0;
1106*68d75effSDimitry Andric 
1107*68d75effSDimitry Andric   // Number of bytes written in total.
1108*68d75effSDimitry Andric   return formatter.str_off;
1109*68d75effSDimitry Andric }
1110*68d75effSDimitry Andric 
1111*68d75effSDimitry Andric extern "C" {
1112*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1113*68d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
1114*68d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
1115*68d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
1116*68d75effSDimitry Andric   va_list ap;
1117*68d75effSDimitry Andric   va_start(ap, ret_label);
1118*68d75effSDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
1119*68d75effSDimitry Andric   va_end(ap);
1120*68d75effSDimitry Andric   return ret;
1121*68d75effSDimitry Andric }
1122*68d75effSDimitry Andric 
1123*68d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
1124*68d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
1125*68d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
1126*68d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
1127*68d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
1128*68d75effSDimitry Andric   va_list ap;
1129*68d75effSDimitry Andric   va_start(ap, ret_label);
1130*68d75effSDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
1131*68d75effSDimitry Andric   va_end(ap);
1132*68d75effSDimitry Andric   return ret;
1133*68d75effSDimitry Andric }
1134*68d75effSDimitry Andric 
1135*68d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
1136*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
1137*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
1138*68d75effSDimitry Andric                              u32 *) {}
1139*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
1140*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
1141*68d75effSDimitry Andric 
1142*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
1143*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
1144*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
1145*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
1146*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
1147*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
1148*68d75effSDimitry Andric                              void) {}
1149*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
1150*68d75effSDimitry Andric                              void) {}
1151*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
1152*68d75effSDimitry Andric                              void) {}
1153*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
1154*68d75effSDimitry Andric                              void) {}
1155*68d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
1156*68d75effSDimitry Andric }  // extern "C"
1157