xref: /freebsd/contrib/llvm-project/compiler-rt/lib/dfsan/dfsan_custom.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
168d75effSDimitry Andric //===-- dfsan.cpp ---------------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of DataFlowSanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // This file defines the custom functions listed in done_abilist.txt.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
1568d75effSDimitry Andric #include "sanitizer_common/sanitizer_internal_defs.h"
1668d75effSDimitry Andric #include "sanitizer_common/sanitizer_linux.h"
1768d75effSDimitry Andric 
1868d75effSDimitry Andric #include "dfsan/dfsan.h"
1968d75effSDimitry Andric 
2068d75effSDimitry Andric #include <arpa/inet.h>
2168d75effSDimitry Andric #include <assert.h>
2268d75effSDimitry Andric #include <ctype.h>
2368d75effSDimitry Andric #include <dlfcn.h>
2468d75effSDimitry Andric #include <link.h>
2568d75effSDimitry Andric #include <poll.h>
2668d75effSDimitry Andric #include <pthread.h>
2768d75effSDimitry Andric #include <pwd.h>
2868d75effSDimitry Andric #include <sched.h>
2968d75effSDimitry Andric #include <signal.h>
3068d75effSDimitry Andric #include <stdarg.h>
3168d75effSDimitry Andric #include <stdint.h>
3268d75effSDimitry Andric #include <stdio.h>
3368d75effSDimitry Andric #include <stdlib.h>
3468d75effSDimitry Andric #include <string.h>
3568d75effSDimitry Andric #include <sys/resource.h>
3668d75effSDimitry Andric #include <sys/select.h>
3768d75effSDimitry Andric #include <sys/stat.h>
3868d75effSDimitry Andric #include <sys/time.h>
3968d75effSDimitry Andric #include <sys/types.h>
4068d75effSDimitry Andric #include <time.h>
4168d75effSDimitry Andric #include <unistd.h>
4268d75effSDimitry Andric 
4368d75effSDimitry Andric using namespace __dfsan;
4468d75effSDimitry Andric 
4568d75effSDimitry Andric #define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)                                     \
4668d75effSDimitry Andric   do {                                                                         \
4768d75effSDimitry Andric     if (f)                                                                     \
4868d75effSDimitry Andric       f(__VA_ARGS__);                                                          \
4968d75effSDimitry Andric   } while (false)
5068d75effSDimitry Andric #define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
5168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__);
5268d75effSDimitry Andric 
5368d75effSDimitry Andric extern "C" {
5468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
5568d75effSDimitry Andric __dfsw_stat(const char *path, struct stat *buf, dfsan_label path_label,
5668d75effSDimitry Andric             dfsan_label buf_label, dfsan_label *ret_label) {
5768d75effSDimitry Andric   int ret = stat(path, buf);
5868d75effSDimitry Andric   if (ret == 0)
5968d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
6068d75effSDimitry Andric   *ret_label = 0;
6168d75effSDimitry Andric   return ret;
6268d75effSDimitry Andric }
6368d75effSDimitry Andric 
6468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_fstat(int fd, struct stat *buf,
6568d75effSDimitry Andric                                                dfsan_label fd_label,
6668d75effSDimitry Andric                                                dfsan_label buf_label,
6768d75effSDimitry Andric                                                dfsan_label *ret_label) {
6868d75effSDimitry Andric   int ret = fstat(fd, buf);
6968d75effSDimitry Andric   if (ret == 0)
7068d75effSDimitry Andric     dfsan_set_label(0, buf, sizeof(struct stat));
7168d75effSDimitry Andric   *ret_label = 0;
7268d75effSDimitry Andric   return ret;
7368d75effSDimitry Andric }
7468d75effSDimitry Andric 
7568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strchr(const char *s, int c,
7668d75effSDimitry Andric                                                   dfsan_label s_label,
7768d75effSDimitry Andric                                                   dfsan_label c_label,
7868d75effSDimitry Andric                                                   dfsan_label *ret_label) {
7968d75effSDimitry Andric   for (size_t i = 0;; ++i) {
8068d75effSDimitry Andric     if (s[i] == c || s[i] == 0) {
8168d75effSDimitry Andric       if (flags().strict_data_dependencies) {
8268d75effSDimitry Andric         *ret_label = s_label;
8368d75effSDimitry Andric       } else {
8468d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s, i + 1),
8568d75effSDimitry Andric                                  dfsan_union(s_label, c_label));
8668d75effSDimitry Andric       }
87*5ffd83dbSDimitry Andric 
88*5ffd83dbSDimitry Andric       // If s[i] is the \0 at the end of the string, and \0 is not the
89*5ffd83dbSDimitry Andric       // character we are searching for, then return null.
90*5ffd83dbSDimitry Andric       if (s[i] == 0 && c != 0) {
91*5ffd83dbSDimitry Andric         return nullptr;
92*5ffd83dbSDimitry Andric       }
93*5ffd83dbSDimitry Andric       return const_cast<char *>(s + i);
9468d75effSDimitry Andric     }
9568d75effSDimitry Andric   }
9668d75effSDimitry Andric }
9768d75effSDimitry Andric 
9868d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, uptr caller_pc,
9968d75effSDimitry Andric                               const void *s1, const void *s2, size_t n,
10068d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
10168d75effSDimitry Andric                               dfsan_label n_label)
10268d75effSDimitry Andric 
10368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_memcmp(const void *s1, const void *s2,
10468d75effSDimitry Andric                                                 size_t n, dfsan_label s1_label,
10568d75effSDimitry Andric                                                 dfsan_label s2_label,
10668d75effSDimitry Andric                                                 dfsan_label n_label,
10768d75effSDimitry Andric                                                 dfsan_label *ret_label) {
10868d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_memcmp, GET_CALLER_PC(), s1, s2, n,
10968d75effSDimitry Andric                              s1_label, s2_label, n_label);
11068d75effSDimitry Andric   const char *cs1 = (const char *) s1, *cs2 = (const char *) s2;
11168d75effSDimitry Andric   for (size_t i = 0; i != n; ++i) {
11268d75effSDimitry Andric     if (cs1[i] != cs2[i]) {
11368d75effSDimitry Andric       if (flags().strict_data_dependencies) {
11468d75effSDimitry Andric         *ret_label = 0;
11568d75effSDimitry Andric       } else {
11668d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(cs1, i + 1),
11768d75effSDimitry Andric                                  dfsan_read_label(cs2, i + 1));
11868d75effSDimitry Andric       }
11968d75effSDimitry Andric       return cs1[i] - cs2[i];
12068d75effSDimitry Andric     }
12168d75effSDimitry Andric   }
12268d75effSDimitry Andric 
12368d75effSDimitry Andric   if (flags().strict_data_dependencies) {
12468d75effSDimitry Andric     *ret_label = 0;
12568d75effSDimitry Andric   } else {
12668d75effSDimitry Andric     *ret_label = dfsan_union(dfsan_read_label(cs1, n),
12768d75effSDimitry Andric                              dfsan_read_label(cs2, n));
12868d75effSDimitry Andric   }
12968d75effSDimitry Andric   return 0;
13068d75effSDimitry Andric }
13168d75effSDimitry Andric 
13268d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, uptr caller_pc,
13368d75effSDimitry Andric                               const char *s1, const char *s2,
13468d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label)
13568d75effSDimitry Andric 
13668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strcmp(const char *s1, const char *s2,
13768d75effSDimitry Andric                                                 dfsan_label s1_label,
13868d75effSDimitry Andric                                                 dfsan_label s2_label,
13968d75effSDimitry Andric                                                 dfsan_label *ret_label) {
14068d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strcmp, GET_CALLER_PC(), s1, s2,
14168d75effSDimitry Andric                              s1_label, s2_label);
14268d75effSDimitry Andric   for (size_t i = 0;; ++i) {
14368d75effSDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0) {
14468d75effSDimitry Andric       if (flags().strict_data_dependencies) {
14568d75effSDimitry Andric         *ret_label = 0;
14668d75effSDimitry Andric       } else {
14768d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
14868d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
14968d75effSDimitry Andric       }
15068d75effSDimitry Andric       return s1[i] - s2[i];
15168d75effSDimitry Andric     }
15268d75effSDimitry Andric   }
15368d75effSDimitry Andric   return 0;
15468d75effSDimitry Andric }
15568d75effSDimitry Andric 
15668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
15768d75effSDimitry Andric __dfsw_strcasecmp(const char *s1, const char *s2, dfsan_label s1_label,
15868d75effSDimitry Andric                   dfsan_label s2_label, dfsan_label *ret_label) {
15968d75effSDimitry Andric   for (size_t i = 0;; ++i) {
160*5ffd83dbSDimitry Andric     char s1_lower = tolower(s1[i]);
161*5ffd83dbSDimitry Andric     char s2_lower = tolower(s2[i]);
162*5ffd83dbSDimitry Andric 
163*5ffd83dbSDimitry Andric     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0) {
16468d75effSDimitry Andric       if (flags().strict_data_dependencies) {
16568d75effSDimitry Andric         *ret_label = 0;
16668d75effSDimitry Andric       } else {
16768d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
16868d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
16968d75effSDimitry Andric       }
170*5ffd83dbSDimitry Andric       return s1_lower - s2_lower;
17168d75effSDimitry Andric     }
17268d75effSDimitry Andric   }
17368d75effSDimitry Andric   return 0;
17468d75effSDimitry Andric }
17568d75effSDimitry Andric 
17668d75effSDimitry Andric DECLARE_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, uptr caller_pc,
17768d75effSDimitry Andric                               const char *s1, const char *s2, size_t n,
17868d75effSDimitry Andric                               dfsan_label s1_label, dfsan_label s2_label,
17968d75effSDimitry Andric                               dfsan_label n_label)
18068d75effSDimitry Andric 
18168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_strncmp(const char *s1, const char *s2,
18268d75effSDimitry Andric                                                  size_t n, dfsan_label s1_label,
18368d75effSDimitry Andric                                                  dfsan_label s2_label,
18468d75effSDimitry Andric                                                  dfsan_label n_label,
18568d75effSDimitry Andric                                                  dfsan_label *ret_label) {
18668d75effSDimitry Andric   if (n == 0) {
18768d75effSDimitry Andric     *ret_label = 0;
18868d75effSDimitry Andric     return 0;
18968d75effSDimitry Andric   }
19068d75effSDimitry Andric 
19168d75effSDimitry Andric   CALL_WEAK_INTERCEPTOR_HOOK(dfsan_weak_hook_strncmp, GET_CALLER_PC(), s1, s2,
19268d75effSDimitry Andric                              n, s1_label, s2_label, n_label);
19368d75effSDimitry Andric 
19468d75effSDimitry Andric   for (size_t i = 0;; ++i) {
19568d75effSDimitry Andric     if (s1[i] != s2[i] || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
19668d75effSDimitry Andric       if (flags().strict_data_dependencies) {
19768d75effSDimitry Andric         *ret_label = 0;
19868d75effSDimitry Andric       } else {
19968d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
20068d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
20168d75effSDimitry Andric       }
20268d75effSDimitry Andric       return s1[i] - s2[i];
20368d75effSDimitry Andric     }
20468d75effSDimitry Andric   }
20568d75effSDimitry Andric   return 0;
20668d75effSDimitry Andric }
20768d75effSDimitry Andric 
20868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
20968d75effSDimitry Andric __dfsw_strncasecmp(const char *s1, const char *s2, size_t n,
21068d75effSDimitry Andric                    dfsan_label s1_label, dfsan_label s2_label,
21168d75effSDimitry Andric                    dfsan_label n_label, dfsan_label *ret_label) {
21268d75effSDimitry Andric   if (n == 0) {
21368d75effSDimitry Andric     *ret_label = 0;
21468d75effSDimitry Andric     return 0;
21568d75effSDimitry Andric   }
21668d75effSDimitry Andric 
21768d75effSDimitry Andric   for (size_t i = 0;; ++i) {
218*5ffd83dbSDimitry Andric     char s1_lower = tolower(s1[i]);
219*5ffd83dbSDimitry Andric     char s2_lower = tolower(s2[i]);
220*5ffd83dbSDimitry Andric 
221*5ffd83dbSDimitry Andric     if (s1_lower != s2_lower || s1[i] == 0 || s2[i] == 0 || i == n - 1) {
22268d75effSDimitry Andric       if (flags().strict_data_dependencies) {
22368d75effSDimitry Andric         *ret_label = 0;
22468d75effSDimitry Andric       } else {
22568d75effSDimitry Andric         *ret_label = dfsan_union(dfsan_read_label(s1, i + 1),
22668d75effSDimitry Andric                                  dfsan_read_label(s2, i + 1));
22768d75effSDimitry Andric       }
228*5ffd83dbSDimitry Andric       return s1_lower - s2_lower;
22968d75effSDimitry Andric     }
23068d75effSDimitry Andric   }
23168d75effSDimitry Andric   return 0;
23268d75effSDimitry Andric }
23368d75effSDimitry Andric 
23468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_calloc(size_t nmemb, size_t size,
23568d75effSDimitry Andric                                                   dfsan_label nmemb_label,
23668d75effSDimitry Andric                                                   dfsan_label size_label,
23768d75effSDimitry Andric                                                   dfsan_label *ret_label) {
23868d75effSDimitry Andric   void *p = calloc(nmemb, size);
23968d75effSDimitry Andric   dfsan_set_label(0, p, nmemb * size);
24068d75effSDimitry Andric   *ret_label = 0;
24168d75effSDimitry Andric   return p;
24268d75effSDimitry Andric }
24368d75effSDimitry Andric 
24468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE size_t
24568d75effSDimitry Andric __dfsw_strlen(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
24668d75effSDimitry Andric   size_t ret = strlen(s);
24768d75effSDimitry Andric   if (flags().strict_data_dependencies) {
24868d75effSDimitry Andric     *ret_label = 0;
24968d75effSDimitry Andric   } else {
25068d75effSDimitry Andric     *ret_label = dfsan_read_label(s, ret + 1);
25168d75effSDimitry Andric   }
25268d75effSDimitry Andric   return ret;
25368d75effSDimitry Andric }
25468d75effSDimitry Andric 
25568d75effSDimitry Andric 
25668d75effSDimitry Andric static void *dfsan_memcpy(void *dest, const void *src, size_t n) {
25768d75effSDimitry Andric   dfsan_label *sdest = shadow_for(dest);
25868d75effSDimitry Andric   const dfsan_label *ssrc = shadow_for(src);
25968d75effSDimitry Andric   internal_memcpy((void *)sdest, (const void *)ssrc, n * sizeof(dfsan_label));
26068d75effSDimitry Andric   return internal_memcpy(dest, src, n);
26168d75effSDimitry Andric }
26268d75effSDimitry Andric 
26368d75effSDimitry Andric static void dfsan_memset(void *s, int c, dfsan_label c_label, size_t n) {
26468d75effSDimitry Andric   internal_memset(s, c, n);
26568d75effSDimitry Andric   dfsan_set_label(c_label, s, n);
26668d75effSDimitry Andric }
26768d75effSDimitry Andric 
26868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
26968d75effSDimitry Andric void *__dfsw_memcpy(void *dest, const void *src, size_t n,
27068d75effSDimitry Andric                     dfsan_label dest_label, dfsan_label src_label,
27168d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
27268d75effSDimitry Andric   *ret_label = dest_label;
27368d75effSDimitry Andric   return dfsan_memcpy(dest, src, n);
27468d75effSDimitry Andric }
27568d75effSDimitry Andric 
27668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
27768d75effSDimitry Andric void *__dfsw_memset(void *s, int c, size_t n,
27868d75effSDimitry Andric                     dfsan_label s_label, dfsan_label c_label,
27968d75effSDimitry Andric                     dfsan_label n_label, dfsan_label *ret_label) {
28068d75effSDimitry Andric   dfsan_memset(s, c, c_label, n);
28168d75effSDimitry Andric   *ret_label = s_label;
28268d75effSDimitry Andric   return s;
28368d75effSDimitry Andric }
28468d75effSDimitry Andric 
28568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
28668d75effSDimitry Andric __dfsw_strdup(const char *s, dfsan_label s_label, dfsan_label *ret_label) {
28768d75effSDimitry Andric   size_t len = strlen(s);
28868d75effSDimitry Andric   void *p = malloc(len+1);
28968d75effSDimitry Andric   dfsan_memcpy(p, s, len+1);
29068d75effSDimitry Andric   *ret_label = 0;
29168d75effSDimitry Andric   return static_cast<char *>(p);
29268d75effSDimitry Andric }
29368d75effSDimitry Andric 
29468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *
29568d75effSDimitry Andric __dfsw_strncpy(char *s1, const char *s2, size_t n, dfsan_label s1_label,
29668d75effSDimitry Andric                dfsan_label s2_label, dfsan_label n_label,
29768d75effSDimitry Andric                dfsan_label *ret_label) {
29868d75effSDimitry Andric   size_t len = strlen(s2);
29968d75effSDimitry Andric   if (len < n) {
30068d75effSDimitry Andric     dfsan_memcpy(s1, s2, len+1);
30168d75effSDimitry Andric     dfsan_memset(s1+len+1, 0, 0, n-len-1);
30268d75effSDimitry Andric   } else {
30368d75effSDimitry Andric     dfsan_memcpy(s1, s2, n);
30468d75effSDimitry Andric   }
30568d75effSDimitry Andric 
30668d75effSDimitry Andric   *ret_label = s1_label;
30768d75effSDimitry Andric   return s1;
30868d75effSDimitry Andric }
30968d75effSDimitry Andric 
31068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
31168d75effSDimitry Andric __dfsw_pread(int fd, void *buf, size_t count, off_t offset,
31268d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
31368d75effSDimitry Andric              dfsan_label count_label, dfsan_label offset_label,
31468d75effSDimitry Andric              dfsan_label *ret_label) {
31568d75effSDimitry Andric   ssize_t ret = pread(fd, buf, count, offset);
31668d75effSDimitry Andric   if (ret > 0)
31768d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
31868d75effSDimitry Andric   *ret_label = 0;
31968d75effSDimitry Andric   return ret;
32068d75effSDimitry Andric }
32168d75effSDimitry Andric 
32268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE ssize_t
32368d75effSDimitry Andric __dfsw_read(int fd, void *buf, size_t count,
32468d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
32568d75effSDimitry Andric              dfsan_label count_label,
32668d75effSDimitry Andric              dfsan_label *ret_label) {
32768d75effSDimitry Andric   ssize_t ret = read(fd, buf, count);
32868d75effSDimitry Andric   if (ret > 0)
32968d75effSDimitry Andric     dfsan_set_label(0, buf, ret);
33068d75effSDimitry Andric   *ret_label = 0;
33168d75effSDimitry Andric   return ret;
33268d75effSDimitry Andric }
33368d75effSDimitry Andric 
33468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_clock_gettime(clockid_t clk_id,
33568d75effSDimitry Andric                                                        struct timespec *tp,
33668d75effSDimitry Andric                                                        dfsan_label clk_id_label,
33768d75effSDimitry Andric                                                        dfsan_label tp_label,
33868d75effSDimitry Andric                                                        dfsan_label *ret_label) {
33968d75effSDimitry Andric   int ret = clock_gettime(clk_id, tp);
34068d75effSDimitry Andric   if (ret == 0)
34168d75effSDimitry Andric     dfsan_set_label(0, tp, sizeof(struct timespec));
34268d75effSDimitry Andric   *ret_label = 0;
34368d75effSDimitry Andric   return ret;
34468d75effSDimitry Andric }
34568d75effSDimitry Andric 
34668d75effSDimitry Andric static void unpoison(const void *ptr, uptr size) {
34768d75effSDimitry Andric   dfsan_set_label(0, const_cast<void *>(ptr), size);
34868d75effSDimitry Andric }
34968d75effSDimitry Andric 
35068d75effSDimitry Andric // dlopen() ultimately calls mmap() down inside the loader, which generally
35168d75effSDimitry Andric // doesn't participate in dynamic symbol resolution.  Therefore we won't
35268d75effSDimitry Andric // intercept its calls to mmap, and we have to hook it here.
35368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *
35468d75effSDimitry Andric __dfsw_dlopen(const char *filename, int flag, dfsan_label filename_label,
35568d75effSDimitry Andric               dfsan_label flag_label, dfsan_label *ret_label) {
35668d75effSDimitry Andric   void *handle = dlopen(filename, flag);
35768d75effSDimitry Andric   link_map *map = GET_LINK_MAP_BY_DLOPEN_HANDLE(handle);
35868d75effSDimitry Andric   if (map)
35968d75effSDimitry Andric     ForEachMappedRegion(map, unpoison);
36068d75effSDimitry Andric   *ret_label = 0;
36168d75effSDimitry Andric   return handle;
36268d75effSDimitry Andric }
36368d75effSDimitry Andric 
36468d75effSDimitry Andric struct pthread_create_info {
36568d75effSDimitry Andric   void *(*start_routine_trampoline)(void *, void *, dfsan_label, dfsan_label *);
36668d75effSDimitry Andric   void *start_routine;
36768d75effSDimitry Andric   void *arg;
36868d75effSDimitry Andric };
36968d75effSDimitry Andric 
37068d75effSDimitry Andric static void *pthread_create_cb(void *p) {
37168d75effSDimitry Andric   pthread_create_info pci(*(pthread_create_info *)p);
37268d75effSDimitry Andric   free(p);
37368d75effSDimitry Andric   dfsan_label ret_label;
37468d75effSDimitry Andric   return pci.start_routine_trampoline(pci.start_routine, pci.arg, 0,
37568d75effSDimitry Andric                                       &ret_label);
37668d75effSDimitry Andric }
37768d75effSDimitry Andric 
37868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_pthread_create(
37968d75effSDimitry Andric     pthread_t *thread, const pthread_attr_t *attr,
38068d75effSDimitry Andric     void *(*start_routine_trampoline)(void *, void *, dfsan_label,
38168d75effSDimitry Andric                                       dfsan_label *),
38268d75effSDimitry Andric     void *start_routine, void *arg, dfsan_label thread_label,
38368d75effSDimitry Andric     dfsan_label attr_label, dfsan_label start_routine_label,
38468d75effSDimitry Andric     dfsan_label arg_label, dfsan_label *ret_label) {
38568d75effSDimitry Andric   pthread_create_info *pci =
38668d75effSDimitry Andric       (pthread_create_info *)malloc(sizeof(pthread_create_info));
38768d75effSDimitry Andric   pci->start_routine_trampoline = start_routine_trampoline;
38868d75effSDimitry Andric   pci->start_routine = start_routine;
38968d75effSDimitry Andric   pci->arg = arg;
39068d75effSDimitry Andric   int rv = pthread_create(thread, attr, pthread_create_cb, (void *)pci);
39168d75effSDimitry Andric   if (rv != 0)
39268d75effSDimitry Andric     free(pci);
39368d75effSDimitry Andric   *ret_label = 0;
39468d75effSDimitry Andric   return rv;
39568d75effSDimitry Andric }
39668d75effSDimitry Andric 
39768d75effSDimitry Andric struct dl_iterate_phdr_info {
39868d75effSDimitry Andric   int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
39968d75effSDimitry Andric                              size_t size, void *data, dfsan_label info_label,
40068d75effSDimitry Andric                              dfsan_label size_label, dfsan_label data_label,
40168d75effSDimitry Andric                              dfsan_label *ret_label);
40268d75effSDimitry Andric   void *callback;
40368d75effSDimitry Andric   void *data;
40468d75effSDimitry Andric };
40568d75effSDimitry Andric 
40668d75effSDimitry Andric int dl_iterate_phdr_cb(struct dl_phdr_info *info, size_t size, void *data) {
40768d75effSDimitry Andric   dl_iterate_phdr_info *dipi = (dl_iterate_phdr_info *)data;
40868d75effSDimitry Andric   dfsan_set_label(0, *info);
40968d75effSDimitry Andric   dfsan_set_label(0, const_cast<char *>(info->dlpi_name),
41068d75effSDimitry Andric                   strlen(info->dlpi_name) + 1);
41168d75effSDimitry Andric   dfsan_set_label(
41268d75effSDimitry Andric       0, const_cast<char *>(reinterpret_cast<const char *>(info->dlpi_phdr)),
41368d75effSDimitry Andric       sizeof(*info->dlpi_phdr) * info->dlpi_phnum);
41468d75effSDimitry Andric   dfsan_label ret_label;
41568d75effSDimitry Andric   return dipi->callback_trampoline(dipi->callback, info, size, dipi->data, 0, 0,
41668d75effSDimitry Andric                                    0, &ret_label);
41768d75effSDimitry Andric }
41868d75effSDimitry Andric 
41968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_dl_iterate_phdr(
42068d75effSDimitry Andric     int (*callback_trampoline)(void *callback, struct dl_phdr_info *info,
42168d75effSDimitry Andric                                size_t size, void *data, dfsan_label info_label,
42268d75effSDimitry Andric                                dfsan_label size_label, dfsan_label data_label,
42368d75effSDimitry Andric                                dfsan_label *ret_label),
42468d75effSDimitry Andric     void *callback, void *data, dfsan_label callback_label,
42568d75effSDimitry Andric     dfsan_label data_label, dfsan_label *ret_label) {
42668d75effSDimitry Andric   dl_iterate_phdr_info dipi = { callback_trampoline, callback, data };
42768d75effSDimitry Andric   *ret_label = 0;
42868d75effSDimitry Andric   return dl_iterate_phdr(dl_iterate_phdr_cb, &dipi);
42968d75effSDimitry Andric }
43068d75effSDimitry Andric 
43168d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
43268d75effSDimitry Andric char *__dfsw_ctime_r(const time_t *timep, char *buf, dfsan_label timep_label,
43368d75effSDimitry Andric                      dfsan_label buf_label, dfsan_label *ret_label) {
43468d75effSDimitry Andric   char *ret = ctime_r(timep, buf);
43568d75effSDimitry Andric   if (ret) {
43668d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), buf,
43768d75effSDimitry Andric                     strlen(buf) + 1);
43868d75effSDimitry Andric     *ret_label = buf_label;
43968d75effSDimitry Andric   } else {
44068d75effSDimitry Andric     *ret_label = 0;
44168d75effSDimitry Andric   }
44268d75effSDimitry Andric   return ret;
44368d75effSDimitry Andric }
44468d75effSDimitry Andric 
44568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
44668d75effSDimitry Andric char *__dfsw_fgets(char *s, int size, FILE *stream, dfsan_label s_label,
44768d75effSDimitry Andric                    dfsan_label size_label, dfsan_label stream_label,
44868d75effSDimitry Andric                    dfsan_label *ret_label) {
44968d75effSDimitry Andric   char *ret = fgets(s, size, stream);
45068d75effSDimitry Andric   if (ret) {
45168d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
45268d75effSDimitry Andric     *ret_label = s_label;
45368d75effSDimitry Andric   } else {
45468d75effSDimitry Andric     *ret_label = 0;
45568d75effSDimitry Andric   }
45668d75effSDimitry Andric   return ret;
45768d75effSDimitry Andric }
45868d75effSDimitry Andric 
45968d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
46068d75effSDimitry Andric char *__dfsw_getcwd(char *buf, size_t size, dfsan_label buf_label,
46168d75effSDimitry Andric                     dfsan_label size_label, dfsan_label *ret_label) {
46268d75effSDimitry Andric   char *ret = getcwd(buf, size);
46368d75effSDimitry Andric   if (ret) {
46468d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
46568d75effSDimitry Andric     *ret_label = buf_label;
46668d75effSDimitry Andric   } else {
46768d75effSDimitry Andric     *ret_label = 0;
46868d75effSDimitry Andric   }
46968d75effSDimitry Andric   return ret;
47068d75effSDimitry Andric }
47168d75effSDimitry Andric 
47268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
47368d75effSDimitry Andric char *__dfsw_get_current_dir_name(dfsan_label *ret_label) {
47468d75effSDimitry Andric   char *ret = get_current_dir_name();
47568d75effSDimitry Andric   if (ret) {
47668d75effSDimitry Andric     dfsan_set_label(0, ret, strlen(ret) + 1);
47768d75effSDimitry Andric   }
47868d75effSDimitry Andric   *ret_label = 0;
47968d75effSDimitry Andric   return ret;
48068d75effSDimitry Andric }
48168d75effSDimitry Andric 
48268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
48368d75effSDimitry Andric int __dfsw_gethostname(char *name, size_t len, dfsan_label name_label,
48468d75effSDimitry Andric                        dfsan_label len_label, dfsan_label *ret_label) {
48568d75effSDimitry Andric   int ret = gethostname(name, len);
48668d75effSDimitry Andric   if (ret == 0) {
48768d75effSDimitry Andric     dfsan_set_label(0, name, strlen(name) + 1);
48868d75effSDimitry Andric   }
48968d75effSDimitry Andric   *ret_label = 0;
49068d75effSDimitry Andric   return ret;
49168d75effSDimitry Andric }
49268d75effSDimitry Andric 
49368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
49468d75effSDimitry Andric int __dfsw_getrlimit(int resource, struct rlimit *rlim,
49568d75effSDimitry Andric                      dfsan_label resource_label, dfsan_label rlim_label,
49668d75effSDimitry Andric                      dfsan_label *ret_label) {
49768d75effSDimitry Andric   int ret = getrlimit(resource, rlim);
49868d75effSDimitry Andric   if (ret == 0) {
49968d75effSDimitry Andric     dfsan_set_label(0, rlim, sizeof(struct rlimit));
50068d75effSDimitry Andric   }
50168d75effSDimitry Andric   *ret_label = 0;
50268d75effSDimitry Andric   return ret;
50368d75effSDimitry Andric }
50468d75effSDimitry Andric 
50568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
50668d75effSDimitry Andric int __dfsw_getrusage(int who, struct rusage *usage, dfsan_label who_label,
50768d75effSDimitry Andric                      dfsan_label usage_label, dfsan_label *ret_label) {
50868d75effSDimitry Andric   int ret = getrusage(who, usage);
50968d75effSDimitry Andric   if (ret == 0) {
51068d75effSDimitry Andric     dfsan_set_label(0, usage, sizeof(struct rusage));
51168d75effSDimitry Andric   }
51268d75effSDimitry Andric   *ret_label = 0;
51368d75effSDimitry Andric   return ret;
51468d75effSDimitry Andric }
51568d75effSDimitry Andric 
51668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
51768d75effSDimitry Andric char *__dfsw_strcpy(char *dest, const char *src, dfsan_label dst_label,
51868d75effSDimitry Andric                     dfsan_label src_label, dfsan_label *ret_label) {
51968d75effSDimitry Andric   char *ret = strcpy(dest, src);  // NOLINT
52068d75effSDimitry Andric   if (ret) {
52168d75effSDimitry Andric     internal_memcpy(shadow_for(dest), shadow_for(src),
52268d75effSDimitry Andric                     sizeof(dfsan_label) * (strlen(src) + 1));
52368d75effSDimitry Andric   }
52468d75effSDimitry Andric   *ret_label = dst_label;
52568d75effSDimitry Andric   return ret;
52668d75effSDimitry Andric }
52768d75effSDimitry Andric 
52868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
52968d75effSDimitry Andric long int __dfsw_strtol(const char *nptr, char **endptr, int base,
53068d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
53168d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
53268d75effSDimitry Andric   char *tmp_endptr;
53368d75effSDimitry Andric   long int ret = strtol(nptr, &tmp_endptr, base);
53468d75effSDimitry Andric   if (endptr) {
53568d75effSDimitry Andric     *endptr = tmp_endptr;
53668d75effSDimitry Andric   }
53768d75effSDimitry Andric   if (tmp_endptr > nptr) {
53868d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
53968d75effSDimitry Andric     *ret_label = dfsan_union(
54068d75effSDimitry Andric         base_label,
54168d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
54268d75effSDimitry Andric   } else {
54368d75effSDimitry Andric     *ret_label = 0;
54468d75effSDimitry Andric   }
54568d75effSDimitry Andric   return ret;
54668d75effSDimitry Andric }
54768d75effSDimitry Andric 
54868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
54968d75effSDimitry Andric double __dfsw_strtod(const char *nptr, char **endptr,
55068d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
55168d75effSDimitry Andric                        dfsan_label *ret_label) {
55268d75effSDimitry Andric   char *tmp_endptr;
55368d75effSDimitry Andric   double ret = strtod(nptr, &tmp_endptr);
55468d75effSDimitry Andric   if (endptr) {
55568d75effSDimitry Andric     *endptr = tmp_endptr;
55668d75effSDimitry Andric   }
55768d75effSDimitry Andric   if (tmp_endptr > nptr) {
55868d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
55968d75effSDimitry Andric     *ret_label = dfsan_read_label(
56068d75effSDimitry Andric         nptr,
56168d75effSDimitry Andric         tmp_endptr - nptr + (*tmp_endptr ? 0 : 1));
56268d75effSDimitry Andric   } else {
56368d75effSDimitry Andric     *ret_label = 0;
56468d75effSDimitry Andric   }
56568d75effSDimitry Andric   return ret;
56668d75effSDimitry Andric }
56768d75effSDimitry Andric 
56868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
56968d75effSDimitry Andric long long int __dfsw_strtoll(const char *nptr, char **endptr, int base,
57068d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
57168d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
57268d75effSDimitry Andric   char *tmp_endptr;
57368d75effSDimitry Andric   long long int ret = strtoll(nptr, &tmp_endptr, base);
57468d75effSDimitry Andric   if (endptr) {
57568d75effSDimitry Andric     *endptr = tmp_endptr;
57668d75effSDimitry Andric   }
57768d75effSDimitry Andric   if (tmp_endptr > nptr) {
57868d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
57968d75effSDimitry Andric     *ret_label = dfsan_union(
58068d75effSDimitry Andric         base_label,
58168d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
58268d75effSDimitry Andric   } else {
58368d75effSDimitry Andric     *ret_label = 0;
58468d75effSDimitry Andric   }
58568d75effSDimitry Andric   return ret;
58668d75effSDimitry Andric }
58768d75effSDimitry Andric 
58868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
58968d75effSDimitry Andric unsigned long int __dfsw_strtoul(const char *nptr, char **endptr, int base,
59068d75effSDimitry Andric                        dfsan_label nptr_label, dfsan_label endptr_label,
59168d75effSDimitry Andric                        dfsan_label base_label, dfsan_label *ret_label) {
59268d75effSDimitry Andric   char *tmp_endptr;
59368d75effSDimitry Andric   unsigned long int ret = strtoul(nptr, &tmp_endptr, base);
59468d75effSDimitry Andric   if (endptr) {
59568d75effSDimitry Andric     *endptr = tmp_endptr;
59668d75effSDimitry Andric   }
59768d75effSDimitry Andric   if (tmp_endptr > nptr) {
59868d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
59968d75effSDimitry Andric     *ret_label = dfsan_union(
60068d75effSDimitry Andric         base_label,
60168d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
60268d75effSDimitry Andric   } else {
60368d75effSDimitry Andric     *ret_label = 0;
60468d75effSDimitry Andric   }
60568d75effSDimitry Andric   return ret;
60668d75effSDimitry Andric }
60768d75effSDimitry Andric 
60868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
60968d75effSDimitry Andric long long unsigned int __dfsw_strtoull(const char *nptr, char **endptr,
61068d75effSDimitry Andric                                        dfsan_label nptr_label,
61168d75effSDimitry Andric                                        int base, dfsan_label endptr_label,
61268d75effSDimitry Andric                                        dfsan_label base_label,
61368d75effSDimitry Andric                                        dfsan_label *ret_label) {
61468d75effSDimitry Andric   char *tmp_endptr;
61568d75effSDimitry Andric   long long unsigned int ret = strtoull(nptr, &tmp_endptr, base);
61668d75effSDimitry Andric   if (endptr) {
61768d75effSDimitry Andric     *endptr = tmp_endptr;
61868d75effSDimitry Andric   }
61968d75effSDimitry Andric   if (tmp_endptr > nptr) {
62068d75effSDimitry Andric     // If *tmp_endptr is '\0' include its label as well.
62168d75effSDimitry Andric     *ret_label = dfsan_union(
62268d75effSDimitry Andric         base_label,
62368d75effSDimitry Andric         dfsan_read_label(nptr, tmp_endptr - nptr + (*tmp_endptr ? 0 : 1)));
62468d75effSDimitry Andric   } else {
62568d75effSDimitry Andric     *ret_label = 0;
62668d75effSDimitry Andric   }
62768d75effSDimitry Andric   return ret;
62868d75effSDimitry Andric }
62968d75effSDimitry Andric 
63068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
63168d75effSDimitry Andric time_t __dfsw_time(time_t *t, dfsan_label t_label, dfsan_label *ret_label) {
63268d75effSDimitry Andric   time_t ret = time(t);
63368d75effSDimitry Andric   if (ret != (time_t) -1 && t) {
63468d75effSDimitry Andric     dfsan_set_label(0, t, sizeof(time_t));
63568d75effSDimitry Andric   }
63668d75effSDimitry Andric   *ret_label = 0;
63768d75effSDimitry Andric   return ret;
63868d75effSDimitry Andric }
63968d75effSDimitry Andric 
64068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
64168d75effSDimitry Andric int __dfsw_inet_pton(int af, const char *src, void *dst, dfsan_label af_label,
64268d75effSDimitry Andric                      dfsan_label src_label, dfsan_label dst_label,
64368d75effSDimitry Andric                      dfsan_label *ret_label) {
64468d75effSDimitry Andric   int ret = inet_pton(af, src, dst);
64568d75effSDimitry Andric   if (ret == 1) {
64668d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(src, strlen(src) + 1), dst,
64768d75effSDimitry Andric                     af == AF_INET ? sizeof(struct in_addr) : sizeof(in6_addr));
64868d75effSDimitry Andric   }
64968d75effSDimitry Andric   *ret_label = 0;
65068d75effSDimitry Andric   return ret;
65168d75effSDimitry Andric }
65268d75effSDimitry Andric 
65368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
65468d75effSDimitry Andric struct tm *__dfsw_localtime_r(const time_t *timep, struct tm *result,
65568d75effSDimitry Andric                               dfsan_label timep_label, dfsan_label result_label,
65668d75effSDimitry Andric                               dfsan_label *ret_label) {
65768d75effSDimitry Andric   struct tm *ret = localtime_r(timep, result);
65868d75effSDimitry Andric   if (ret) {
65968d75effSDimitry Andric     dfsan_set_label(dfsan_read_label(timep, sizeof(time_t)), result,
66068d75effSDimitry Andric                     sizeof(struct tm));
66168d75effSDimitry Andric     *ret_label = result_label;
66268d75effSDimitry Andric   } else {
66368d75effSDimitry Andric     *ret_label = 0;
66468d75effSDimitry Andric   }
66568d75effSDimitry Andric   return ret;
66668d75effSDimitry Andric }
66768d75effSDimitry Andric 
66868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
66968d75effSDimitry Andric int __dfsw_getpwuid_r(id_t uid, struct passwd *pwd,
67068d75effSDimitry Andric                       char *buf, size_t buflen, struct passwd **result,
67168d75effSDimitry Andric                       dfsan_label uid_label, dfsan_label pwd_label,
67268d75effSDimitry Andric                       dfsan_label buf_label, dfsan_label buflen_label,
67368d75effSDimitry Andric                       dfsan_label result_label, dfsan_label *ret_label) {
67468d75effSDimitry Andric   // Store the data in pwd, the strings referenced from pwd in buf, and the
67568d75effSDimitry Andric   // address of pwd in *result.  On failure, NULL is stored in *result.
67668d75effSDimitry Andric   int ret = getpwuid_r(uid, pwd, buf, buflen, result);
67768d75effSDimitry Andric   if (ret == 0) {
67868d75effSDimitry Andric     dfsan_set_label(0, pwd, sizeof(struct passwd));
67968d75effSDimitry Andric     dfsan_set_label(0, buf, strlen(buf) + 1);
68068d75effSDimitry Andric   }
68168d75effSDimitry Andric   *ret_label = 0;
68268d75effSDimitry Andric   dfsan_set_label(0, result, sizeof(struct passwd*));
68368d75effSDimitry Andric   return ret;
68468d75effSDimitry Andric }
68568d75effSDimitry Andric 
68668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
68768d75effSDimitry Andric int __dfsw_poll(struct pollfd *fds, nfds_t nfds, int timeout,
68868d75effSDimitry Andric                 dfsan_label dfs_label, dfsan_label nfds_label,
68968d75effSDimitry Andric                 dfsan_label timeout_label, dfsan_label *ret_label) {
69068d75effSDimitry Andric   int ret = poll(fds, nfds, timeout);
69168d75effSDimitry Andric   if (ret >= 0) {
69268d75effSDimitry Andric     for (; nfds > 0; --nfds) {
69368d75effSDimitry Andric       dfsan_set_label(0, &fds[nfds - 1].revents, sizeof(fds[nfds - 1].revents));
69468d75effSDimitry Andric     }
69568d75effSDimitry Andric   }
69668d75effSDimitry Andric   *ret_label = 0;
69768d75effSDimitry Andric   return ret;
69868d75effSDimitry Andric }
69968d75effSDimitry Andric 
70068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
70168d75effSDimitry Andric int __dfsw_select(int nfds, fd_set *readfds, fd_set *writefds,
70268d75effSDimitry Andric                   fd_set *exceptfds, struct timeval *timeout,
70368d75effSDimitry Andric                   dfsan_label nfds_label, dfsan_label readfds_label,
70468d75effSDimitry Andric                   dfsan_label writefds_label, dfsan_label exceptfds_label,
70568d75effSDimitry Andric                   dfsan_label timeout_label, dfsan_label *ret_label) {
70668d75effSDimitry Andric   int ret = select(nfds, readfds, writefds, exceptfds, timeout);
70768d75effSDimitry Andric   // Clear everything (also on error) since their content is either set or
70868d75effSDimitry Andric   // undefined.
70968d75effSDimitry Andric   if (readfds) {
71068d75effSDimitry Andric     dfsan_set_label(0, readfds, sizeof(fd_set));
71168d75effSDimitry Andric   }
71268d75effSDimitry Andric   if (writefds) {
71368d75effSDimitry Andric     dfsan_set_label(0, writefds, sizeof(fd_set));
71468d75effSDimitry Andric   }
71568d75effSDimitry Andric   if (exceptfds) {
71668d75effSDimitry Andric     dfsan_set_label(0, exceptfds, sizeof(fd_set));
71768d75effSDimitry Andric   }
71868d75effSDimitry Andric   dfsan_set_label(0, timeout, sizeof(struct timeval));
71968d75effSDimitry Andric   *ret_label = 0;
72068d75effSDimitry Andric   return ret;
72168d75effSDimitry Andric }
72268d75effSDimitry Andric 
72368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
72468d75effSDimitry Andric int __dfsw_sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask,
72568d75effSDimitry Andric                              dfsan_label pid_label,
72668d75effSDimitry Andric                              dfsan_label cpusetsize_label,
72768d75effSDimitry Andric                              dfsan_label mask_label, dfsan_label *ret_label) {
72868d75effSDimitry Andric   int ret = sched_getaffinity(pid, cpusetsize, mask);
72968d75effSDimitry Andric   if (ret == 0) {
73068d75effSDimitry Andric     dfsan_set_label(0, mask, cpusetsize);
73168d75effSDimitry Andric   }
73268d75effSDimitry Andric   *ret_label = 0;
73368d75effSDimitry Andric   return ret;
73468d75effSDimitry Andric }
73568d75effSDimitry Andric 
73668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
73768d75effSDimitry Andric int __dfsw_sigemptyset(sigset_t *set, dfsan_label set_label,
73868d75effSDimitry Andric                        dfsan_label *ret_label) {
73968d75effSDimitry Andric   int ret = sigemptyset(set);
74068d75effSDimitry Andric   dfsan_set_label(0, set, sizeof(sigset_t));
74168d75effSDimitry Andric   return ret;
74268d75effSDimitry Andric }
74368d75effSDimitry Andric 
74468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
74568d75effSDimitry Andric int __dfsw_sigaction(int signum, const struct sigaction *act,
74668d75effSDimitry Andric                      struct sigaction *oldact, dfsan_label signum_label,
74768d75effSDimitry Andric                      dfsan_label act_label, dfsan_label oldact_label,
74868d75effSDimitry Andric                      dfsan_label *ret_label) {
74968d75effSDimitry Andric   int ret = sigaction(signum, act, oldact);
75068d75effSDimitry Andric   if (oldact) {
75168d75effSDimitry Andric     dfsan_set_label(0, oldact, sizeof(struct sigaction));
75268d75effSDimitry Andric   }
75368d75effSDimitry Andric   *ret_label = 0;
75468d75effSDimitry Andric   return ret;
75568d75effSDimitry Andric }
75668d75effSDimitry Andric 
75768d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
75868d75effSDimitry Andric int __dfsw_gettimeofday(struct timeval *tv, struct timezone *tz,
75968d75effSDimitry Andric                         dfsan_label tv_label, dfsan_label tz_label,
76068d75effSDimitry Andric                         dfsan_label *ret_label) {
76168d75effSDimitry Andric   int ret = gettimeofday(tv, tz);
76268d75effSDimitry Andric   if (tv) {
76368d75effSDimitry Andric     dfsan_set_label(0, tv, sizeof(struct timeval));
76468d75effSDimitry Andric   }
76568d75effSDimitry Andric   if (tz) {
76668d75effSDimitry Andric     dfsan_set_label(0, tz, sizeof(struct timezone));
76768d75effSDimitry Andric   }
76868d75effSDimitry Andric   *ret_label = 0;
76968d75effSDimitry Andric   return ret;
77068d75effSDimitry Andric }
77168d75effSDimitry Andric 
77268d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void *__dfsw_memchr(void *s, int c, size_t n,
77368d75effSDimitry Andric                                                   dfsan_label s_label,
77468d75effSDimitry Andric                                                   dfsan_label c_label,
77568d75effSDimitry Andric                                                   dfsan_label n_label,
77668d75effSDimitry Andric                                                   dfsan_label *ret_label) {
77768d75effSDimitry Andric   void *ret = memchr(s, c, n);
77868d75effSDimitry Andric   if (flags().strict_data_dependencies) {
77968d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
78068d75effSDimitry Andric   } else {
78168d75effSDimitry Andric     size_t len =
78268d75effSDimitry Andric         ret ? reinterpret_cast<char *>(ret) - reinterpret_cast<char *>(s) + 1
78368d75effSDimitry Andric             : n;
78468d75effSDimitry Andric     *ret_label =
78568d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, len), dfsan_union(s_label, c_label));
78668d75effSDimitry Andric   }
78768d75effSDimitry Andric   return ret;
78868d75effSDimitry Andric }
78968d75effSDimitry Andric 
79068d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strrchr(char *s, int c,
79168d75effSDimitry Andric                                                    dfsan_label s_label,
79268d75effSDimitry Andric                                                    dfsan_label c_label,
79368d75effSDimitry Andric                                                    dfsan_label *ret_label) {
79468d75effSDimitry Andric   char *ret = strrchr(s, c);
79568d75effSDimitry Andric   if (flags().strict_data_dependencies) {
79668d75effSDimitry Andric     *ret_label = ret ? s_label : 0;
79768d75effSDimitry Andric   } else {
79868d75effSDimitry Andric     *ret_label =
79968d75effSDimitry Andric         dfsan_union(dfsan_read_label(s, strlen(s) + 1),
80068d75effSDimitry Andric                     dfsan_union(s_label, c_label));
80168d75effSDimitry Andric   }
80268d75effSDimitry Andric 
80368d75effSDimitry Andric   return ret;
80468d75effSDimitry Andric }
80568d75effSDimitry Andric 
80668d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE char *__dfsw_strstr(char *haystack, char *needle,
80768d75effSDimitry Andric                                                   dfsan_label haystack_label,
80868d75effSDimitry Andric                                                   dfsan_label needle_label,
80968d75effSDimitry Andric                                                   dfsan_label *ret_label) {
81068d75effSDimitry Andric   char *ret = strstr(haystack, needle);
81168d75effSDimitry Andric   if (flags().strict_data_dependencies) {
81268d75effSDimitry Andric     *ret_label = ret ? haystack_label : 0;
81368d75effSDimitry Andric   } else {
81468d75effSDimitry Andric     size_t len = ret ? ret + strlen(needle) - haystack : strlen(haystack) + 1;
81568d75effSDimitry Andric     *ret_label =
81668d75effSDimitry Andric         dfsan_union(dfsan_read_label(haystack, len),
81768d75effSDimitry Andric                     dfsan_union(dfsan_read_label(needle, strlen(needle) + 1),
81868d75effSDimitry Andric                                 dfsan_union(haystack_label, needle_label)));
81968d75effSDimitry Andric   }
82068d75effSDimitry Andric 
82168d75effSDimitry Andric   return ret;
82268d75effSDimitry Andric }
82368d75effSDimitry Andric 
82468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int __dfsw_nanosleep(const struct timespec *req,
82568d75effSDimitry Andric                                                    struct timespec *rem,
82668d75effSDimitry Andric                                                    dfsan_label req_label,
82768d75effSDimitry Andric                                                    dfsan_label rem_label,
82868d75effSDimitry Andric                                                    dfsan_label *ret_label) {
82968d75effSDimitry Andric   int ret = nanosleep(req, rem);
83068d75effSDimitry Andric   *ret_label = 0;
83168d75effSDimitry Andric   if (ret == -1) {
83268d75effSDimitry Andric     // Interrupted by a signal, rem is filled with the remaining time.
83368d75effSDimitry Andric     dfsan_set_label(0, rem, sizeof(struct timespec));
83468d75effSDimitry Andric   }
83568d75effSDimitry Andric   return ret;
83668d75effSDimitry Andric }
83768d75effSDimitry Andric 
83868d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
83968d75effSDimitry Andric __dfsw_socketpair(int domain, int type, int protocol, int sv[2],
84068d75effSDimitry Andric                   dfsan_label domain_label, dfsan_label type_label,
84168d75effSDimitry Andric                   dfsan_label protocol_label, dfsan_label sv_label,
84268d75effSDimitry Andric                   dfsan_label *ret_label) {
84368d75effSDimitry Andric   int ret = socketpair(domain, type, protocol, sv);
84468d75effSDimitry Andric   *ret_label = 0;
84568d75effSDimitry Andric   if (ret == 0) {
84668d75effSDimitry Andric     dfsan_set_label(0, sv, sizeof(*sv) * 2);
84768d75effSDimitry Andric   }
84868d75effSDimitry Andric   return ret;
84968d75effSDimitry Andric }
85068d75effSDimitry Andric 
85168d75effSDimitry Andric // Type of the trampoline function passed to the custom version of
85268d75effSDimitry Andric // dfsan_set_write_callback.
85368d75effSDimitry Andric typedef void (*write_trampoline_t)(
85468d75effSDimitry Andric     void *callback,
85568d75effSDimitry Andric     int fd, const void *buf, ssize_t count,
85668d75effSDimitry Andric     dfsan_label fd_label, dfsan_label buf_label, dfsan_label count_label);
85768d75effSDimitry Andric 
85868d75effSDimitry Andric // Calls to dfsan_set_write_callback() set the values in this struct.
85968d75effSDimitry Andric // Calls to the custom version of write() read (and invoke) them.
86068d75effSDimitry Andric static struct {
86168d75effSDimitry Andric   write_trampoline_t write_callback_trampoline = nullptr;
86268d75effSDimitry Andric   void *write_callback = nullptr;
86368d75effSDimitry Andric } write_callback_info;
86468d75effSDimitry Andric 
86568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE void
86668d75effSDimitry Andric __dfsw_dfsan_set_write_callback(
86768d75effSDimitry Andric     write_trampoline_t write_callback_trampoline,
86868d75effSDimitry Andric     void *write_callback,
86968d75effSDimitry Andric     dfsan_label write_callback_label,
87068d75effSDimitry Andric     dfsan_label *ret_label) {
87168d75effSDimitry Andric   write_callback_info.write_callback_trampoline = write_callback_trampoline;
87268d75effSDimitry Andric   write_callback_info.write_callback = write_callback;
87368d75effSDimitry Andric }
87468d75effSDimitry Andric 
87568d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE int
87668d75effSDimitry Andric __dfsw_write(int fd, const void *buf, size_t count,
87768d75effSDimitry Andric              dfsan_label fd_label, dfsan_label buf_label,
87868d75effSDimitry Andric              dfsan_label count_label, dfsan_label *ret_label) {
87968d75effSDimitry Andric   if (write_callback_info.write_callback) {
88068d75effSDimitry Andric     write_callback_info.write_callback_trampoline(
88168d75effSDimitry Andric         write_callback_info.write_callback,
88268d75effSDimitry Andric         fd, buf, count,
88368d75effSDimitry Andric         fd_label, buf_label, count_label);
88468d75effSDimitry Andric   }
88568d75effSDimitry Andric 
88668d75effSDimitry Andric   *ret_label = 0;
88768d75effSDimitry Andric   return write(fd, buf, count);
88868d75effSDimitry Andric }
88968d75effSDimitry Andric } // namespace __dfsan
89068d75effSDimitry Andric 
89168d75effSDimitry Andric // Type used to extract a dfsan_label with va_arg()
89268d75effSDimitry Andric typedef int dfsan_label_va;
89368d75effSDimitry Andric 
89468d75effSDimitry Andric // Formats a chunk either a constant string or a single format directive (e.g.,
89568d75effSDimitry Andric // '%.3f').
89668d75effSDimitry Andric struct Formatter {
89768d75effSDimitry Andric   Formatter(char *str_, const char *fmt_, size_t size_)
89868d75effSDimitry Andric       : str(str_), str_off(0), size(size_), fmt_start(fmt_), fmt_cur(fmt_),
89968d75effSDimitry Andric         width(-1) {}
90068d75effSDimitry Andric 
90168d75effSDimitry Andric   int format() {
90268d75effSDimitry Andric     char *tmp_fmt = build_format_string();
90368d75effSDimitry Andric     int retval =
90468d75effSDimitry Andric         snprintf(str + str_off, str_off < size ? size - str_off : 0, tmp_fmt,
90568d75effSDimitry Andric                  0 /* used only to avoid warnings */);
90668d75effSDimitry Andric     free(tmp_fmt);
90768d75effSDimitry Andric     return retval;
90868d75effSDimitry Andric   }
90968d75effSDimitry Andric 
91068d75effSDimitry Andric   template <typename T> int format(T arg) {
91168d75effSDimitry Andric     char *tmp_fmt = build_format_string();
91268d75effSDimitry Andric     int retval;
91368d75effSDimitry Andric     if (width >= 0) {
91468d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
91568d75effSDimitry Andric                         tmp_fmt, width, arg);
91668d75effSDimitry Andric     } else {
91768d75effSDimitry Andric       retval = snprintf(str + str_off, str_off < size ? size - str_off : 0,
91868d75effSDimitry Andric                         tmp_fmt, arg);
91968d75effSDimitry Andric     }
92068d75effSDimitry Andric     free(tmp_fmt);
92168d75effSDimitry Andric     return retval;
92268d75effSDimitry Andric   }
92368d75effSDimitry Andric 
92468d75effSDimitry Andric   char *build_format_string() {
92568d75effSDimitry Andric     size_t fmt_size = fmt_cur - fmt_start + 1;
92668d75effSDimitry Andric     char *new_fmt = (char *)malloc(fmt_size + 1);
92768d75effSDimitry Andric     assert(new_fmt);
92868d75effSDimitry Andric     internal_memcpy(new_fmt, fmt_start, fmt_size);
92968d75effSDimitry Andric     new_fmt[fmt_size] = '\0';
93068d75effSDimitry Andric     return new_fmt;
93168d75effSDimitry Andric   }
93268d75effSDimitry Andric 
93368d75effSDimitry Andric   char *str_cur() { return str + str_off; }
93468d75effSDimitry Andric 
93568d75effSDimitry Andric   size_t num_written_bytes(int retval) {
93668d75effSDimitry Andric     if (retval < 0) {
93768d75effSDimitry Andric       return 0;
93868d75effSDimitry Andric     }
93968d75effSDimitry Andric 
94068d75effSDimitry Andric     size_t num_avail = str_off < size ? size - str_off : 0;
94168d75effSDimitry Andric     if (num_avail == 0) {
94268d75effSDimitry Andric       return 0;
94368d75effSDimitry Andric     }
94468d75effSDimitry Andric 
94568d75effSDimitry Andric     size_t num_written = retval;
94668d75effSDimitry Andric     // A return value of {v,}snprintf of size or more means that the output was
94768d75effSDimitry Andric     // truncated.
94868d75effSDimitry Andric     if (num_written >= num_avail) {
94968d75effSDimitry Andric       num_written -= num_avail;
95068d75effSDimitry Andric     }
95168d75effSDimitry Andric 
95268d75effSDimitry Andric     return num_written;
95368d75effSDimitry Andric   }
95468d75effSDimitry Andric 
95568d75effSDimitry Andric   char *str;
95668d75effSDimitry Andric   size_t str_off;
95768d75effSDimitry Andric   size_t size;
95868d75effSDimitry Andric   const char *fmt_start;
95968d75effSDimitry Andric   const char *fmt_cur;
96068d75effSDimitry Andric   int width;
96168d75effSDimitry Andric };
96268d75effSDimitry Andric 
96368d75effSDimitry Andric // Formats the input and propagates the input labels to the output. The output
96468d75effSDimitry Andric // is stored in 'str'. 'size' bounds the number of output bytes. 'format' and
96568d75effSDimitry Andric // 'ap' are the format string and the list of arguments for formatting. Returns
96668d75effSDimitry Andric // the return value vsnprintf would return.
96768d75effSDimitry Andric //
96868d75effSDimitry Andric // The function tokenizes the format string in chunks representing either a
96968d75effSDimitry Andric // constant string or a single format directive (e.g., '%.3f') and formats each
97068d75effSDimitry Andric // chunk independently into the output string. This approach allows to figure
97168d75effSDimitry Andric // out which bytes of the output string depends on which argument and thus to
97268d75effSDimitry Andric // propagate labels more precisely.
97368d75effSDimitry Andric //
97468d75effSDimitry Andric // WARNING: This implementation does not support conversion specifiers with
97568d75effSDimitry Andric // positional arguments.
97668d75effSDimitry Andric static int format_buffer(char *str, size_t size, const char *fmt,
97768d75effSDimitry Andric                          dfsan_label *va_labels, dfsan_label *ret_label,
97868d75effSDimitry Andric                          va_list ap) {
97968d75effSDimitry Andric   Formatter formatter(str, fmt, size);
98068d75effSDimitry Andric 
98168d75effSDimitry Andric   while (*formatter.fmt_cur) {
98268d75effSDimitry Andric     formatter.fmt_start = formatter.fmt_cur;
98368d75effSDimitry Andric     formatter.width = -1;
98468d75effSDimitry Andric     int retval = 0;
98568d75effSDimitry Andric 
98668d75effSDimitry Andric     if (*formatter.fmt_cur != '%') {
98768d75effSDimitry Andric       // Ordinary character. Consume all the characters until a '%' or the end
98868d75effSDimitry Andric       // of the string.
98968d75effSDimitry Andric       for (; *(formatter.fmt_cur + 1) && *(formatter.fmt_cur + 1) != '%';
99068d75effSDimitry Andric            ++formatter.fmt_cur) {}
99168d75effSDimitry Andric       retval = formatter.format();
99268d75effSDimitry Andric       dfsan_set_label(0, formatter.str_cur(),
99368d75effSDimitry Andric                       formatter.num_written_bytes(retval));
99468d75effSDimitry Andric     } else {
99568d75effSDimitry Andric       // Conversion directive. Consume all the characters until a conversion
99668d75effSDimitry Andric       // specifier or the end of the string.
99768d75effSDimitry Andric       bool end_fmt = false;
99868d75effSDimitry Andric       for (; *formatter.fmt_cur && !end_fmt; ) {
99968d75effSDimitry Andric         switch (*++formatter.fmt_cur) {
100068d75effSDimitry Andric         case 'd':
100168d75effSDimitry Andric         case 'i':
100268d75effSDimitry Andric         case 'o':
100368d75effSDimitry Andric         case 'u':
100468d75effSDimitry Andric         case 'x':
100568d75effSDimitry Andric         case 'X':
100668d75effSDimitry Andric           switch (*(formatter.fmt_cur - 1)) {
100768d75effSDimitry Andric           case 'h':
100868d75effSDimitry Andric             // Also covers the 'hh' case (since the size of the arg is still
100968d75effSDimitry Andric             // an int).
101068d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
101168d75effSDimitry Andric             break;
101268d75effSDimitry Andric           case 'l':
101368d75effSDimitry Andric             if (formatter.fmt_cur - formatter.fmt_start >= 2 &&
101468d75effSDimitry Andric                 *(formatter.fmt_cur - 2) == 'l') {
101568d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long long int));
101668d75effSDimitry Andric             } else {
101768d75effSDimitry Andric               retval = formatter.format(va_arg(ap, long int));
101868d75effSDimitry Andric             }
101968d75effSDimitry Andric             break;
102068d75effSDimitry Andric           case 'q':
102168d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long long int));
102268d75effSDimitry Andric             break;
102368d75effSDimitry Andric           case 'j':
102468d75effSDimitry Andric             retval = formatter.format(va_arg(ap, intmax_t));
102568d75effSDimitry Andric             break;
102668d75effSDimitry Andric           case 'z':
102768d75effSDimitry Andric           case 't':
102868d75effSDimitry Andric             retval = formatter.format(va_arg(ap, size_t));
102968d75effSDimitry Andric             break;
103068d75effSDimitry Andric           default:
103168d75effSDimitry Andric             retval = formatter.format(va_arg(ap, int));
103268d75effSDimitry Andric           }
103368d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
103468d75effSDimitry Andric                           formatter.num_written_bytes(retval));
103568d75effSDimitry Andric           end_fmt = true;
103668d75effSDimitry Andric           break;
103768d75effSDimitry Andric 
103868d75effSDimitry Andric         case 'a':
103968d75effSDimitry Andric         case 'A':
104068d75effSDimitry Andric         case 'e':
104168d75effSDimitry Andric         case 'E':
104268d75effSDimitry Andric         case 'f':
104368d75effSDimitry Andric         case 'F':
104468d75effSDimitry Andric         case 'g':
104568d75effSDimitry Andric         case 'G':
104668d75effSDimitry Andric           if (*(formatter.fmt_cur - 1) == 'L') {
104768d75effSDimitry Andric             retval = formatter.format(va_arg(ap, long double));
104868d75effSDimitry Andric           } else {
104968d75effSDimitry Andric             retval = formatter.format(va_arg(ap, double));
105068d75effSDimitry Andric           }
105168d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
105268d75effSDimitry Andric                           formatter.num_written_bytes(retval));
105368d75effSDimitry Andric           end_fmt = true;
105468d75effSDimitry Andric           break;
105568d75effSDimitry Andric 
105668d75effSDimitry Andric         case 'c':
105768d75effSDimitry Andric           retval = formatter.format(va_arg(ap, int));
105868d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
105968d75effSDimitry Andric                           formatter.num_written_bytes(retval));
106068d75effSDimitry Andric           end_fmt = true;
106168d75effSDimitry Andric           break;
106268d75effSDimitry Andric 
106368d75effSDimitry Andric         case 's': {
106468d75effSDimitry Andric           char *arg = va_arg(ap, char *);
106568d75effSDimitry Andric           retval = formatter.format(arg);
106668d75effSDimitry Andric           va_labels++;
106768d75effSDimitry Andric           internal_memcpy(shadow_for(formatter.str_cur()), shadow_for(arg),
106868d75effSDimitry Andric                           sizeof(dfsan_label) *
106968d75effSDimitry Andric                               formatter.num_written_bytes(retval));
107068d75effSDimitry Andric           end_fmt = true;
107168d75effSDimitry Andric           break;
107268d75effSDimitry Andric         }
107368d75effSDimitry Andric 
107468d75effSDimitry Andric         case 'p':
107568d75effSDimitry Andric           retval = formatter.format(va_arg(ap, void *));
107668d75effSDimitry Andric           dfsan_set_label(*va_labels++, formatter.str_cur(),
107768d75effSDimitry Andric                           formatter.num_written_bytes(retval));
107868d75effSDimitry Andric           end_fmt = true;
107968d75effSDimitry Andric           break;
108068d75effSDimitry Andric 
108168d75effSDimitry Andric         case 'n': {
108268d75effSDimitry Andric           int *ptr = va_arg(ap, int *);
108368d75effSDimitry Andric           *ptr = (int)formatter.str_off;
108468d75effSDimitry Andric           va_labels++;
108568d75effSDimitry Andric           dfsan_set_label(0, ptr, sizeof(ptr));
108668d75effSDimitry Andric           end_fmt = true;
108768d75effSDimitry Andric           break;
108868d75effSDimitry Andric         }
108968d75effSDimitry Andric 
109068d75effSDimitry Andric         case '%':
109168d75effSDimitry Andric           retval = formatter.format();
109268d75effSDimitry Andric           dfsan_set_label(0, formatter.str_cur(),
109368d75effSDimitry Andric                           formatter.num_written_bytes(retval));
109468d75effSDimitry Andric           end_fmt = true;
109568d75effSDimitry Andric           break;
109668d75effSDimitry Andric 
109768d75effSDimitry Andric         case '*':
109868d75effSDimitry Andric           formatter.width = va_arg(ap, int);
109968d75effSDimitry Andric           va_labels++;
110068d75effSDimitry Andric           break;
110168d75effSDimitry Andric 
110268d75effSDimitry Andric         default:
110368d75effSDimitry Andric           break;
110468d75effSDimitry Andric         }
110568d75effSDimitry Andric       }
110668d75effSDimitry Andric     }
110768d75effSDimitry Andric 
110868d75effSDimitry Andric     if (retval < 0) {
110968d75effSDimitry Andric       return retval;
111068d75effSDimitry Andric     }
111168d75effSDimitry Andric 
111268d75effSDimitry Andric     formatter.fmt_cur++;
111368d75effSDimitry Andric     formatter.str_off += retval;
111468d75effSDimitry Andric   }
111568d75effSDimitry Andric 
111668d75effSDimitry Andric   *ret_label = 0;
111768d75effSDimitry Andric 
111868d75effSDimitry Andric   // Number of bytes written in total.
111968d75effSDimitry Andric   return formatter.str_off;
112068d75effSDimitry Andric }
112168d75effSDimitry Andric 
112268d75effSDimitry Andric extern "C" {
112368d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
112468d75effSDimitry Andric int __dfsw_sprintf(char *str, const char *format, dfsan_label str_label,
112568d75effSDimitry Andric                    dfsan_label format_label, dfsan_label *va_labels,
112668d75effSDimitry Andric                    dfsan_label *ret_label, ...) {
112768d75effSDimitry Andric   va_list ap;
112868d75effSDimitry Andric   va_start(ap, ret_label);
112968d75effSDimitry Andric   int ret = format_buffer(str, ~0ul, format, va_labels, ret_label, ap);
113068d75effSDimitry Andric   va_end(ap);
113168d75effSDimitry Andric   return ret;
113268d75effSDimitry Andric }
113368d75effSDimitry Andric 
113468d75effSDimitry Andric SANITIZER_INTERFACE_ATTRIBUTE
113568d75effSDimitry Andric int __dfsw_snprintf(char *str, size_t size, const char *format,
113668d75effSDimitry Andric                     dfsan_label str_label, dfsan_label size_label,
113768d75effSDimitry Andric                     dfsan_label format_label, dfsan_label *va_labels,
113868d75effSDimitry Andric                     dfsan_label *ret_label, ...) {
113968d75effSDimitry Andric   va_list ap;
114068d75effSDimitry Andric   va_start(ap, ret_label);
114168d75effSDimitry Andric   int ret = format_buffer(str, size, format, va_labels, ret_label, ap);
114268d75effSDimitry Andric   va_end(ap);
114368d75effSDimitry Andric   return ret;
114468d75effSDimitry Andric }
114568d75effSDimitry Andric 
114668d75effSDimitry Andric // Default empty implementations (weak). Users should redefine them.
114768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *) {}
114868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init, u32 *,
114968d75effSDimitry Andric                              u32 *) {}
115068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
115168d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
115268d75effSDimitry Andric 
115368d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp, void) {}
115468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp1, void) {}
115568d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp2, void) {}
115668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp4, void) {}
115768d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_cmp8, void) {}
115868d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp1,
115968d75effSDimitry Andric                              void) {}
116068d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp2,
116168d75effSDimitry Andric                              void) {}
116268d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp4,
116368d75effSDimitry Andric                              void) {}
116468d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_const_cmp8,
116568d75effSDimitry Andric                              void) {}
116668d75effSDimitry Andric SANITIZER_INTERFACE_WEAK_DEF(void, __dfsw___sanitizer_cov_trace_switch, void) {}
116768d75effSDimitry Andric }  // extern "C"
1168