summaryrefslogtreecommitdiff
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c281
1 files changed, 146 insertions, 135 deletions
diff --git a/util.c b/util.c
index aa8e7ef3f2..4caa324849 100644
--- a/util.c
+++ b/util.c
@@ -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);
}
}