| /* APPLE LOCAL file mainline */ |
| #include <stdarg.h> |
| |
| extern void abort (void); |
| |
| extern int inside_main; |
| void *chk_fail_buf[256] __attribute__((aligned (16))); |
| volatile int chk_fail_allowed, chk_calls; |
| volatile int memcpy_disallowed, mempcpy_disallowed, memmove_disallowed; |
| volatile int memset_disallowed, strcpy_disallowed, stpcpy_disallowed; |
| volatile int strncpy_disallowed, strcat_disallowed, strncat_disallowed; |
| volatile int sprintf_disallowed, vsprintf_disallowed; |
| volatile int snprintf_disallowed, vsnprintf_disallowed; |
| extern __SIZE_TYPE__ strlen (const char *); |
| extern int vsprintf (char *, const char *, va_list); |
| |
| void __attribute__((noreturn)) |
| __chk_fail (void) |
| { |
| if (chk_fail_allowed) |
| __builtin_longjmp (chk_fail_buf, 1); |
| abort (); |
| } |
| |
| void * |
| memcpy (void *dst, const void *src, __SIZE_TYPE__ n) |
| { |
| const char *srcp; |
| char *dstp; |
| |
| #ifdef __OPTIMIZE__ |
| if (memcpy_disallowed && inside_main) |
| abort (); |
| #endif |
| |
| srcp = src; |
| dstp = dst; |
| while (n-- != 0) |
| *dstp++ = *srcp++; |
| |
| return dst; |
| } |
| |
| void * |
| __memcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into memcpy. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (n > size) |
| __chk_fail (); |
| return memcpy (dst, src, n); |
| } |
| |
| void * |
| mempcpy (void *dst, const void *src, __SIZE_TYPE__ n) |
| { |
| const char *srcp; |
| char *dstp; |
| |
| #ifdef __OPTIMIZE__ |
| if (mempcpy_disallowed && inside_main) |
| abort (); |
| #endif |
| |
| srcp = src; |
| dstp = dst; |
| while (n-- != 0) |
| *dstp++ = *srcp++; |
| |
| return dstp; |
| } |
| |
| void * |
| __mempcpy_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into mempcpy. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (n > size) |
| __chk_fail (); |
| return mempcpy (dst, src, n); |
| } |
| |
| void * |
| memmove (void *dst, const void *src, __SIZE_TYPE__ n) |
| { |
| const char *srcp; |
| char *dstp; |
| |
| #ifdef __OPTIMIZE__ |
| if (memmove_disallowed && inside_main) |
| abort (); |
| #endif |
| |
| srcp = src; |
| dstp = dst; |
| if (srcp < dstp) |
| while (n-- != 0) |
| dstp[n] = srcp[n]; |
| else |
| while (n-- != 0) |
| *dstp++ = *srcp++; |
| |
| return dst; |
| } |
| |
| void * |
| __memmove_chk (void *dst, const void *src, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into memmove. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (n > size) |
| __chk_fail (); |
| return memmove (dst, src, n); |
| } |
| |
| void * |
| memset (void *dst, int c, __SIZE_TYPE__ n) |
| { |
| /* Single-byte memsets should be done inline when optimisation |
| is enabled. */ |
| #ifdef __OPTIMIZE__ |
| if (memset_disallowed && inside_main && n < 2) |
| abort (); |
| #endif |
| |
| while (n-- != 0) |
| n[(char *) dst] = c; |
| |
| return dst; |
| } |
| |
| void * |
| __memset_chk (void *dst, int c, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into memset. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (n > size) |
| __chk_fail (); |
| return memset (dst, c, n); |
| } |
| |
| char * |
| strcpy (char *d, const char *s) |
| { |
| char *r = d; |
| #ifdef __OPTIMIZE__ |
| if (strcpy_disallowed && inside_main) |
| abort (); |
| #endif |
| while ((*d++ = *s++)); |
| return r; |
| } |
| |
| char * |
| __strcpy_chk (char *d, const char *s, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into strcpy. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (strlen (s) >= size) |
| __chk_fail (); |
| return strcpy (d, s); |
| } |
| |
| char * |
| stpcpy (char *dst, const char *src) |
| { |
| #ifdef __OPTIMIZE__ |
| if (stpcpy_disallowed && inside_main) |
| abort (); |
| #endif |
| |
| while (*src != 0) |
| *dst++ = *src++; |
| |
| *dst = 0; |
| return dst; |
| } |
| |
| char * |
| __stpcpy_chk (char *d, const char *s, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into stpcpy. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (strlen (s) >= size) |
| __chk_fail (); |
| return stpcpy (d, s); |
| } |
| |
| char * |
| strncpy (char *s1, const char *s2, __SIZE_TYPE__ n) |
| { |
| char *dest = s1; |
| #ifdef __OPTIMIZE__ |
| if (strncpy_disallowed && inside_main) |
| abort(); |
| #endif |
| for (; *s2 && n; n--) |
| *s1++ = *s2++; |
| while (n--) |
| *s1++ = 0; |
| return dest; |
| } |
| |
| char * |
| __strncpy_chk (char *s1, const char *s2, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into strncpy. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (n > size) |
| __chk_fail (); |
| return strncpy (s1, s2, n); |
| } |
| |
| char * |
| strcat (char *dst, const char *src) |
| { |
| char *p = dst; |
| |
| #ifdef __OPTIMIZE__ |
| if (strcat_disallowed && inside_main) |
| abort (); |
| #endif |
| |
| while (*p) |
| p++; |
| while ((*p++ = *src++)) |
| ; |
| return dst; |
| } |
| |
| char * |
| __strcat_chk (char *d, const char *s, __SIZE_TYPE__ size) |
| { |
| /* If size is -1, GCC should always optimize the call into strcat. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| if (strlen (d) + strlen (s) >= size) |
| __chk_fail (); |
| return strcat (d, s); |
| } |
| |
| char * |
| strncat (char *s1, const char *s2, __SIZE_TYPE__ n) |
| { |
| char *dest = s1; |
| char c; |
| #ifdef __OPTIMIZE__ |
| if (strncat_disallowed && inside_main) |
| abort(); |
| #endif |
| while (*s1) s1++; |
| c = '\0'; |
| while (n > 0) |
| { |
| c = *s2++; |
| *s1++ = c; |
| if (c == '\0') |
| return dest; |
| n--; |
| } |
| if (c != '\0') |
| *s1 = '\0'; |
| return dest; |
| } |
| |
| char * |
| __strncat_chk (char *d, const char *s, __SIZE_TYPE__ n, __SIZE_TYPE__ size) |
| { |
| __SIZE_TYPE__ len = strlen (d), n1 = n; |
| const char *s1 = s; |
| |
| /* If size is -1, GCC should always optimize the call into strncat. */ |
| if (size == (__SIZE_TYPE__) -1) |
| abort (); |
| ++chk_calls; |
| while (len < size && n1 > 0) |
| { |
| if (*s1++ == '\0') |
| break; |
| ++len; |
| --n1; |
| } |
| |
| if (len >= size) |
| __chk_fail (); |
| return strncat (d, s, n); |
| } |
| |
| /* No chk test in GCC testsuite needs more bytes than this. |
| As we can't expect vsnprintf to be available on the target, |
| assume 4096 bytes is enough. */ |
| static char chk_sprintf_buf[4096]; |
| |
| int |
| __sprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, ...) |
| { |
| int ret; |
| va_list ap; |
| |
| /* If size is -1 and flag 0, GCC should always optimize the call into |
| sprintf. */ |
| if (size == (__SIZE_TYPE__) -1 && flag == 0) |
| abort (); |
| ++chk_calls; |
| #ifdef __OPTIMIZE__ |
| if (sprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| va_start (ap, fmt); |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| va_end (ap); |
| if (ret >= 0) |
| { |
| if (ret >= size) |
| __chk_fail (); |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| } |
| return ret; |
| } |
| |
| int |
| __vsprintf_chk (char *str, int flag, __SIZE_TYPE__ size, const char *fmt, |
| va_list ap) |
| { |
| int ret; |
| |
| /* If size is -1 and flag 0, GCC should always optimize the call into |
| vsprintf. */ |
| if (size == (__SIZE_TYPE__) -1 && flag == 0) |
| abort (); |
| ++chk_calls; |
| #ifdef __OPTIMIZE__ |
| if (vsprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| if (ret >= 0) |
| { |
| if (ret >= size) |
| __chk_fail (); |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| } |
| return ret; |
| } |
| |
| int |
| __snprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size, |
| const char *fmt, ...) |
| { |
| int ret; |
| va_list ap; |
| |
| /* If size is -1 and flag 0, GCC should always optimize the call into |
| snprintf. */ |
| if (size == (__SIZE_TYPE__) -1 && flag == 0) |
| abort (); |
| ++chk_calls; |
| if (size < len) |
| __chk_fail (); |
| #ifdef __OPTIMIZE__ |
| if (snprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| va_start (ap, fmt); |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| va_end (ap); |
| if (ret >= 0) |
| { |
| if (ret < len) |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| else |
| { |
| memcpy (str, chk_sprintf_buf, len - 1); |
| str[len - 1] = '\0'; |
| } |
| } |
| return ret; |
| } |
| |
| int |
| __vsnprintf_chk (char *str, __SIZE_TYPE__ len, int flag, __SIZE_TYPE__ size, |
| const char *fmt, va_list ap) |
| { |
| int ret; |
| |
| /* If size is -1 and flag 0, GCC should always optimize the call into |
| vsnprintf. */ |
| if (size == (__SIZE_TYPE__) -1 && flag == 0) |
| abort (); |
| ++chk_calls; |
| if (size < len) |
| __chk_fail (); |
| #ifdef __OPTIMIZE__ |
| if (vsnprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| if (ret >= 0) |
| { |
| if (ret < len) |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| else |
| { |
| memcpy (str, chk_sprintf_buf, len - 1); |
| str[len - 1] = '\0'; |
| } |
| } |
| return ret; |
| } |
| |
| int |
| snprintf (char *str, __SIZE_TYPE__ len, const char *fmt, ...) |
| { |
| int ret; |
| va_list ap; |
| |
| #ifdef __OPTIMIZE__ |
| if (snprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| va_start (ap, fmt); |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| va_end (ap); |
| if (ret >= 0) |
| { |
| if (ret < len) |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| else if (len) |
| { |
| memcpy (str, chk_sprintf_buf, len - 1); |
| str[len - 1] = '\0'; |
| } |
| } |
| return ret; |
| } |
| |
| int |
| vsnprintf (char *str, __SIZE_TYPE__ len, const char *fmt, va_list ap) |
| { |
| int ret; |
| |
| #ifdef __OPTIMIZE__ |
| if (vsnprintf_disallowed && inside_main) |
| abort(); |
| #endif |
| ret = vsprintf (chk_sprintf_buf, fmt, ap); |
| if (ret >= 0) |
| { |
| if (ret < len) |
| memcpy (str, chk_sprintf_buf, ret + 1); |
| else if (len) |
| { |
| memcpy (str, chk_sprintf_buf, len - 1); |
| str[len - 1] = '\0'; |
| } |
| } |
| return ret; |
| } |