diff options
Diffstat (limited to 'util.c')
| -rw-r--r-- | util.c | 281 |
1 files changed, 146 insertions, 135 deletions
@@ -10,22 +10,31 @@ **********************************************************************/ #if defined __MINGW32__ || defined __MINGW64__ -#define MINGW_HAS_SECURE_API 1 +# define MINGW_HAS_SECURE_API 1 #endif -#include "internal.h" +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ 1 /* for qsort_s() */ +#endif + +#include "ruby/internal/config.h" #include <ctype.h> -#include <stdio.h> #include <errno.h> -#include <math.h> #include <float.h> +#include <math.h> +#include <stdio.h> #ifdef _WIN32 -#include "missing/file.h" +# include "missing/file.h" #endif +#include "internal.h" +#include "internal/sanitizers.h" +#include "internal/imemo.h" +#include "internal/util.h" #include "ruby/util.h" +#include "ruby_atomic.h" const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF"; #define hexdigit ruby_hexdigits @@ -33,43 +42,19 @@ const char ruby_hexdigits[] = "0123456789abcdef0123456789ABCDEF"; unsigned long ruby_scan_oct(const char *start, size_t len, size_t *retlen) { - register const char *s = start; - register unsigned long retval = 0; - size_t i; - - for (i = 0; i < len; i++) { - if ((s[0] < '0') || ('7' < s[0])) { - break; - } - retval <<= 3; - retval |= *s++ - '0'; - } - *retlen = (int)(s - start); /* less than len */ - return retval; + int overflow; + unsigned long val = ruby_scan_digits(start, (ssize_t)len, 8, retlen, &overflow); + (void)overflow; + return val; } unsigned long ruby_scan_hex(const char *start, size_t len, size_t *retlen) { - register const char *s = start; - register unsigned long retval = 0; - const char *tmp; - size_t i = 0; - - for (i = 0; i < len; i++) { - if (! s[0]) { - break; - } - tmp = strchr(hexdigit, *s); - if (! tmp) { - break; - } - retval <<= 4; - retval |= (tmp - hexdigit) & 15; - s++; - } - *retlen = (int)(s - start); /* less than len */ - return retval; + int overflow; + unsigned long val = ruby_scan_digits(start, (ssize_t)len, 16, retlen, &overflow); + (void)overflow; + return val; } const signed char ruby_digit36_to_number_table[] = { @@ -96,6 +81,8 @@ NO_SANITIZE("unsigned-integer-overflow", extern unsigned long ruby_scan_digits(c unsigned long ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *overflow) { + RBIMPL_ASSERT_OR_ASSUME(base >= 2); + RBIMPL_ASSERT_OR_ASSUME(base <= 36); const char *start = str; unsigned long ret = 0, x; @@ -104,15 +91,15 @@ ruby_scan_digits(const char *str, ssize_t len, int base, size_t *retlen, int *ov *overflow = 0; if (!len) { - *retlen = 0; - return 0; + *retlen = 0; + return 0; } do { - int d = ruby_digit36_to_number_table[(unsigned char)*str++]; + int d = ruby_digit36_to_number_table[(unsigned char)*str++]; if (d == -1 || base <= d) { - --str; - break; + --str; + break; } if (mul_overflow < ret) *overflow = 1; @@ -135,6 +122,11 @@ ruby_strtoul(const char *str, char **endptr, int base) unsigned long ret; const char *subject_found = str; + if (base < 0) { + errno = EINVAL; + return 0; + } + if (base == 1 || 36 < base) { errno = EINVAL; return 0; @@ -195,18 +187,12 @@ ruby_strtoul(const char *str, char **endptr, int base) } } +#if !defined HAVE_GNU_QSORT_R #include <sys/types.h> -#include <sys/stat.h> +#include <stdint.h> #ifdef HAVE_UNISTD_H #include <unistd.h> #endif -#if defined(HAVE_FCNTL_H) -#include <fcntl.h> -#endif - -#ifndef S_ISDIR -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif typedef int (cmpfunc_t)(const void*, const void*, void*); @@ -255,7 +241,7 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void qsort_s(base, nel, size, cmp, d); } # define HAVE_GNU_QSORT_R 1 -#elif !defined HAVE_GNU_QSORT_R +#else /* mm.c */ #define mmtype long @@ -396,7 +382,8 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void for (;;) { start: if (L + size == R) { /* 2 elements */ - if ((*cmp)(L,R,d) > 0) mmswap(L,R); goto nxt; + if ((*cmp)(L,R,d) > 0) mmswap(L,R); + goto nxt; } l = L; r = R; @@ -407,57 +394,57 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void register char *m1; register char *m3; if (n >= 200) { - n = size*(n>>3); /* number of bytes in splitting 8 */ - { - register char *p1 = l + n; - register char *p2 = p1 + n; - register char *p3 = p2 + n; - m1 = med3(p1, p2, p3); - p1 = m + n; - p2 = p1 + n; - p3 = p2 + n; - m3 = med3(p1, p2, p3); - } + n = size*(n>>3); /* number of bytes in splitting 8 */ + { + register char *p1 = l + n; + register char *p2 = p1 + n; + register char *p3 = p2 + n; + m1 = med3(p1, p2, p3); + p1 = m + n; + p2 = p1 + n; + p3 = p2 + n; + m3 = med3(p1, p2, p3); + } } else { - n = size*(n>>2); /* number of bytes in splitting 4 */ - m1 = l + n; - m3 = m + n; + n = size*(n>>2); /* number of bytes in splitting 4 */ + m1 = l + n; + m3 = m + n; } m = med3(m1, m, m3); } if ((t = (*cmp)(l,m,d)) < 0) { /*3-5-?*/ if ((t = (*cmp)(m,r,d)) < 0) { /*3-5-7*/ - if (chklim && nel >= chklim) { /* check if already ascending order */ - char *p; - chklim = 0; - for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail; - goto nxt; - } - fail: goto loopA; /*3-5-7*/ + if (chklim && nel >= chklim) { /* check if already ascending order */ + char *p; + chklim = 0; + for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) > 0) goto fail; + goto nxt; + } + fail: goto loopA; /*3-5-7*/ } if (t > 0) { - if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/ - mmrot3(r,m,l); goto loopA; /*3-5-2*/ + if ((*cmp)(l,r,d) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/ + mmrot3(r,m,l); goto loopA; /*3-5-2*/ } goto loopB; /*3-5-5*/ } if (t > 0) { /*7-5-?*/ if ((t = (*cmp)(m,r,d)) > 0) { /*7-5-3*/ - if (chklim && nel >= chklim) { /* check if already ascending order */ - char *p; - chklim = 0; - for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2; - while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */ - goto nxt; - } - fail2: mmswap(l,r); goto loopA; /*7-5-3*/ + if (chklim && nel >= chklim) { /* check if already ascending order */ + char *p; + chklim = 0; + for (p=l; p<r; p+=size) if ((*cmp)(p,p+size,d) < 0) goto fail2; + while (l<r) {mmswap(l,r); l+=size; r-=size;} /* reverse region */ + goto nxt; + } + fail2: mmswap(l,r); goto loopA; /*7-5-3*/ } if (t < 0) { - if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/ - mmrot3(l,m,r); goto loopA; /*7-5-6*/ + if ((*cmp)(l,r,d) <= 0) {mmswap(l,m); goto loopB;} /*7-5-8*/ + mmrot3(l,m,r); goto loopA; /*7-5-6*/ } mmswap(l,r); goto loopA; /*7-5-5*/ } @@ -476,18 +463,18 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void loopA: eq_l = 1; eq_r = 1; /* splitting type A */ /* left <= median < right */ for (;;) { for (;;) { - if ((l += size) == r) - {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} - if (l == m) continue; - if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} - if (t < 0) eq_l = 0; + if ((l += size) == r) + {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} + if (l == m) continue; + if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} + if (t < 0) eq_l = 0; } for (;;) { - if (l == (r -= size)) - {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} - if (r == m) {m = l; break;} - if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} - if (t == 0) break; + if (l == (r -= size)) + {l -= size; if (l != m) mmswap(m,l); l -= size; goto fin;} + if (r == m) {m = l; break;} + if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} + if (t == 0) break; } mmswap(l,r); /* swap left and right */ } @@ -495,18 +482,18 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void loopB: eq_l = 1; eq_r = 1; /* splitting type B */ /* left < median <= right */ for (;;) { for (;;) { - if (l == (r -= size)) - {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} - if (r == m) continue; - if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} - if (t > 0) eq_r = 0; + if (l == (r -= size)) + {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} + if (r == m) continue; + if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} + if (t > 0) eq_r = 0; } for (;;) { - if ((l += size) == r) - {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} - if (l == m) {m = r; break;} - if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} - if (t == 0) break; + if ((l += size) == r) + {r += size; if (r != m) mmswap(r,m); r += size; goto fin;} + if (l == m) {m = r; break;} + if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} + if (t == 0) break; } mmswap(l,r); /* swap left and right */ } @@ -514,14 +501,15 @@ ruby_qsort(void* base, const size_t nel, const size_t size, cmpfunc_t *cmp, void fin: if (eq_l == 0) /* need to sort left side */ if (eq_r == 0) /* need to sort right side */ - if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */ - else {PUSH(L,l); L = r;} /* sort right side first */ + if (l-L < R-r) {PUSH(r,R); R = l;} /* sort left side first */ + else {PUSH(L,l); L = r;} /* sort right side first */ else R = l; /* need to sort left side only */ else if (eq_r == 0) L = r; /* need to sort right side only */ else goto nxt; /* need not to sort both sides */ } } -#endif /* HAVE_GNU_QSORT_R */ +#endif +#endif /* !HAVE_GNU_QSORT_R */ char * ruby_strdup(const char *str) @@ -535,52 +523,75 @@ ruby_strdup(const char *str) return tmp; } +#if defined HAVE_GETCWD +# if defined NO_GETCWD_MALLOC + char * ruby_getcwd(void) { -#if defined HAVE_GETCWD -# undef RUBY_UNTYPED_DATA_WARNING -# define RUBY_UNTYPED_DATA_WARNING 0 -# if defined NO_GETCWD_MALLOC - VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, RUBY_DEFAULT_FREE, NULL); + VALUE guard = rb_imemo_tmpbuf_new(); int size = 200; char *buf = xmalloc(size); while (!getcwd(buf, size)) { - int e = errno; - if (e != ERANGE) { - xfree(buf); - DATA_PTR(guard) = NULL; - rb_syserr_fail(e, "getcwd"); - } - size *= 2; - DATA_PTR(guard) = buf; - buf = xrealloc(buf, size); + int e = errno; + if (e != ERANGE) { + rb_free_tmp_buffer(&guard); + rb_syserr_fail(e, "getcwd"); + } + size *= 2; + rb_imemo_tmpbuf_set_ptr(guard, buf); + buf = xrealloc(buf, size); } + rb_imemo_tmpbuf_set_ptr(guard, NULL); + return buf; +} + # else - VALUE guard = Data_Wrap_Struct((VALUE)0, NULL, free, NULL); + +static const rb_data_type_t getcwd_buffer_guard_type = { + .wrap_struct_name = "ruby_getcwd_guard", + .function = { + .dfree = free // not xfree. + }, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED +}; + +char * +ruby_getcwd(void) +{ + VALUE guard = TypedData_Wrap_Struct((VALUE)0, &getcwd_buffer_guard_type, NULL); char *buf, *cwd = getcwd(NULL, 0); - DATA_PTR(guard) = cwd; + RTYPEDDATA_DATA(guard) = cwd; if (!cwd) rb_sys_fail("getcwd"); buf = ruby_strdup(cwd); /* allocate by xmalloc */ free(cwd); + RTYPEDDATA_DATA(RB_GC_GUARD(guard)) = NULL; + return buf; +} + # endif - DATA_PTR(RB_GC_GUARD(guard)) = NULL; #else + # ifndef PATH_MAX # define PATH_MAX 8192 # endif + +char * +ruby_getcwd(void) +{ char *buf = xmalloc(PATH_MAX+1); if (!getwd(buf)) { - int e = errno; - xfree(buf); - rb_syserr_fail(e, "getwd"); + int e = errno; + xfree(buf); + rb_syserr_fail(e, "getwd"); } -#endif return buf; } +#endif + void ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *arg) { @@ -589,12 +600,12 @@ ruby_each_words(const char *str, void (*func)(const char*, int, void*), void *ar if (!str) return; for (; *str; str = end) { - while (ISSPACE(*str) || *str == ',') str++; - if (!*str) break; - end = str; - while (*end && !ISSPACE(*end) && *end != ',') end++; - len = (int)(end - str); /* assume no string exceeds INT_MAX */ - (*func)(str, len, arg); + while (ISSPACE(*str) || *str == ',') str++; + if (!*str) break; + end = str; + while (*end && !ISSPACE(*end) && *end != ',') end++; + len = (int)(end - str); /* assume no string exceeds INT_MAX */ + (*func)(str, len, arg); } } |
