Index: lib/sanitizer_common/sanitizer_common_interceptors.inc =================================================================== --- lib/sanitizer_common/sanitizer_common_interceptors.inc +++ lib/sanitizer_common/sanitizer_common_interceptors.inc @@ -110,6 +110,7 @@ #define stat __stat50 #define time __time50 #define times __times13 +#define unvis __unvis50 #define wait3 __wait350 #define wait4 __wait450 extern const unsigned short *_ctype_tab_; @@ -7362,6 +7363,271 @@ #define INIT_GETVFSSTAT #endif +#if SANITIZER_INTERCEPT_VIS +INTERCEPTOR(char *, vis, char *dst, int c, int flag, int nextc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, vis, dst, c, flag, nextc); + char *end = REAL(vis)(dst, c, flag, nextc); + // dst is NULL terminated and end points to the NULL char + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); + return end; +} +INTERCEPTOR(char *, nvis, char *dst, SIZE_T dlen, int c, int flag, int nextc) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, nvis, dst, dlen, c, flag, nextc); + char *end = REAL(nvis)(dst, dlen, c, flag, nextc); + // nvis cannot make sure the dst is NULL terminated + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, + Min((SIZE_T)(end - dst + 1), dlen)); + return end; +} +INTERCEPTOR(int, strvis, char *dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strvis, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int len = REAL(strvis)(dst, src, flag); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, stravis, char **dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, stravis, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int len = REAL(stravis)(dst, src, flag); + if (dst) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, sizeof(char *)); + if (*dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, *dst, len + 1); + } + return len; +} +INTERCEPTOR(int, strnvis, char *dst, SIZE_T dlen, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnvis, dst, dlen, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int len = REAL(strnvis)(dst, dlen, src, flag); + // The interface will be valid even if there is no space for NULL char + if (dst && len > 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)len + 1, dlen)); + return len; +} +INTERCEPTOR(int, strvisx, char *dst, const char *src, SIZE_T len, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strvisx, dst, src, len, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + int ret = REAL(strvisx)(dst, src, len, flag); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnvisx, dst, dlen, src, len, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + int ret = REAL(strnvisx)(dst, dlen, src, len, flag); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + return ret; +} +INTERCEPTOR(int, strenvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag, int *cerr_ptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strenvisx, dst, dlen, src, len, flag, cerr_ptr); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold + // according to the implementation + if (cerr_ptr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); + int ret = REAL(strenvisx)(dst, dlen, src, len, flag, cerr_ptr); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + if (cerr_ptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); + return ret; +} +INTERCEPTOR(char *, svis, char *dst, int c, int flag, int nextc, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, svis, dst, c, flag, nextc, extra); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + char *end = REAL(svis)(dst, c, flag, nextc, extra); + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, end - dst + 1); + return end; +} +INTERCEPTOR(char *, snvis, char *dst, SIZE_T dlen, int c, int flag, int nextc, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, snvis, dst, dlen, c, flag, nextc, extra); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + char *end = REAL(snvis)(dst, dlen, c, flag, nextc, extra); + if (dst && end) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, + Min((SIZE_T)(end - dst + 1), dlen)); + return end; +} +INTERCEPTOR(int, strsvis, char *dst, const char *src, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsvis, dst, src, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + int len = REAL(strsvis)(dst, src, flag, extra); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, len + 1); + return len; +} +INTERCEPTOR(int, strsnvis, char *dst, SIZE_T dlen, const char *src, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsnvis, dst, dlen, src, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + int len = REAL(strsnvis)(dst, dlen, src, flag, extra); + // The interface will be valid even if there is no space for NULL char + if (dst && len >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)len + 1, dlen)); + return len; +} +INTERCEPTOR(int, strsvisx, char *dst, const char *src, SIZE_T len, int flag, + const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsvisx, dst, src, len, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + int ret = REAL(strsvisx)(dst, src, len, flag, extra); + if (dst) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strsnvisx, char *dst, SIZE_T dlen, const char *src, SIZE_T len, + int flag, const char *extra) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsnvisx, dst, dlen, src, len, flag, extra); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + int ret = REAL(strsnvisx)(dst, dlen, src, len, flag, extra); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + return ret; +} +INTERCEPTOR(int, strsenvisx, char *dst, SIZE_T dlen, const char *src, + SIZE_T len, int flag, const char *extra, int *cerr_ptr) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strsenvisx, dst, dlen, src, len, flag, extra, + cerr_ptr); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, len); + if (extra) + COMMON_INTERCEPTOR_READ_RANGE(ctx, extra, REAL(strlen)(extra) + 1); + // FIXME: only need to be checked when "flag | VIS_NOLOCALE" doesn't hold + // according to the implementation + if (cerr_ptr) + COMMON_INTERCEPTOR_READ_RANGE(ctx, cerr_ptr, sizeof(int)); + int ret = REAL(strsenvisx)(dst, dlen, src, len, flag, extra, cerr_ptr); + if (dst && ret >= 0) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + if (cerr_ptr) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cerr_ptr, sizeof(int)); + return ret; +} +INTERCEPTOR(int, unvis, char *cp, int c, int *astate, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, unvis, cp, c, astate, flag); + if (astate) + COMMON_INTERCEPTOR_READ_RANGE(ctx, astate, sizeof(*astate)); + int ret = REAL(unvis)(cp, c, astate, flag); + if (ret == unvis_valid || ret == unvis_validpush) { + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, cp, sizeof(*cp)); + } + return ret; +} +INTERCEPTOR(int, strunvis, char *dst, const char *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strunvis, dst, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int ret = REAL(strunvis)(dst, src); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnunvis, char *dst, SIZE_T dlen, const char *src) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnunvis, dst, dlen, src); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int ret = REAL(strnunvis)(dst, dlen, src); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + return ret; +} +INTERCEPTOR(int, strunvisx, char *dst, const char *src, int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strunvisx, dst, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int ret = REAL(strunvisx)(dst, src, flag); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, ret + 1); + return ret; +} +INTERCEPTOR(int, strnunvisx, char *dst, SIZE_T dlen, const char *src, + int flag) { + void *ctx; + COMMON_INTERCEPTOR_ENTER(ctx, strnunvisx, dst, dlen, src, flag); + if (src) + COMMON_INTERCEPTOR_READ_RANGE(ctx, src, REAL(strlen)(src) + 1); + int ret = REAL(strnunvisx)(dst, dlen, src, flag); + if (ret != -1) + COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, Min((SIZE_T)ret + 1, dlen)); + return ret; +} +#define INIT_VIS \ + COMMON_INTERCEPT_FUNCTION(vis); \ + COMMON_INTERCEPT_FUNCTION(nvis); \ + COMMON_INTERCEPT_FUNCTION(strvis); \ + COMMON_INTERCEPT_FUNCTION(stravis); \ + COMMON_INTERCEPT_FUNCTION(strnvis); \ + COMMON_INTERCEPT_FUNCTION(strvisx); \ + COMMON_INTERCEPT_FUNCTION(strnvisx); \ + COMMON_INTERCEPT_FUNCTION(strenvisx); \ + COMMON_INTERCEPT_FUNCTION(svis); \ + COMMON_INTERCEPT_FUNCTION(snvis); \ + COMMON_INTERCEPT_FUNCTION(strsvis); \ + COMMON_INTERCEPT_FUNCTION(strsnvis); \ + COMMON_INTERCEPT_FUNCTION(strsvisx); \ + COMMON_INTERCEPT_FUNCTION(strsnvisx); \ + COMMON_INTERCEPT_FUNCTION(strsenvisx); \ + COMMON_INTERCEPT_FUNCTION(unvis); \ + COMMON_INTERCEPT_FUNCTION(strunvis); \ + COMMON_INTERCEPT_FUNCTION(strnunvis); \ + COMMON_INTERCEPT_FUNCTION(strunvisx); \ + COMMON_INTERCEPT_FUNCTION(strnunvisx) +#else +#define INIT_VIS +#endif + static void InitializeCommonInterceptors() { static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1]; interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap(); @@ -7619,6 +7885,7 @@ INIT_MI_VECTOR_HASH; INIT_SETVBUF; INIT_GETVFSSTAT; + INIT_VIS; INIT___PRINTF_CHK; } Index: lib/sanitizer_common/sanitizer_platform_interceptors.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_interceptors.h +++ lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -521,5 +521,6 @@ #define SANITIZER_INTERCEPT_GETMNTINFO SI_NETBSD #define SANITIZER_INTERCEPT_MI_VECTOR_HASH SI_NETBSD #define SANITIZER_INTERCEPT_GETVFSSTAT SI_NETBSD +#define SANITIZER_INTERCEPT_VIS SI_NETBSD #endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H Index: lib/sanitizer_common/sanitizer_platform_limits_netbsd.h =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_netbsd.h +++ lib/sanitizer_common/sanitizer_platform_limits_netbsd.h @@ -2202,6 +2202,9 @@ extern const int si_SEGV_MAPERR; extern const int si_SEGV_ACCERR; + +extern const int unvis_valid; +extern const int unvis_validpush; } // namespace __sanitizer #define CHECK_TYPE_SIZE(TYPE) \ Index: lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc =================================================================== --- lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc +++ lib/sanitizer_common/sanitizer_platform_limits_netbsd.cc @@ -2092,6 +2092,9 @@ const int si_SEGV_MAPERR = SEGV_MAPERR; const int si_SEGV_ACCERR = SEGV_ACCERR; + +const int unvis_valid = UNVIS_VALID; +const int unvis_validpush = UNVIS_VALIDPUSH; } // namespace __sanitizer using namespace __sanitizer; Index: test/sanitizer_common/TestCases/NetBSD/vis.cc =================================================================== --- /dev/null +++ test/sanitizer_common/TestCases/NetBSD/vis.cc @@ -0,0 +1,245 @@ +// RUN: %clangxx -O0 -g %s -o %t && %run %t 2>&1 | FileCheck %s + +#include +#include +#include +#include +#include +#include +#include + +void test_vis() { + char visout[5]; + int ch = toascii(0x1); + vis(visout, ch, VIS_SAFE | VIS_NOSLASH, 0); + printf("vis: %s\n", visout); +} + +void test_nvis() { + char visout[5]; + int ch = toascii(0x2); + nvis(visout, sizeof visout, ch, VIS_SAFE | VIS_NOSLASH, 0); + printf("nvis: %s\n", visout); +} + +void test_strvis() { + char visout[5]; + strvis(visout, "\3", VIS_SAFE | VIS_NOSLASH); + printf("strvis: %s\n", visout); +} + +void test_stravis() { + char *visout; + stravis(&visout, "\4", VIS_SAFE | VIS_NOSLASH); + printf("stravis: %s\n", visout); + free(visout); +} + +void test_strnvis() { + char visout[5]; + strnvis(visout, sizeof visout, "\5", VIS_SAFE | VIS_NOSLASH); + printf("strnvis: %s\n", visout); +} + +void test_strvisx() { + char visout[5]; + char src[] = "\6"; + strvisx(visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH); + printf("strvisx: %s\n", visout); +} + +void test_strnvisx() { + char visout[5]; + char src[] = "\1"; + strnvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH); + printf("strnvisx: %s\n", visout); +} + +void test_strenvisx() { + char visout[5]; + char src[] = "\2"; + strenvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH, NULL); + printf("strenvisx: %s\n", visout); +} + +void test_svis() { + char visout[5]; + int ch = toascii(0x3); + svis(visout, ch, VIS_SAFE | VIS_NOSLASH, 0, "x"); + printf("svis: %s\n", visout); +} + +void test_snvis() { + char visout[5]; + int ch = toascii(0x2); + snvis(visout, sizeof visout, ch, VIS_SAFE | VIS_NOSLASH, 0, "x"); + printf("snvis: %s\n", visout); +} + +void test_strsvis() { + char visout[5]; + strsvis(visout, "\4", VIS_SAFE | VIS_NOSLASH, "x"); + printf("strsvis: %s\n", visout); +} + +void test_strsnvis() { + char visout[5]; + strsnvis(visout, sizeof visout, "\5", VIS_SAFE | VIS_NOSLASH, "x"); + printf("strsnvis: %s\n", visout); +} + +void test_strsvisx() { + char visout[5]; + char src[] = "\5"; + strsvisx(visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH, "x"); + printf("strsvisx: %s\n", visout); +} + +void test_strsnvisx() { + char visout[5]; + char src[] = "\6"; + strsnvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH, "x"); + printf("strsnvisx: %s\n", visout); +} + +void test_strsenvisx() { + char visout[5]; + char src[] = "\1"; + strsenvisx(visout, sizeof visout, src, sizeof src - 1 /* skip final \0 */, + VIS_SAFE | VIS_NOSLASH, "x", NULL); + printf("strsenvisx: %s\n", visout); +} + +void test_unvis() { + char visout[5]; + int ch = toascii(0x1); + vis(visout, ch, VIS_SAFE, 0); + + int state = 0; + char out; + char *p = visout; + while ((ch = *(p++)) != '\0') { + again: + switch (unvis(&out, ch, &state, 0)) { + case 0: + case UNVIS_NOCHAR: + break; + case UNVIS_VALID: + printf("unvis: %" PRIx8 "\n", (unsigned char)out); + break; + case UNVIS_VALIDPUSH: + printf("unvis: %" PRIx8 "\n", (unsigned char)out); + goto again; + case UNVIS_SYNBAD: + errx(1, "Bad character sequence!"); + } + } + if (unvis(&out, '\0', &state, UNVIS_END) == UNVIS_VALID) + printf("unvis: %" PRIx8 "\n", (unsigned char)out); +} + +void test_strunvis() { + char visout[5]; + int ch = toascii(0x2); + vis(visout, ch, VIS_SAFE, 0); + + char p[5]; + strunvis(p, visout); + + char *pp = p; + while ((ch = *(pp++)) != '\0') + printf("strunvis: %" PRIx8 "\n", (unsigned char)ch); +} + +void test_strnunvis() { + char visout[5]; + int ch = toascii(0x3); + vis(visout, ch, VIS_SAFE, 0); + + char p[5]; + strnunvis(p, sizeof p, visout); + + char *pp = p; + while ((ch = *(pp++)) != '\0') + printf("strnunvis: %" PRIx8 "\n", (unsigned char)ch); +} + +void test_strunvisx() { + char visout[5]; + int ch = toascii(0x4); + vis(visout, ch, VIS_SAFE, 0); + + char p[5]; + strunvisx(p, visout, VIS_SAFE); + + char *pp = p; + while ((ch = *(pp++)) != '\0') + printf("strunvisx: %" PRIx8 "\n", (unsigned char)ch); +} + +void test_strnunvisx() { + char visout[5]; + int ch = toascii(0x5); + vis(visout, ch, VIS_SAFE, 0); + + char p[5]; + strnunvisx(p, sizeof p, visout, VIS_SAFE); + + char *pp = p; + while ((ch = *(pp++)) != '\0') + printf("strnunvisx: %" PRIx8 "\n", (unsigned char)ch); +} + +int main(void) { + printf("vis\n"); + + test_vis(); + test_nvis(); + test_strvis(); + test_stravis(); + test_strnvis(); + test_strvisx(); + test_strnvisx(); + test_strenvisx(); + test_svis(); + test_snvis(); + test_strsvis(); + test_strsnvis(); + test_strsvisx(); + test_strsnvisx(); + test_strsenvisx(); + test_unvis(); + test_strunvis(); + test_strnunvis(); + test_strunvisx(); + test_strnunvisx(); + + // CHECK: vis + // CHECK: vis: ^A + // CHECK: nvis: ^B + // CHECK: strvis: ^C + // CHECK: stravis: ^D + // CHECK: strnvis: ^E + // CHECK: strvisx: ^F + // CHECK: strnvisx: ^A + // CHECK: strenvisx: ^B + // CHECK: svis: ^C + // CHECK: snvis: ^B + // CHECK: strsvis: ^D + // CHECK: strsnvis: ^E + // CHECK: strsvisx: ^E + // CHECK: strsnvisx: ^F + // CHECK: strsenvisx: ^A + // CHECK: unvis: 1 + // CHECK: strunvis: 2 + // CHECK: strnunvis: 3 + // CHECK: strunvisx: 4 + // CHECK: strnunvisx: 5 + + return 0; +}