int main (void) { unsigned char buf[6] = { 0x25, 0xe2, 0x82, 0xac, 0xce, 0xbb }; mbstate_t state; const char *src; wchar_t wc = 42; size_t n; int result = 0; const char *used_locale; setlocale (LC_CTYPE,"de_DE.UTF-8"); /* Double check. */ used_locale = setlocale (LC_CTYPE, NULL); printf ("used locale: \"%s\"\n", used_locale); result = strcmp (used_locale, "de_DE.UTF-8"); memset (&state, '\0', sizeof (state)); src = (const char *) buf; show (mbsnrtowcs (&wc, &src, 1, 1, &state), 1, 37, buf + 1); show (mbsnrtowcs (&wc, &src, 3, 1, &state), 1, 8364, buf + 4); show (mbsnrtowcs (&wc, &src, 1, 1, &state), 0, 8364, buf + 5); show (mbsnrtowcs (&wc, &src, 1, 1, &state), 1, 955, buf + 6); return result; }
ATF_TC_BODY(mbsnrtowcs, tc) { size_t i; const struct test *t; mbstate_t state; wchar_t buf[64]; const char *src; size_t len; for (i = 0; i < __arraycount(tests); ++i) { t = &tests[i]; ATF_REQUIRE_STREQ(setlocale(LC_ALL, "C"), "C"); ATF_REQUIRE(setlocale(LC_CTYPE, t->locale) != NULL); memset(&state, 0, sizeof(state)); src = t->data; len = mbsnrtowcs(buf, &src, t->limit, __arraycount(buf), &state); ATF_REQUIRE_EQ(src, t->data + t->limit); ATF_REQUIRE_EQ(len, t->output1_len); ATF_REQUIRE(wmemcmp(t->output1, buf, len) == 0); len = mbsnrtowcs(buf, &src, strlen(src) + 1, __arraycount(buf), &state); ATF_REQUIRE_EQ(len, strlen(t->data) - t->limit); ATF_REQUIRE(wmemcmp(t->output2, buf, len + 1) == 0); ATF_REQUIRE_EQ(src, NULL); } }
static const char *mbsnr(const char *str, int inbuf, int outbuf) { static char out[128]; wchar_t tmp[128]; int res; unsigned i; const char *s = str; mbstate_t ps; for (i = 0; i < 128; i++) tmp[i] = '~'; memset(&ps, 0, sizeof(ps)); res = mbsnrtowcs(tmp, &s, inbuf, outbuf, &ps); if (res < 0) { if (errno == EILSEQ) { snprintf(out, sizeof(out), "EILSEQ(%d)", (int)(s - str)); return out; } return "unknown error"; } if (tmp[res] == 0) tmp[res] = s ? 'z' : 'Z'; for (i = 0; i < 128; i++) { out[i] = tmp[i]; if (out[i] == '~') { out[i+1] = 0; break; } } return out; }
size_t mbsrtowcs(wchar_t *dst, const char **src, size_t len, mbstate_t *ps) { static mbstate_t mbs; if (ps == NULL) ps = &mbs; return (mbsnrtowcs(dst, src, SIZE_MAX, len, ps)); }
/* Print out utf-8 string. */ void pws(FILE *f, uint8_t *bp, size_t len) { mbstate_t state; memset(&state, 0, sizeof(state)); wchar_t *tmp; tmp = malloc((len + 1) * sizeof(wchar_t)); size_t n; const char *ptr = (const char *)bp; n = mbsnrtowcs(tmp, &ptr, len, len, &state); tmp[n] = L'\0'; fputws(tmp, stdout); free(tmp); }
static size_t wmbsnrtowcs(wchar_t *dest, const char **src, size_t nbytes, size_t len) { mbstate_t ps; size_t n; memset(&ps, 0, sizeof(mbstate_t)); n = mbsnrtowcs(dest, src, nbytes, len, &ps); if (n!=(size_t)-1 && *src) { *src -= ps.__count; } return n; }
TEST(wchar, mbsnrtowcs) { wchar_t dst[128]; const char* s = "hello, world!"; const char* src; memset(dst, 0, sizeof(dst)); src = s; ASSERT_EQ(0U, mbsnrtowcs(dst, &src, 0, 0, NULL)); memset(dst, 0, sizeof(dst)); src = s; ASSERT_EQ(2U, mbsnrtowcs(dst, &src, 2, 123, NULL)); // glibc chokes on SIZE_MAX here. ASSERT_EQ(L'h', dst[0]); ASSERT_EQ(L'e', dst[1]); ASSERT_EQ(&s[2], src); memset(dst, 0, sizeof(dst)); src = s; ASSERT_EQ(3U, mbsnrtowcs(dst, &src, SIZE_MAX, 3, NULL)); ASSERT_EQ(L'h', dst[0]); ASSERT_EQ(L'e', dst[1]); ASSERT_EQ(L'l', dst[2]); ASSERT_EQ(&s[3], src); }
static int wmemstream_write(void *v, const char *b, int l) { struct state *st = v; wchar_t *p; size_t nmc, len, end; end = (st->pos + l); if (end >= st->size) { /* 1.6 is (very) close to the golden ratio. */ size_t sz = st->size * 8 / 5; if (sz < end + 1) sz = end + 1; p = reallocarray(st->string, sz, sizeof(wchar_t)); if (!p) return (-1); bzero(p + st->size, (sz - st->size) * sizeof(wchar_t)); *st->pbuf = st->string = p; st->size = sz; } nmc = (st->size - st->pos) * sizeof(wchar_t); len = mbsnrtowcs(st->string + st->pos, &b, nmc, l, &st->mbs); if (len == (size_t)-1) return (-1); st->pos += len; if (st->pos > st->len) { st->len = st->pos; st->string[st->len] = L'\0'; } *st->psize = st->pos; return (len); }
int main (int argc, char *argv[]) { mbstate_t state; wchar_t wc; size_t ret; /* configure should already have checked that the locale is supported. */ if (setlocale (LC_ALL, "") == NULL) return 1; /* Test NUL byte input. */ { const char *src; memset (&state, '\0', sizeof (mbstate_t)); src = ""; ret = mbsnrtowcs (NULL, &src, 1, 0, &state); ASSERT (ret == 0); ASSERT (mbsinit (&state)); src = ""; ret = mbsnrtowcs (NULL, &src, 1, 1, &state); ASSERT (ret == 0); ASSERT (mbsinit (&state)); wc = (wchar_t) 0xBADFACE; src = ""; ret = mbsnrtowcs (&wc, &src, 1, 0, &state); ASSERT (ret == 0); ASSERT (wc == (wchar_t) 0xBADFACE); ASSERT (mbsinit (&state)); wc = (wchar_t) 0xBADFACE; src = ""; ret = mbsnrtowcs (&wc, &src, 1, 1, &state); ASSERT (ret == 0); ASSERT (wc == 0); ASSERT (mbsinit (&state)); } if (argc > 1) { int unlimited; for (unlimited = 0; unlimited < 2; unlimited++) { #define BUFSIZE 10 wchar_t buf[BUFSIZE]; const char *src; mbstate_t temp_state; { size_t i; for (i = 0; i < BUFSIZE; i++) buf[i] = (wchar_t) 0xBADFACE; } switch (argv[1][0]) { case '1': /* Locale encoding is ISO-8859-1 or ISO-8859-15. */ { char input[] = "B\374\337er"; /* "Büßer" */ memset (&state, '\0', sizeof (mbstate_t)); wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input, 1, &state); ASSERT (ret == 1); ASSERT (wc == 'B'); ASSERT (mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input + 1, 1, &state); ASSERT (ret == 1); ASSERT (wctob (wc) == (unsigned char) '\374'); ASSERT (mbsinit (&state)); input[1] = '\0'; src = input + 2; temp_state = state; ret = mbsnrtowcs (NULL, &src, 4, unlimited ? BUFSIZE : 1, &temp_state); ASSERT (ret == 3); ASSERT (src == input + 2); ASSERT (mbsinit (&state)); src = input + 2; ret = mbsnrtowcs (buf, &src, 4, unlimited ? BUFSIZE : 1, &state); ASSERT (ret == (unlimited ? 3 : 1)); ASSERT (src == (unlimited ? NULL : input + 3)); ASSERT (wctob (buf[0]) == (unsigned char) '\337'); if (unlimited) { ASSERT (buf[1] == 'e'); ASSERT (buf[2] == 'r'); ASSERT (buf[3] == 0); ASSERT (buf[4] == (wchar_t) 0xBADFACE); } else ASSERT (buf[1] == (wchar_t) 0xBADFACE); ASSERT (mbsinit (&state)); } break; case '2': /* Locale encoding is UTF-8. */ { char input[] = "B\303\274\303\237er"; /* "Büßer" */ memset (&state, '\0', sizeof (mbstate_t)); wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input, 1, &state); ASSERT (ret == 1); ASSERT (wc == 'B'); ASSERT (mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input + 1, 1, &state); ASSERT (ret == (size_t)(-2)); ASSERT (wc == (wchar_t) 0xBADFACE); ASSERT (!mbsinit (&state)); input[1] = '\0'; src = input + 2; temp_state = state; ret = mbsnrtowcs (NULL, &src, 6, unlimited ? BUFSIZE : 2, &temp_state); ASSERT (ret == 4); ASSERT (src == input + 2); ASSERT (!mbsinit (&state)); src = input + 2; ret = mbsnrtowcs (buf, &src, 6, unlimited ? BUFSIZE : 2, &state); ASSERT (ret == (unlimited ? 4 : 2)); ASSERT (src == (unlimited ? NULL : input + 5)); ASSERT (wctob (buf[0]) == EOF); ASSERT (wctob (buf[1]) == EOF); if (unlimited) { ASSERT (buf[2] == 'e'); ASSERT (buf[3] == 'r'); ASSERT (buf[4] == 0); ASSERT (buf[5] == (wchar_t) 0xBADFACE); } else ASSERT (buf[2] == (wchar_t) 0xBADFACE); ASSERT (mbsinit (&state)); } break; case '3': /* Locale encoding is EUC-JP. */ { char input[] = "<\306\374\313\334\270\354>"; /* "<日本語>" */ memset (&state, '\0', sizeof (mbstate_t)); wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input, 1, &state); ASSERT (ret == 1); ASSERT (wc == '<'); ASSERT (mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input + 1, 2, &state); ASSERT (ret == 2); ASSERT (wctob (wc) == EOF); ASSERT (mbsinit (&state)); input[1] = '\0'; input[2] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input + 3, 1, &state); ASSERT (ret == (size_t)(-2)); ASSERT (wc == (wchar_t) 0xBADFACE); ASSERT (!mbsinit (&state)); input[3] = '\0'; src = input + 4; temp_state = state; ret = mbsnrtowcs (NULL, &src, 5, unlimited ? BUFSIZE : 2, &temp_state); ASSERT (ret == 3); ASSERT (src == input + 4); ASSERT (!mbsinit (&state)); src = input + 4; ret = mbsnrtowcs (buf, &src, 5, unlimited ? BUFSIZE : 2, &state); ASSERT (ret == (unlimited ? 3 : 2)); ASSERT (src == (unlimited ? NULL : input + 7)); ASSERT (wctob (buf[0]) == EOF); ASSERT (wctob (buf[1]) == EOF); if (unlimited) { ASSERT (buf[2] == '>'); ASSERT (buf[3] == 0); ASSERT (buf[4] == (wchar_t) 0xBADFACE); } else ASSERT (buf[2] == (wchar_t) 0xBADFACE); ASSERT (mbsinit (&state)); } break; case '4': /* Locale encoding is GB18030. */ { char input[] = "B\250\271\201\060\211\070er"; /* "Büßer" */ memset (&state, '\0', sizeof (mbstate_t)); wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input, 1, &state); ASSERT (ret == 1); ASSERT (wc == 'B'); ASSERT (mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc (&wc, input + 1, 1, &state); ASSERT (ret == (size_t)(-2)); ASSERT (wc == (wchar_t) 0xBADFACE); ASSERT (!mbsinit (&state)); input[1] = '\0'; src = input + 2; temp_state = state; ret = mbsnrtowcs (NULL, &src, 8, unlimited ? BUFSIZE : 2, &temp_state); ASSERT (ret == 4); ASSERT (src == input + 2); ASSERT (!mbsinit (&state)); src = input + 2; ret = mbsnrtowcs (buf, &src, 8, unlimited ? BUFSIZE : 2, &state); ASSERT (ret == (unlimited ? 4 : 2)); ASSERT (src == (unlimited ? NULL : input + 7)); ASSERT (wctob (buf[0]) == EOF); ASSERT (wctob (buf[1]) == EOF); if (unlimited) { ASSERT (buf[2] == 'e'); ASSERT (buf[3] == 'r'); ASSERT (buf[4] == 0); ASSERT (buf[5] == (wchar_t) 0xBADFACE); } else ASSERT (buf[2] == (wchar_t) 0xBADFACE); ASSERT (mbsinit (&state)); } break; default: return 1; } } return 0; } return 1; }
int main(int argc, char *argv[]) { mbstate_t state; wchar_t wc; size_t ret; int mode; /* configure should already have checked that the locale is supported. */ if (setlocale(LC_ALL, "") == NULL) { fprintf(stderr, "unable to set standard locale\n"); return 1; } /* Test NUL byte input. */ { const char *src; memset(&state, '\0', sizeof(mbstate_t)); src = ""; ret = mbsnrtowcs(NULL, &src, 1, 0, &state); assert(ret == 0); assert(mbsinit (&state)); src = ""; ret = mbsnrtowcs(NULL, &src, 1, 1, &state); assert(ret == 0); assert(mbsinit (&state)); wc = (wchar_t) 0xBADFACE; src = ""; ret = mbsnrtowcs(&wc, &src, 1, 0, &state); assert(ret == 0); assert(wc == (wchar_t) 0xBADFACE); assert(mbsinit (&state)); wc = (wchar_t) 0xBADFACE; src = ""; ret = mbsnrtowcs(&wc, &src, 1, 1, &state); assert(ret == 0); assert(wc == 0); assert(mbsinit (&state)); } for (mode = '1'; mode <= '4'; ++mode) { int unlimited; for (unlimited = 0; unlimited < 2; unlimited++) { wchar_t buf[BUFSIZE]; const char *src; mbstate_t temp_state; { size_t i; for (i = 0; i < BUFSIZE; i++) buf[i] = (wchar_t) 0xBADFACE; } switch (mode) { case '1': /* Locale encoding is ISO-8859-1 or ISO-8859-15. */ printf("ISO8859-1 ...\n"); { char input[] = "B\374\337er"; /* "Büßer" */ memset(&state, '\0', sizeof(mbstate_t)); if (setlocale (LC_ALL, "en_US.ISO8859-1") == NULL) { fprintf(stderr, "unable to set ISO8859-1 locale, skipping\n"); break; } wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input, 1, &state); assert(ret == 1); assert(wc == 'B'); assert(mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input + 1, 1, &state); assert(ret == 1); assert(wctob (wc) == (unsigned char) '\374'); assert(mbsinit (&state)); input[1] = '\0'; src = input + 2; temp_state = state; ret = mbsnrtowcs(NULL, &src, 4, unlimited ? BUFSIZE : 1, &temp_state); assert(ret == 3); assert(src == input + 2); assert(mbsinit (&state)); src = input + 2; ret = mbsnrtowcs(buf, &src, 4, unlimited ? BUFSIZE : 1, &state); assert(ret == (unlimited ? 3 : 1)); assert(src == (unlimited ? NULL : input + 3)); assert(wctob (buf[0]) == (unsigned char) '\337'); if (unlimited) { assert(buf[1] == 'e'); assert(buf[2] == 'r'); assert(buf[3] == 0); assert(buf[4] == (wchar_t) 0xBADFACE); } else assert(buf[1] == (wchar_t) 0xBADFACE); assert(mbsinit (&state)); } break; case '2': /* Locale encoding is UTF-8. */ printf("UTF-8 ...\n"); { char input[] = "B\303\274\303\237er"; /* "Büßer" */ memset(&state, '\0', sizeof(mbstate_t)); if (setlocale (LC_ALL, "en_US.UTF-8") == NULL) { fprintf(stderr, "unable to set UTF-8 locale, skipping\n"); break; } wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input, 1, &state); assert(ret == 1); assert(wc == 'B'); assert(mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input + 1, 1, &state); assert(ret == (size_t)(-2)); assert(wc == (wchar_t) 0xBADFACE); assert(!mbsinit (&state)); input[1] = '\0'; // Copying mbstate_t doesn't really copy the ICU-converter's state, so this // doesn't work on Haiku. #ifndef __HAIKU__ src = input + 2; temp_state = state; ret = mbsnrtowcs(NULL, &src, 6, unlimited ? BUFSIZE : 2, &temp_state); assert(ret == 4); assert(src == input + 2); assert(!mbsinit (&state)); #endif src = input + 2; ret = mbsnrtowcs(buf, &src, 6, unlimited ? BUFSIZE : 2, &state); assert(ret == (unlimited ? 4 : 2)); assert(src == (unlimited ? NULL : input + 5)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); if (unlimited) { assert(buf[2] == 'e'); assert(buf[3] == 'r'); assert(buf[4] == 0); assert(buf[5] == (wchar_t) 0xBADFACE); } else assert(buf[2] == (wchar_t) 0xBADFACE); assert(mbsinit (&state)); } break; case '3': /* Locale encoding is EUC-JP. */ printf("EUC-JP ...\n"); { char input[] = "<\306\374\313\334\270\354>"; /* "<日本語>" */ memset(&state, '\0', sizeof(mbstate_t)); if (setlocale (LC_ALL, "en_US.EUC-JP") == NULL) { fprintf(stderr, "unable to set EUC-JP locale, skipping\n"); break; } wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input, 1, &state); assert(ret == 1); assert(wc == '<'); assert(mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input + 1, 2, &state); assert(ret == 2); assert(wctob (wc) == EOF); assert(mbsinit (&state)); input[1] = '\0'; input[2] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input + 3, 1, &state); assert(ret == (size_t)(-2)); assert(wc == (wchar_t) 0xBADFACE); assert(!mbsinit (&state)); input[3] = '\0'; // Copying mbstate_t doesn't really copy the ICU-converter's state, so this // doesn't work on Haiku. #ifndef __HAIKU__ src = input + 4; temp_state = state; ret = mbsnrtowcs(NULL, &src, 5, unlimited ? BUFSIZE : 2, &temp_state); assert(ret == 3); assert(src == input + 4); assert(!mbsinit (&state)); #endif src = input + 4; ret = mbsnrtowcs(buf, &src, 5, unlimited ? BUFSIZE : 2, &state); assert(ret == (unlimited ? 3 : 2)); assert(src == (unlimited ? NULL : input + 7)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); if (unlimited) { assert(buf[2] == '>'); assert(buf[3] == 0); assert(buf[4] == (wchar_t) 0xBADFACE); } else assert(buf[2] == (wchar_t) 0xBADFACE); assert(mbsinit (&state)); } break; case '4': /* Locale encoding is GB18030. */ printf("GB18030 ...\n"); { char input[] = "B\250\271\201\060\211\070er"; /* "Büßer" */ memset(&state, '\0', sizeof(mbstate_t)); if (setlocale (LC_ALL, "en_US.GB18030") == NULL) { fprintf(stderr, "unable to set GB18030 locale, skipping\n"); break; } wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input, 1, &state); assert(ret == 1); assert(wc == 'B'); assert(mbsinit (&state)); input[0] = '\0'; wc = (wchar_t) 0xBADFACE; ret = mbrtowc(&wc, input + 1, 1, &state); assert(ret == (size_t)(-2)); assert(wc == (wchar_t) 0xBADFACE); assert(!mbsinit (&state)); input[1] = '\0'; // Copying mbstate_t doesn't really copy the ICU-converter's state, so this // doesn't work on Haiku. #ifndef __HAIKU__ src = input + 2; temp_state = state; ret = mbsnrtowcs(NULL, &src, 8, unlimited ? BUFSIZE : 2, &temp_state); assert(ret == 4); assert(src == input + 2); assert(!mbsinit (&state)); #endif src = input + 2; ret = mbsnrtowcs(buf, &src, 8, unlimited ? BUFSIZE : 2, &state); assert(ret == (unlimited ? 4 : 2)); assert(src == (unlimited ? NULL : input + 7)); assert(wctob (buf[0]) == EOF); assert(wctob (buf[1]) == EOF); if (unlimited) { assert(buf[2] == 'e'); assert(buf[3] == 'r'); assert(buf[4] == 0); assert(buf[5] == (wchar_t) 0xBADFACE); } else assert(buf[2] == (wchar_t) 0xBADFACE); assert(mbsinit (&state)); } break; default: return 1; } } } return 0; }
size_t mbsrtowcs(wchar_t* dst, const char** src, size_t len, mbstate_t* ps) { return mbsnrtowcs(dst, src, SIZE_MAX, len, ps); }
//! helper that translates an utf8 string to ascii with some error return codes char * utf8toascii(const char *str_src, longlong *len_src, struct workspace_t * ws, char *str_dst, int limit) { mbstate_t *mbstate = ws->mbstate; size_t len_mbsnrtowcs, len_ret = LENGTH_MAX, len_min = LENGTH_MAX; char *ret = str_dst, *in_s = (char *)str_src; //utf8; memset((void *)mbstate, '\0', sizeof(mbstate_t)); if ( (len_mbsnrtowcs = mbsnrtowcs(NULL, &str_src, *len_src, 0, mbstate)) == (size_t) -1 ) { debug_print("str_src(%s): %s", str_src, strerror(errno)); return NULL; } len_min = MIN(len_mbsnrtowcs, limit); debug_print("1] len_mbsnrtowcs(%zu) limit(%d) LENGTH_MAX(%d) min(%zu)", len_mbsnrtowcs, limit, LENGTH_MAX, len_min); if ( len_mbsnrtowcs == *len_src ) { strncpy(str_dst, str_src, len_min); str_dst[len_min] = '\0'; str_dst[len_min + 1] = '\0'; // NULLNULL is proper string ending when parsing utf8 *len_src = len_min; return str_dst; } if ( ws->iconv_init == 0 ) { if ( (ws->ic = iconv_open("ascii//TRANSLIT", "UTF-8")) == (iconv_t) -1 ) { debug_print("%s", "failed to initialize iconv"); return NULL; } ws->iconv_init = 1; } if ( iconv(ws->ic, &in_s, (size_t *) len_src, &ret, &len_ret) == (size_t) -1 ) { debug_print("in_s(%s) len_src(%lld) len_ret(%zu) error: %s", str_src, *len_src, len_ret, strerror(errno)); if ( errno == E2BIG ) { debug_print("inside E2BIG len_mbsnrtowcs(%zu) len_src(%lld)", len_mbsnrtowcs, *len_src); len_mbsnrtowcs = len_min; //LENGTH_MAX; } else { return NULL; } } *len_src = len_min; // adjust converted length str_dst[len_min] = '\0'; str_dst[len_min + 1] = '\0'; // NULLNULL is proper string ending when parsing utf8 // iconv house cleaning as per man 3 iconv_open if ( iconv(ws->ic, NULL, NULL, NULL, NULL) == (size_t) -1 ) { return NULL; } return str_dst; }
static int do_test (void) { struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigemptyset (&sa.sa_mask); sigaction (SIGABRT, &sa, NULL); /* Avoid all the buffer overflow messages on stderr. */ int fd = open (_PATH_DEVNULL, O_WRONLY); if (fd == -1) close (STDERR_FILENO); else { dup2 (fd, STDERR_FILENO); close (fd); } setenv ("LIBC_FATAL_STDERR_", "1", 1); struct A { char buf1[9]; char buf2[1]; } a; struct wA { wchar_t buf1[9]; wchar_t buf2[1]; } wa; printf ("Test checking routines at fortify level %d\n", #ifdef __USE_FORTIFY_LEVEL (int) __USE_FORTIFY_LEVEL #else 0 #endif ); /* These ops can be done without runtime checking of object size. */ memcpy (buf, "abcdefghij", 10); memmove (buf + 1, buf, 9); if (memcmp (buf, "aabcdefghi", 10)) FAIL (); if (mempcpy (buf + 5, "abcde", 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10)) FAIL (); memset (buf + 8, 'j', 2); if (memcmp (buf, "aabcdabcjj", 10)) FAIL (); strcpy (buf + 4, "EDCBA"); if (memcmp (buf, "aabcEDCBA", 10)) FAIL (); if (stpcpy (buf + 8, "F") != buf + 9 || memcmp (buf, "aabcEDCBF", 10)) FAIL (); strncpy (buf + 6, "X", 4); if (memcmp (buf, "aabcEDX\0\0", 10)) FAIL (); if (sprintf (buf + 7, "%s", "67") != 2 || memcmp (buf, "aabcEDX67", 10)) FAIL (); if (snprintf (buf + 7, 3, "%s", "987654") != 6 || memcmp (buf, "aabcEDX98", 10)) FAIL (); /* These ops need runtime checking, but shouldn't __chk_fail. */ memcpy (buf, "abcdefghij", l0 + 10); memmove (buf + 1, buf, l0 + 9); if (memcmp (buf, "aabcdefghi", 10)) FAIL (); if (mempcpy (buf + 5, "abcde", l0 + 5) != buf + 10 || memcmp (buf, "aabcdabcde", 10)) FAIL (); memset (buf + 8, 'j', l0 + 2); if (memcmp (buf, "aabcdabcjj", 10)) FAIL (); strcpy (buf + 4, str1 + 5); if (memcmp (buf, "aabcEDCBA", 10)) FAIL (); if (stpcpy (buf + 8, str2) != buf + 9 || memcmp (buf, "aabcEDCBF", 10)) FAIL (); strncpy (buf + 6, "X", l0 + 4); if (memcmp (buf, "aabcEDX\0\0", 10)) FAIL (); if (stpncpy (buf + 5, "cd", l0 + 5) != buf + 7 || memcmp (buf, "aabcEcd\0\0", 10)) FAIL (); if (sprintf (buf + 7, "%d", num1) != 2 || memcmp (buf, "aabcEcd67", 10)) FAIL (); if (snprintf (buf + 7, 3, "%d", num2) != 6 || memcmp (buf, "aabcEcd98", 10)) FAIL (); buf[l0 + 8] = '\0'; strcat (buf, "A"); if (memcmp (buf, "aabcEcd9A", 10)) FAIL (); buf[l0 + 7] = '\0'; strncat (buf, "ZYXWV", l0 + 2); if (memcmp (buf, "aabcEcdZY", 10)) FAIL (); memcpy (a.buf1, "abcdefghij", l0 + 10); memmove (a.buf1 + 1, a.buf1, l0 + 9); if (memcmp (a.buf1, "aabcdefghi", 10)) FAIL (); if (mempcpy (a.buf1 + 5, "abcde", l0 + 5) != a.buf1 + 10 || memcmp (a.buf1, "aabcdabcde", 10)) FAIL (); memset (a.buf1 + 8, 'j', l0 + 2); if (memcmp (a.buf1, "aabcdabcjj", 10)) FAIL (); #if __USE_FORTIFY_LEVEL < 2 /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2 and sufficient GCC support, as the string operations overflow from a.buf1 into a.buf2. */ strcpy (a.buf1 + 4, str1 + 5); if (memcmp (a.buf1, "aabcEDCBA", 10)) FAIL (); if (stpcpy (a.buf1 + 8, str2) != a.buf1 + 9 || memcmp (a.buf1, "aabcEDCBF", 10)) FAIL (); strncpy (a.buf1 + 6, "X", l0 + 4); if (memcmp (a.buf1, "aabcEDX\0\0", 10)) FAIL (); if (sprintf (a.buf1 + 7, "%d", num1) != 2 || memcmp (a.buf1, "aabcEDX67", 10)) FAIL (); if (snprintf (a.buf1 + 7, 3, "%d", num2) != 6 || memcmp (a.buf1, "aabcEDX98", 10)) FAIL (); a.buf1[l0 + 8] = '\0'; strcat (a.buf1, "A"); if (memcmp (a.buf1, "aabcEDX9A", 10)) FAIL (); a.buf1[l0 + 7] = '\0'; strncat (a.buf1, "ZYXWV", l0 + 2); if (memcmp (a.buf1, "aabcEDXZY", 10)) FAIL (); #endif #if __USE_FORTIFY_LEVEL >= 1 /* Now check if all buffer overflows are caught at runtime. */ CHK_FAIL_START memcpy (buf + 1, "abcdefghij", l0 + 10); CHK_FAIL_END CHK_FAIL_START memmove (buf + 2, buf + 1, l0 + 9); CHK_FAIL_END CHK_FAIL_START p = mempcpy (buf + 6, "abcde", l0 + 5); CHK_FAIL_END CHK_FAIL_START memset (buf + 9, 'j', l0 + 2); CHK_FAIL_END CHK_FAIL_START strcpy (buf + 5, str1 + 5); CHK_FAIL_END CHK_FAIL_START p = stpcpy (buf + 9, str2); CHK_FAIL_END CHK_FAIL_START strncpy (buf + 7, "X", l0 + 4); CHK_FAIL_END CHK_FAIL_START stpncpy (buf + 6, "cd", l0 + 5); CHK_FAIL_END CHK_FAIL_START sprintf (buf + 8, "%d", num1); CHK_FAIL_END CHK_FAIL_START snprintf (buf + 8, l0 + 3, "%d", num2); CHK_FAIL_END memcpy (buf, str1 + 2, l0 + 9); CHK_FAIL_START strcat (buf, "AB"); CHK_FAIL_END memcpy (buf, str1 + 3, l0 + 8); CHK_FAIL_START strncat (buf, "ZYXWV", l0 + 3); CHK_FAIL_END CHK_FAIL_START memcpy (a.buf1 + 1, "abcdefghij", l0 + 10); CHK_FAIL_END CHK_FAIL_START memmove (a.buf1 + 2, a.buf1 + 1, l0 + 9); CHK_FAIL_END CHK_FAIL_START p = mempcpy (a.buf1 + 6, "abcde", l0 + 5); CHK_FAIL_END CHK_FAIL_START memset (a.buf1 + 9, 'j', l0 + 2); CHK_FAIL_END #if __USE_FORTIFY_LEVEL >= 2 # define O 0 #else # define O 1 #endif CHK_FAIL_START strcpy (a.buf1 + (O + 4), str1 + 5); CHK_FAIL_END CHK_FAIL_START p = stpcpy (a.buf1 + (O + 8), str2); CHK_FAIL_END CHK_FAIL_START strncpy (a.buf1 + (O + 6), "X", l0 + 4); CHK_FAIL_END CHK_FAIL_START sprintf (a.buf1 + (O + 7), "%d", num1); CHK_FAIL_END CHK_FAIL_START snprintf (a.buf1 + (O + 7), l0 + 3, "%d", num2); CHK_FAIL_END memcpy (a.buf1, str1 + (3 - O), l0 + 8 + O); CHK_FAIL_START strcat (a.buf1, "AB"); CHK_FAIL_END memcpy (a.buf1, str1 + (4 - O), l0 + 7 + O); CHK_FAIL_START strncat (a.buf1, "ZYXWV", l0 + 3); CHK_FAIL_END #endif /* These ops can be done without runtime checking of object size. */ wmemcpy (wbuf, L"abcdefghij", 10); wmemmove (wbuf + 1, wbuf, 9); if (wmemcmp (wbuf, L"aabcdefghi", 10)) FAIL (); if (wmempcpy (wbuf + 5, L"abcde", 5) != wbuf + 10 || wmemcmp (wbuf, L"aabcdabcde", 10)) FAIL (); wmemset (wbuf + 8, L'j', 2); if (wmemcmp (wbuf, L"aabcdabcjj", 10)) FAIL (); wcscpy (wbuf + 4, L"EDCBA"); if (wmemcmp (wbuf, L"aabcEDCBA", 10)) FAIL (); if (wcpcpy (wbuf + 8, L"F") != wbuf + 9 || wmemcmp (wbuf, L"aabcEDCBF", 10)) FAIL (); wcsncpy (wbuf + 6, L"X", 4); if (wmemcmp (wbuf, L"aabcEDX\0\0", 10)) FAIL (); if (swprintf (wbuf + 7, 3, L"%ls", L"987654") >= 0 || wmemcmp (wbuf, L"aabcEDX98", 10)) FAIL (); if (swprintf (wbuf + 7, 3, L"64") != 2 || wmemcmp (wbuf, L"aabcEDX64", 10)) FAIL (); /* These ops need runtime checking, but shouldn't __chk_fail. */ wmemcpy (wbuf, L"abcdefghij", l0 + 10); wmemmove (wbuf + 1, wbuf, l0 + 9); if (wmemcmp (wbuf, L"aabcdefghi", 10)) FAIL (); if (wmempcpy (wbuf + 5, L"abcde", l0 + 5) != wbuf + 10 || wmemcmp (wbuf, L"aabcdabcde", 10)) FAIL (); wmemset (wbuf + 8, L'j', l0 + 2); if (wmemcmp (wbuf, L"aabcdabcjj", 10)) FAIL (); wcscpy (wbuf + 4, wstr1 + 5); if (wmemcmp (wbuf, L"aabcEDCBA", 10)) FAIL (); if (wcpcpy (wbuf + 8, wstr2) != wbuf + 9 || wmemcmp (wbuf, L"aabcEDCBF", 10)) FAIL (); wcsncpy (wbuf + 6, L"X", l0 + 4); if (wmemcmp (wbuf, L"aabcEDX\0\0", 10)) FAIL (); if (wcpncpy (wbuf + 5, L"cd", l0 + 5) != wbuf + 7 || wmemcmp (wbuf, L"aabcEcd\0\0", 10)) FAIL (); if (swprintf (wbuf + 7, 3, L"%d", num2) >= 0 || wmemcmp (wbuf, L"aabcEcd98", 10)) FAIL (); wbuf[l0 + 8] = L'\0'; wcscat (wbuf, L"A"); if (wmemcmp (wbuf, L"aabcEcd9A", 10)) FAIL (); wbuf[l0 + 7] = L'\0'; wcsncat (wbuf, L"ZYXWV", l0 + 2); if (wmemcmp (wbuf, L"aabcEcdZY", 10)) FAIL (); wmemcpy (wa.buf1, L"abcdefghij", l0 + 10); wmemmove (wa.buf1 + 1, wa.buf1, l0 + 9); if (wmemcmp (wa.buf1, L"aabcdefghi", 10)) FAIL (); if (wmempcpy (wa.buf1 + 5, L"abcde", l0 + 5) != wa.buf1 + 10 || wmemcmp (wa.buf1, L"aabcdabcde", 10)) FAIL (); wmemset (wa.buf1 + 8, L'j', l0 + 2); if (wmemcmp (wa.buf1, L"aabcdabcjj", 10)) FAIL (); #if __USE_FORTIFY_LEVEL < 2 /* The following tests are supposed to crash with -D_FORTIFY_SOURCE=2 and sufficient GCC support, as the string operations overflow from a.buf1 into a.buf2. */ wcscpy (wa.buf1 + 4, wstr1 + 5); if (wmemcmp (wa.buf1, L"aabcEDCBA", 10)) FAIL (); if (wcpcpy (wa.buf1 + 8, wstr2) != wa.buf1 + 9 || wmemcmp (wa.buf1, L"aabcEDCBF", 10)) FAIL (); wcsncpy (wa.buf1 + 6, L"X", l0 + 4); if (wmemcmp (wa.buf1, L"aabcEDX\0\0", 10)) FAIL (); if (swprintf (wa.buf1 + 7, 3, L"%d", num2) >= 0 || wmemcmp (wa.buf1, L"aabcEDX98", 10)) FAIL (); wa.buf1[l0 + 8] = L'\0'; wcscat (wa.buf1, L"A"); if (wmemcmp (wa.buf1, L"aabcEDX9A", 10)) FAIL (); wa.buf1[l0 + 7] = L'\0'; wcsncat (wa.buf1, L"ZYXWV", l0 + 2); if (wmemcmp (wa.buf1, L"aabcEDXZY", 10)) FAIL (); #endif #if __USE_FORTIFY_LEVEL >= 1 /* Now check if all buffer overflows are caught at runtime. */ CHK_FAIL_START wmemcpy (wbuf + 1, L"abcdefghij", l0 + 10); CHK_FAIL_END CHK_FAIL_START wmemmove (wbuf + 2, wbuf + 1, l0 + 9); CHK_FAIL_END CHK_FAIL_START wp = wmempcpy (wbuf + 6, L"abcde", l0 + 5); CHK_FAIL_END CHK_FAIL_START wmemset (wbuf + 9, L'j', l0 + 2); CHK_FAIL_END CHK_FAIL_START wcscpy (wbuf + 5, wstr1 + 5); CHK_FAIL_END CHK_FAIL_START wp = wcpcpy (wbuf + 9, wstr2); CHK_FAIL_END CHK_FAIL_START wcsncpy (wbuf + 7, L"X", l0 + 4); CHK_FAIL_END CHK_FAIL_START wcpncpy (wbuf + 6, L"cd", l0 + 5); CHK_FAIL_END wmemcpy (wbuf, wstr1 + 2, l0 + 9); CHK_FAIL_START wcscat (wbuf, L"AB"); CHK_FAIL_END wmemcpy (wbuf, wstr1 + 3, l0 + 8); CHK_FAIL_START wcsncat (wbuf, L"ZYXWV", l0 + 3); CHK_FAIL_END CHK_FAIL_START wmemcpy (wa.buf1 + 1, L"abcdefghij", l0 + 10); CHK_FAIL_END CHK_FAIL_START wmemmove (wa.buf1 + 2, wa.buf1 + 1, l0 + 9); CHK_FAIL_END CHK_FAIL_START wp = wmempcpy (wa.buf1 + 6, L"abcde", l0 + 5); CHK_FAIL_END CHK_FAIL_START wmemset (wa.buf1 + 9, L'j', l0 + 2); CHK_FAIL_END #if __USE_FORTIFY_LEVEL >= 2 # define O 0 #else # define O 1 #endif CHK_FAIL_START wcscpy (wa.buf1 + (O + 4), wstr1 + 5); CHK_FAIL_END CHK_FAIL_START wp = wcpcpy (wa.buf1 + (O + 8), wstr2); CHK_FAIL_END CHK_FAIL_START wcsncpy (wa.buf1 + (O + 6), L"X", l0 + 4); CHK_FAIL_END wmemcpy (wa.buf1, wstr1 + (3 - O), l0 + 8 + O); CHK_FAIL_START wcscat (wa.buf1, L"AB"); CHK_FAIL_END wmemcpy (wa.buf1, wstr1 + (4 - O), l0 + 7 + O); CHK_FAIL_START wcsncat (wa.buf1, L"ZYXWV", l0 + 3); CHK_FAIL_END #endif /* Now checks for %n protection. */ /* Constant literals passed directly are always ok (even with warnings about possible bugs from GCC). */ int n1, n2; if (sprintf (buf, "%s%n%s%n", str2, &n1, str2, &n2) != 2 || n1 != 1 || n2 != 2) FAIL (); /* In this case the format string is not known at compile time, but resides in read-only memory, so is ok. */ if (snprintf (buf, 4, str3, str2, &n1, str2, &n2) != 2 || n1 != 1 || n2 != 2) FAIL (); strcpy (buf2 + 2, "%n%s%n"); /* When the format string is writable and contains %n, with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ CHK_FAIL2_START if (sprintf (buf, buf2, str2, &n1, str2, &n1) != 2) FAIL (); CHK_FAIL2_END CHK_FAIL2_START if (snprintf (buf, 3, buf2, str2, &n1, str2, &n1) != 2) FAIL (); CHK_FAIL2_END /* But if there is no %n, even writable format string should work. */ buf2[6] = '\0'; if (sprintf (buf, buf2 + 4, str2) != 1) FAIL (); /* Constant literals passed directly are always ok (even with warnings about possible bugs from GCC). */ if (printf ("%s%n%s%n", str4, &n1, str5, &n2) != 14 || n1 != 7 || n2 != 14) FAIL (); /* In this case the format string is not known at compile time, but resides in read-only memory, so is ok. */ if (printf (str3, str4, &n1, str5, &n2) != 14 || n1 != 7 || n2 != 14) FAIL (); strcpy (buf2 + 2, "%n%s%n"); /* When the format string is writable and contains %n, with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ CHK_FAIL2_START if (printf (buf2, str4, &n1, str5, &n1) != 14) FAIL (); CHK_FAIL2_END /* But if there is no %n, even writable format string should work. */ buf2[6] = '\0'; if (printf (buf2 + 4, str5) != 7) FAIL (); FILE *fp = stdout; /* Constant literals passed directly are always ok (even with warnings about possible bugs from GCC). */ if (fprintf (fp, "%s%n%s%n", str4, &n1, str5, &n2) != 14 || n1 != 7 || n2 != 14) FAIL (); /* In this case the format string is not known at compile time, but resides in read-only memory, so is ok. */ if (fprintf (fp, str3, str4, &n1, str5, &n2) != 14 || n1 != 7 || n2 != 14) FAIL (); strcpy (buf2 + 2, "%n%s%n"); /* When the format string is writable and contains %n, with -D_FORTIFY_SOURCE=2 it causes __chk_fail. */ CHK_FAIL2_START if (fprintf (fp, buf2, str4, &n1, str5, &n1) != 14) FAIL (); CHK_FAIL2_END /* But if there is no %n, even writable format string should work. */ buf2[6] = '\0'; if (fprintf (fp, buf2 + 4, str5) != 7) FAIL (); if (freopen (temp_filename, "r", stdin) == NULL) { puts ("could not open temporary file"); exit (1); } if (gets (buf) != buf || memcmp (buf, "abcdefgh", 9)) FAIL (); if (gets (buf) != buf || memcmp (buf, "ABCDEFGHI", 10)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (gets (buf) != buf) FAIL (); CHK_FAIL_END #endif rewind (stdin); if (fgets (buf, sizeof (buf), stdin) != buf || memcmp (buf, "abcdefgh\n", 10)) FAIL (); if (fgets (buf, sizeof (buf), stdin) != buf || memcmp (buf, "ABCDEFGHI", 10)) FAIL (); rewind (stdin); if (fgets (buf, l0 + sizeof (buf), stdin) != buf || memcmp (buf, "abcdefgh\n", 10)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (fgets (buf, sizeof (buf) + 1, stdin) != buf) FAIL (); CHK_FAIL_END CHK_FAIL_START if (fgets (buf, l0 + sizeof (buf) + 1, stdin) != buf) FAIL (); CHK_FAIL_END #endif rewind (stdin); if (fgets_unlocked (buf, sizeof (buf), stdin) != buf || memcmp (buf, "abcdefgh\n", 10)) FAIL (); if (fgets_unlocked (buf, sizeof (buf), stdin) != buf || memcmp (buf, "ABCDEFGHI", 10)) FAIL (); rewind (stdin); if (fgets_unlocked (buf, l0 + sizeof (buf), stdin) != buf || memcmp (buf, "abcdefgh\n", 10)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (fgets_unlocked (buf, sizeof (buf) + 1, stdin) != buf) FAIL (); CHK_FAIL_END CHK_FAIL_START if (fgets_unlocked (buf, l0 + sizeof (buf) + 1, stdin) != buf) FAIL (); CHK_FAIL_END #endif lseek (fileno (stdin), 0, SEEK_SET); if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1 || memcmp (buf, "abcdefgh\n", 9)) FAIL (); if (read (fileno (stdin), buf, sizeof (buf) - 1) != sizeof (buf) - 1 || memcmp (buf, "ABCDEFGHI", 9)) FAIL (); lseek (fileno (stdin), 0, SEEK_SET); if (read (fileno (stdin), buf, l0 + sizeof (buf) - 1) != sizeof (buf) - 1 || memcmp (buf, "abcdefgh\n", 9)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (read (fileno (stdin), buf, sizeof (buf) + 1) != sizeof (buf) + 1) FAIL (); CHK_FAIL_END #endif if (pread (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2) != sizeof (buf) - 1 || memcmp (buf, "\nABCDEFGH", 9)) FAIL (); if (pread (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1 || memcmp (buf, "abcdefgh\n", 9)) FAIL (); if (pread (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3) != sizeof (buf) - 1 || memcmp (buf, "h\nABCDEFG", 9)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (pread (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf)) != sizeof (buf) + 1) FAIL (); CHK_FAIL_END #endif if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, sizeof (buf) - 2) != sizeof (buf) - 1 || memcmp (buf, "\nABCDEFGH", 9)) FAIL (); if (pread64 (fileno (stdin), buf, sizeof (buf) - 1, 0) != sizeof (buf) - 1 || memcmp (buf, "abcdefgh\n", 9)) FAIL (); if (pread64 (fileno (stdin), buf, l0 + sizeof (buf) - 1, sizeof (buf) - 3) != sizeof (buf) - 1 || memcmp (buf, "h\nABCDEFG", 9)) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (pread64 (fileno (stdin), buf, sizeof (buf) + 1, 2 * sizeof (buf)) != sizeof (buf) + 1) FAIL (); CHK_FAIL_END #endif if (freopen (temp_filename, "r", stdin) == NULL) { puts ("could not open temporary file"); exit (1); } if (fseek (stdin, 9 + 10 + 11, SEEK_SET)) { puts ("could not seek in test file"); exit (1); } #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (gets (buf) != buf) FAIL (); CHK_FAIL_END #endif /* Check whether missing N$ formats are detected. */ CHK_FAIL2_START printf ("%3$d\n", 1, 2, 3, 4); CHK_FAIL2_END CHK_FAIL2_START fprintf (stdout, "%3$d\n", 1, 2, 3, 4); CHK_FAIL2_END CHK_FAIL2_START sprintf (buf, "%3$d\n", 1, 2, 3, 4); CHK_FAIL2_END CHK_FAIL2_START snprintf (buf, sizeof (buf), "%3$d\n", 1, 2, 3, 4); CHK_FAIL2_END int sp[2]; if (socketpair (PF_UNIX, SOCK_STREAM, 0, sp)) FAIL (); else { const char *sendstr = "abcdefgh\nABCDEFGH\n0123456789\n"; if (send (sp[0], sendstr, strlen (sendstr), 0) != strlen (sendstr)) FAIL (); char recvbuf[12]; if (recv (sp[1], recvbuf, sizeof recvbuf, MSG_PEEK) != sizeof recvbuf || memcmp (recvbuf, sendstr, sizeof recvbuf) != 0) FAIL (); if (recv (sp[1], recvbuf + 6, l0 + sizeof recvbuf - 7, MSG_PEEK) != sizeof recvbuf - 7 || memcmp (recvbuf + 6, sendstr, sizeof recvbuf - 7) != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (recv (sp[1], recvbuf + 1, sizeof recvbuf, MSG_PEEK) != sizeof recvbuf) FAIL (); CHK_FAIL_END CHK_FAIL_START if (recv (sp[1], recvbuf + 4, l0 + sizeof recvbuf - 3, MSG_PEEK) != sizeof recvbuf - 3) FAIL (); CHK_FAIL_END #endif socklen_t sl; struct sockaddr_un sa_un; sl = sizeof (sa_un); if (recvfrom (sp[1], recvbuf, sizeof recvbuf, MSG_PEEK, &sa_un, &sl) != sizeof recvbuf || memcmp (recvbuf, sendstr, sizeof recvbuf) != 0) FAIL (); sl = sizeof (sa_un); if (recvfrom (sp[1], recvbuf + 6, l0 + sizeof recvbuf - 7, MSG_PEEK, &sa_un, &sl) != sizeof recvbuf - 7 || memcmp (recvbuf + 6, sendstr, sizeof recvbuf - 7) != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START sl = sizeof (sa_un); if (recvfrom (sp[1], recvbuf + 1, sizeof recvbuf, MSG_PEEK, &sa_un, &sl) != sizeof recvbuf) FAIL (); CHK_FAIL_END CHK_FAIL_START sl = sizeof (sa_un); if (recvfrom (sp[1], recvbuf + 4, l0 + sizeof recvbuf - 3, MSG_PEEK, &sa_un, &sl) != sizeof recvbuf - 3) FAIL (); CHK_FAIL_END #endif close (sp[0]); close (sp[1]); } char fname[] = "/tmp/tst-chk1-dir-XXXXXX\0foo"; char *enddir = strchr (fname, '\0'); if (mkdtemp (fname) == NULL) { printf ("mkdtemp failed: %m\n"); return 1; } *enddir = '/'; if (symlink ("bar", fname) != 0) FAIL (); char readlinkbuf[4]; if (readlink (fname, readlinkbuf, 4) != 3 || memcmp (readlinkbuf, "bar", 3) != 0) FAIL (); if (readlink (fname, readlinkbuf + 1, l0 + 3) != 3 || memcmp (readlinkbuf, "bbar", 4) != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (readlink (fname, readlinkbuf + 2, l0 + 3) != 3) FAIL (); CHK_FAIL_END CHK_FAIL_START if (readlink (fname, readlinkbuf + 3, 4) != 3) FAIL (); CHK_FAIL_END #endif char *cwd1 = getcwd (NULL, 0); if (cwd1 == NULL) FAIL (); char *cwd2 = getcwd (NULL, 250); if (cwd2 == NULL) FAIL (); if (cwd1 && cwd2) { if (strcmp (cwd1, cwd2) != 0) FAIL (); *enddir = '\0'; if (chdir (fname)) FAIL (); char *cwd3 = getcwd (NULL, 0); if (cwd3 == NULL) FAIL (); if (strcmp (fname, cwd3) != 0) printf ("getcwd after chdir is '%s' != '%s'," "get{c,}wd tests skipped\n", cwd3, fname); else { char getcwdbuf[sizeof fname - 3]; char *cwd4 = getcwd (getcwdbuf, sizeof getcwdbuf); if (cwd4 != getcwdbuf || strcmp (getcwdbuf, fname) != 0) FAIL (); cwd4 = getcwd (getcwdbuf + 1, l0 + sizeof getcwdbuf - 1); if (cwd4 != getcwdbuf + 1 || getcwdbuf[0] != fname[0] || strcmp (getcwdbuf + 1, fname) != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (getcwd (getcwdbuf + 2, l0 + sizeof getcwdbuf) != getcwdbuf + 2) FAIL (); CHK_FAIL_END CHK_FAIL_START if (getcwd (getcwdbuf + 2, sizeof getcwdbuf) != getcwdbuf + 2) FAIL (); CHK_FAIL_END #endif if (getwd (getcwdbuf) != getcwdbuf || strcmp (getcwdbuf, fname) != 0) FAIL (); if (getwd (getcwdbuf + 1) != getcwdbuf + 1 || strcmp (getcwdbuf + 1, fname) != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START if (getwd (getcwdbuf + 2) != getcwdbuf + 2) FAIL (); CHK_FAIL_END #endif } if (chdir (cwd1) != 0) FAIL (); free (cwd3); } free (cwd1); free (cwd2); *enddir = '/'; if (unlink (fname) != 0) FAIL (); *enddir = '\0'; if (rmdir (fname) != 0) FAIL (); #if PATH_MAX > 0 char largebuf[PATH_MAX]; char *realres = realpath (".", largebuf); if (realres != largebuf) FAIL (); # if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START char realbuf[1]; realres = realpath (".", realbuf); if (realres != realbuf) FAIL (); CHK_FAIL_END # endif #endif if (setlocale (LC_ALL, "de_DE.UTF-8") != NULL) { assert (MB_CUR_MAX <= 10); /* First a simple test. */ char enough[10]; if (wctomb (enough, L'A') != 1) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 /* We know the wchar_t encoding is ISO 10646. So pick a character which has a multibyte representation which does not fit. */ CHK_FAIL_START char smallbuf[2]; if (wctomb (smallbuf, L'\x100') != 2) FAIL (); CHK_FAIL_END #endif mbstate_t s; memset (&s, '\0', sizeof (s)); if (wcrtomb (enough, L'D', &s) != 1 || enough[0] != 'D') FAIL (); #if __USE_FORTIFY_LEVEL >= 1 /* We know the wchar_t encoding is ISO 10646. So pick a character which has a multibyte representation which does not fit. */ CHK_FAIL_START char smallbuf[2]; if (wcrtomb (smallbuf, L'\x100', &s) != 2) FAIL (); CHK_FAIL_END #endif wchar_t wenough[10]; memset (&s, '\0', sizeof (s)); const char *cp = "A"; if (mbsrtowcs (wenough, &cp, 10, &s) != 1 || wcscmp (wenough, L"A") != 0) FAIL (); cp = "BC"; if (mbsrtowcs (wenough, &cp, l0 + 10, &s) != 2 || wcscmp (wenough, L"BC") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START wchar_t wsmallbuf[2]; cp = "ABC"; mbsrtowcs (wsmallbuf, &cp, 10, &s); CHK_FAIL_END #endif cp = "A"; if (mbstowcs (wenough, cp, 10) != 1 || wcscmp (wenough, L"A") != 0) FAIL (); cp = "DEF"; if (mbstowcs (wenough, cp, l0 + 10) != 3 || wcscmp (wenough, L"DEF") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START wchar_t wsmallbuf[2]; cp = "ABC"; mbstowcs (wsmallbuf, cp, 10); CHK_FAIL_END #endif memset (&s, '\0', sizeof (s)); cp = "ABC"; wcscpy (wenough, L"DEF"); if (mbsnrtowcs (wenough, &cp, 1, 10, &s) != 1 || wcscmp (wenough, L"AEF") != 0) FAIL (); cp = "IJ"; if (mbsnrtowcs (wenough, &cp, 1, l0 + 10, &s) != 1 || wcscmp (wenough, L"IEF") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START wchar_t wsmallbuf[2]; cp = "ABC"; mbsnrtowcs (wsmallbuf, &cp, 3, 10, &s); CHK_FAIL_END #endif memset (&s, '\0', sizeof (s)); const wchar_t *wcp = L"A"; if (wcsrtombs (enough, &wcp, 10, &s) != 1 || strcmp (enough, "A") != 0) FAIL (); wcp = L"BC"; if (wcsrtombs (enough, &wcp, l0 + 10, &s) != 2 || strcmp (enough, "BC") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START char smallbuf[2]; wcp = L"ABC"; wcsrtombs (smallbuf, &wcp, 10, &s); CHK_FAIL_END #endif memset (enough, 'Z', sizeof (enough)); wcp = L"EF"; if (wcstombs (enough, wcp, 10) != 2 || strcmp (enough, "EF") != 0) FAIL (); wcp = L"G"; if (wcstombs (enough, wcp, l0 + 10) != 1 || strcmp (enough, "G") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START char smallbuf[2]; wcp = L"ABC"; wcstombs (smallbuf, wcp, 10); CHK_FAIL_END #endif memset (&s, '\0', sizeof (s)); wcp = L"AB"; if (wcsnrtombs (enough, &wcp, 1, 10, &s) != 1 || strcmp (enough, "A") != 0) FAIL (); wcp = L"BCD"; if (wcsnrtombs (enough, &wcp, 1, l0 + 10, &s) != 1 || strcmp (enough, "B") != 0) FAIL (); #if __USE_FORTIFY_LEVEL >= 1 CHK_FAIL_START char smallbuf[2]; wcp = L"ABC"; wcsnrtombs (smallbuf, &wcp, 3, 10, &s); CHK_FAIL_END #endif }
int main(int argc, char *argv[]) { char srcbuf[128]; wchar_t dstbuf[128]; char *src; mbstate_t s; /* * C/POSIX locale. */ printf("1..1\n"); /* Simple null terminated string. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); src = srcbuf; memset(&s, 0, sizeof(s)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 5); assert(wcscmp(dstbuf, L"hello") == 0); assert(dstbuf[6] == 0xcccc); assert(src == NULL); /* Simple null terminated string, stopping early. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); src = srcbuf; memset(&s, 0, sizeof(s)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 4, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 4); assert(wmemcmp(dstbuf, L"hell", 4) == 0); assert(dstbuf[5] == 0xcccc); assert(src == srcbuf + 4); /* Not enough space in destination buffer. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); src = srcbuf; memset(&s, 0, sizeof(s)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 6, 4, &s) == 4); assert(wmemcmp(dstbuf, L"hell", 4) == 0); assert(dstbuf[5] == 0xcccc); assert(src == srcbuf + 4); /* Null terminated string, internal dest. buffer */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); src = srcbuf; memset(&s, 0, sizeof(s)); assert(mbsnrtowcs(NULL, (const char **)&src, 6, 0, &s) == 5); /* Null terminated string, internal dest. buffer, stopping early */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); src = srcbuf; memset(&s, 0, sizeof(s)); assert(mbsnrtowcs(NULL, (const char **)&src, 4, 0, &s) == 4); /* Null terminated string, internal state. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); src = srcbuf; assert(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) / sizeof(*dstbuf), NULL) == 5); assert(wcscmp(dstbuf, L"hello") == 0); assert(dstbuf[6] == 0xcccc); assert(src == NULL); /* Null terminated string, internal state, internal dest. buffer. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); src = srcbuf; assert(mbsnrtowcs(NULL, (const char **)&src, 6, 0, NULL) == 5); /* Empty source buffer. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); srcbuf[0] = '\0'; src = srcbuf; memset(&s, 0, sizeof(s)); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 1, 1, &s) == 0); assert(dstbuf[0] == 0); assert(dstbuf[1] == 0xcccc); assert(src == NULL); /* Zero length destination buffer. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "hello"); src = srcbuf; memset(&s, 0, sizeof(s)); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 1, 0, &s) == 0); assert(dstbuf[0] == 0xcccc); assert(src == srcbuf); /* Zero length source buffer. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); src = srcbuf; memset(&s, 0, sizeof(s)); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 0, 1, &s) == 0); assert(dstbuf[0] == 0xcccc); assert(src == srcbuf); /* * Japanese (EUC) locale. */ assert(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0); assert(MB_CUR_MAX > 1); memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3"); src = srcbuf; memset(&s, 0, sizeof(s)); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 8, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 5); assert(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 && dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0); assert(src == NULL); /* Partial character. */ memset(srcbuf, 0xcc, sizeof(srcbuf)); strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3"); src = srcbuf; memset(&s, 0, sizeof(s)); wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 4); assert(src == srcbuf + 6); assert(!mbsinit(&s)); assert(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 1); assert(src == srcbuf + 7); assert(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) / sizeof(*dstbuf), &s) == 0); assert(src == NULL); printf("ok 1 - mbsnrtowcs()\n"); return (0); }
/** * Decodes an (external) UTF-8 Unicode multibyte character stream into an (internal) UTF-32 Unicode wide character vector. * * @param p0 the destination wide character array (Hand over as reference!) * @param p1 the destination wide character array count * @param p2 the destination wide character array size * @param p3 the source UTF-8 Unicode multibyte character stream * @param p4 the source UTF-8 Unicode multibyte character stream count */ void decode_utf_8_unicode_character_vector(void* p0, void* p1, void* p2, void* p3, void* p4) { if (p4 != *NULL_POINTER_MEMORY_MODEL) { int* sc = (int*) p4; if (p3 != *NULL_POINTER_MEMORY_MODEL) { char* s = (char*) p3; if (p2 != *NULL_POINTER_MEMORY_MODEL) { int* ds = (int*) p2; if (p1 != *NULL_POINTER_MEMORY_MODEL) { int* dc = (int*) p1; if (p0 != *NULL_POINTER_MEMORY_MODEL) { wchar_t** d = (wchar_t**) p0; if (*dc >= *NUMBER_0_INTEGER_MEMORY_MODEL) { log_terminated_message((void*) INFORMATION_LEVEL_LOG_MODEL, (void*) L"Decode UTF-8 Unicode character vector."); // The new destination wide character vector size. // // CAUTION! The "worst case" is assumed, i.e. that each source character // represents an ascii character encoded by utf-8 with ONE single byte. // Therefore, the destination size is adjusted accordingly. // In case not all source characters are ascii characters -- even better, // since then more than just one source character were used for encoding, // and the destination wide character array will have LESS entries (count) // than the destination size that was set before. // In this case, the destination size will be too big, but can be reduced // to the actual destination count below, if so wanted. *ds = *dc + (*sc * *NUMBER_1_INTEGER_MEMORY_MODEL); // Reallocate destination wide character vector. reallocate_array(p0, p1, p2, (void*) WIDE_CHARACTER_PRIMITIVE_MEMORY_ABSTRACTION); // Set locale. // // Possible locales are: LANG, LC_CTYPE, ..., LC_ALL // where LANG has the lowest and LC_ALL the highest priority. // That is, if LC_ALL is specified, it overwrites e.g. the LC_CTYPE setting. // If no value "" is given, the default will be used. // Note, that LC_CTYPE suffices for the purpose of character conversion, // since it is the category that applies to classification and conversion // of characters, and to multibyte and wide characters. // // CAUTION! This setting is necessary for UTF-8 Unicode character conversion // with restartable multibyte conversion functions like "mbsnrtowcs" // and "wcsnrtombs" to work correctly. // The return value is not used; this is a global setting. char* loc = setlocale(LC_CTYPE, ""); // The state of the conversion. // // Certain character sets use a stateful encoding. // That is, the encoded values depend in some way // on the previous bytes in the text. // // Since the conversion functions allow converting a text // in more than one step, there must be a way to pass this // information from one call of the functions to another. // // A variable of type mbstate_t can contain all the // information about the shift state needed from one call // to a conversion function to another. //?? mbstate_t st; // Clear the whole conversion state variable. // // There is no specific function or initializer to put the // state object in any specific state. The rules are that // the object should always represent the initial state // before the first use and this is achieved here. //?? memreplace((void*) &st, '\0', *MULTIBYTE_CHARACTER_STATE_CONVERSION_TYPE_SIZE); // Initialise error number. // It is a global variable/ function and other operations // may have set some value that is not wanted here. // // CAUTION! Initialise the error number BEFORE calling the function // that might cause an error. errno = *NUMBER_0_INTEGER_MEMORY_MODEL; // Converts the multibyte character string into a wide character string. // // Returns the number of wide characters converted. //?? int n = mbsnrtowcs(*d, &s, *sc, *ds, &st); int n = mbsnrtowcs(*d, (const char**) &s, *sc, *ds, *NULL_POINTER_MEMORY_MODEL); if (n >= *NUMBER_0_INTEGER_MEMORY_MODEL) { // Increment destination count by the number of wide characters converted. *dc = *dc + n; } else { if (errno == EILSEQ) { fwprintf(stdout, L"TEST ERROR EILSEQ errno: %i\n", errno); log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The input string contains an invalid multibyte sequence."); } else { fwprintf(stdout, L"TEST ERROR UNKNOWN errno: %i\n", errno); log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. An unknown error occured."); } } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The destination count is negative."); } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The destination is null."); } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The destination count is null."); } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The destination size is null."); } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The source is null."); } } else { log_terminated_message((void*) ERROR_LEVEL_LOG_MODEL, (void*) L"Could not decode utf-8 unicode character stream. The source count is null."); } }
void WString::prepareWString(const AnyString& string, bool uncprefix) { if (string.empty()) { if (uncprefix) { pSize = 4; pWString = (wchar_t*)::realloc(pWString, sizeof(wchar_t) * 5); pWString[0] = L'\\'; pWString[1] = L'\\'; pWString[2] = L'?'; pWString[3] = L'\\'; pWString[4] = L'\0'; } else clear(); return; } if (string.size() > INT_MAX) { clear(); return; } // Offset according to the presence of the UNC prefix const uint offset = (not uncprefix) ? 0 : 4; #ifdef YUNI_OS_WINDOWS { // Allocate and convert the C-String. Several iterations may be required // for allocating enough room for the conversion. const int sizeRequired = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), string.size(), nullptr, 0); if (sizeRequired <= 0) { clear(); return; } pSize = sizeRequired + offset; pWString = (wchar_t*) realloc(pWString, sizeof(wchar_t) * (pSize + 1)); if (nullptr == pWString) // Impossible to allocate the buffer. Aborting. { clear(); return; } // Converting into Wide String const int n = MultiByteToWideChar(CP_UTF8, 0, string.c_str(), static_cast<int>(string.size()), pWString + offset, static_cast<int>(pSize - offset)); if (n != sizeRequired) { assert(false and "most likely an error"); clear(); return; } } #else { const char* wcstr = string.c_str(); mbstate_t state; memset (&state, '\0', sizeof (state)); size_t sizeRequired = mbsnrtowcs(nullptr, &wcstr, string.size(), 0, &state); if (0 == sizeRequired or (size_t) -1 == sizeRequired) { clear(); return; } pSize = sizeRequired + offset; pWString = (wchar_t*) realloc(pWString, sizeof(wchar_t) * (pSize + 1)); if (nullptr == pWString) // Impossible to allocate the buffer. Aborting. { clear(); return; } memset (&state, '\0', sizeof (state)); size_t written = mbsnrtowcs(pWString + offset, &wcstr, string.size(), pSize - offset, &state); if (0 == written or (size_t) -1 == written) { clear(); return; } } #endif // prepend the Windows UNC prefix if (uncprefix) { pWString[0] = L'\\'; pWString[1] = L'\\'; pWString[2] = L'?'; pWString[3] = L'\\'; } // always ensure that the string is zero terminated pWString[pSize] = L'\0'; }