diff --git a/ChangeLog b/ChangeLog index ed7f437d94..45fc060863 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +Tue Sep 21 18:29:49 2004 Yukihiro Matsumoto + + * array.c (rb_ary_uniq_bang): element size might change during + comparison. [ruby-dev:24298] + +Mon Sep 20 00:24:19 2004 Yukihiro Matsumoto + + * enum.c (enum_sort_by): do not use qsort directly. use + rb_ary_sort_bang() instead. [ruby-dev:24291] + + * enum.c (enum_sort_by): pedantic type check added. + [ruby-dev:24291] + + * hash.c (rb_hash_foreach_iter): check iter_lev after each + iteration. [ruby-dev:24289] + + * array.c (rb_ary_and): element size might change during + comparison. [ruby-dev:24290] + + * array.c (rb_ary_or): ditto. [ruby-dev:24292] + + * array.c (rb_ary_equal): wrong fix. [ruby-dev:24286] + Sat Sep 18 15:02:22 2004 Yukihiro Matsumoto * array.c (rb_ary_equal): element size might change during diff --git a/array.c b/array.c index 67da6b8e7e..3e22138468 100644 --- a/array.c +++ b/array.c @@ -561,21 +561,28 @@ rb_ary_unshift_m(argc, argv, ary) return ary; } +/* faster version - use this if you don't need to treat negative offset */ +static inline VALUE +rb_ary_elt(ary, offset) + VALUE ary; + long offset; +{ + if (RARRAY(ary)->len == 0) return Qnil; + if (offset < 0 || RARRAY(ary)->len <= offset) { + return Qnil; + } + return RARRAY(ary)->ptr[offset]; +} + VALUE rb_ary_entry(ary, offset) VALUE ary; long offset; { - if (RARRAY(ary)->len == 0) return Qnil; - if (offset < 0) { offset += RARRAY(ary)->len; } - if (offset < 0 || RARRAY(ary)->len <= offset) { - return Qnil; - } - - return RARRAY(ary)->ptr[offset]; + return rb_ary_elt(ary, offset); } static VALUE @@ -857,6 +864,10 @@ rb_ary_index(ary, val) * array.rindex(obj) -> int or nil * * Returns the index of the last object in array + if (i > RARRAY(ary)->len) { + i = RARRAY(ary)->len; + continue; + } * == to obj. Returns nil if * no match is found. * @@ -1533,17 +1544,36 @@ rb_ary_reverse_m(ary) return rb_ary_reverse(rb_ary_dup(ary)); } +struct ary_sort_data { + VALUE ary; + VALUE *ptr; + long len; +}; + +static void +ary_sort_check(data) + struct ary_sort_data *data; +{ + if (RARRAY(data->ary)->ptr != data->ptr || RARRAY(data->ary)->len != data->len) { + rb_raise(rb_eArgError, "array modified during sort"); + } +} + static int -sort_1(a, b) +sort_1(a, b, data) VALUE *a, *b; + struct ary_sort_data *data; { VALUE retval = rb_yield_values(2, *a, *b); + + ary_sort_check(data); return rb_cmpint(retval, *a, *b); } static int -sort_2(ap, bp) +sort_2(ap, bp, data) VALUE *ap, *bp; + struct ary_sort_data *data; { VALUE retval; long a = (long)*ap, b = (long)*bp; @@ -1558,6 +1588,7 @@ sort_2(ap, bp) } retval = rb_funcall(a, id_cmp, 1, b); + ary_sort_check(data); return rb_cmpint(retval, a, b); } @@ -1565,8 +1596,12 @@ static VALUE sort_internal(ary) VALUE ary; { + struct ary_sort_data data; + + data.ary = ary; + data.ptr = RARRAY(ary)->ptr; data.len = RARRAY(ary)->len; qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), - rb_block_given_p()?sort_1:sort_2); + rb_block_given_p()?sort_1:sort_2, &data); return ary; } @@ -1775,7 +1810,7 @@ rb_ary_select(argc, argv, ary) result = rb_ary_new2(RARRAY(ary)->len); for (i = 0; i < RARRAY(ary)->len; i++) { if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) { - rb_ary_push(result, rb_ary_entry(ary, i)); + rb_ary_push(result, rb_ary_elt(ary, i)); } } return result; @@ -2038,9 +2073,9 @@ rb_ary_zip(argc, argv, ary) for (i=0; ilen; i++) { VALUE tmp = rb_ary_new2(argc+1); - rb_ary_push(tmp, rb_ary_entry(ary, i)); + rb_ary_push(tmp, rb_ary_elt(ary, i)); for (j=0; jlen; if (alen == 0) return rb_ary_dup(ary); for (i=0; ilen; result = rb_ary_new2(elen); @@ -2094,7 +2129,7 @@ rb_ary_transpose(ary) RARRAY(tmp)->len, elen); } for (j=0; jlen; i++) { if (RARRAY(ary1)->len != RARRAY(ary2)->len) return Qfalse; - if (!rb_equal(RARRAY(ary1)->ptr[i], RARRAY(ary2)->ptr[i])) + if (!rb_equal(rb_ary_elt(ary1, i), rb_ary_elt(ary2, i))) return Qfalse; } return Qtrue; @@ -2640,7 +2675,7 @@ rb_ary_and(ary1, ary2) for (i=0; ilen; i++) { VALUE v = RARRAY(ary1)->ptr[i]; if (st_delete(RHASH(hash)->tbl, (st_data_t*)&v, 0)) { - rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); + rb_ary_push(ary3, rb_ary_elt(ary1, i)); } } @@ -2671,15 +2706,15 @@ rb_ary_or(ary1, ary2) hash = ary_make_hash(ary1, ary2); for (i=0; ilen; i++) { - v = RARRAY(ary1)->ptr[i]; + v = rb_ary_elt(ary1, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&v, 0)) { - rb_ary_push(ary3, RARRAY(ary1)->ptr[i]); + rb_ary_push(ary3, v); } } for (i=0; ilen; i++) { - v = RARRAY(ary2)->ptr[i]; + v = rb_ary_elt(ary2, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&v, 0)) { - rb_ary_push(ary3, RARRAY(ary2)->ptr[i]); + rb_ary_push(ary3, v); } } return ary3; @@ -2704,7 +2739,7 @@ rb_ary_uniq_bang(ary) VALUE ary; { VALUE hash; - VALUE *p, *q, *end; + long i, j; rb_ary_modify(ary); @@ -2713,16 +2748,13 @@ rb_ary_uniq_bang(ary) if (RARRAY(ary)->len == RHASH(hash)->tbl->num_entries) { return Qnil; } - p = q = RARRAY(ary)->ptr; - end = p + RARRAY(ary)->len; - while (p < end) { - VALUE v = *p; + for (i=j=0; ilen; i++) { + VALUE v = rb_ary_elt(ary, i); if (st_delete(RHASH(hash)->tbl, (st_data_t*)&v, 0)) { - *q++ = *p; + rb_ary_store(ary, j++, v); } - p++; } - RARRAY(ary)->len = (q - RARRAY(ary)->ptr); + RARRAY(ary)->len = j; return ary; } diff --git a/dir.c b/dir.c index 9327022328..6448634f11 100644 --- a/dir.c +++ b/dir.c @@ -648,8 +648,9 @@ dir_s_chdir(argc, argv, obj) if (rb_block_given_p()) { struct chdir_data args; + char *cwd = my_getcwd(); - args.old_path = rb_str_new2(my_getcwd()); + args.old_path = rb_tainted_str_new2(cwd); free(cwd); args.new_path = path; args.done = Qfalse; return rb_ensure(chdir_yield, (VALUE)&args, chdir_restore, (VALUE)&args); diff --git a/enum.c b/enum.c index d502047c25..fceed391f6 100644 --- a/enum.c +++ b/enum.c @@ -397,14 +397,17 @@ sort_by_i(i, ary) return Qnil; } -static int -sort_by_cmp(a, b) - VALUE *a, *b; +static VALUE +sort_by_cmp(values, ary) + VALUE values; { - VALUE retval; + VALUE a = RARRAY(values)->ptr[0]; + VALUE b = RARRAY(values)->ptr[1]; - retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]); - return rb_cmpint(retval, *a, *b); + /* pedantic check; they must be arrays */ + Check_Type(a, T_ARRAY); + Check_Type(b, T_ARRAY); + return rb_funcall(RARRAY(a)->ptr[0], id_cmp, 1, RARRAY(b)->ptr[0]); } /* @@ -491,7 +494,7 @@ enum_sort_by(obj) } rb_iterate(rb_each, obj, sort_by_i, ary); if (RARRAY(ary)->len > 1) { - qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp); + rb_iterate(rb_ary_sort_bang, ary, sort_by_cmp, ary); } for (i=0; ilen; i++) { VALUE e = RARRAY(ary)->ptr[i]; diff --git a/hash.c b/hash.c index 209fe26c37..89666ca831 100644 --- a/hash.c +++ b/hash.c @@ -131,9 +131,13 @@ rb_hash_foreach_iter(key, value, arg) if (key == Qundef) return ST_CONTINUE; status = (*arg->func)(key, value, arg->arg); - if (RHASH(arg->hash)->tbl != tbl || RHASH(arg->hash)->tbl->bins != bins){ + if (RHASH(arg->hash)->tbl != tbl || + RHASH(arg->hash)->tbl->bins != bins) { rb_raise(rb_eIndexError, "rehash occurred during iteration"); } + if (RHASH(arg->hash)->iter_lev == 0) { + rb_raise(rb_eArgError, "block re-entered"); + } return status; } diff --git a/lib/delegate.rb b/lib/delegate.rb index 122a565642..a14d62cf5b 100644 --- a/lib/delegate.rb +++ b/lib/delegate.rb @@ -92,7 +92,6 @@ def DelegateClass(superclass) @_dc_obj = obj end def method_missing(m, *args) - p [m, *args] unless @_dc_obj.respond_to?(m) super(m, *args) end diff --git a/util.c b/util.c index 6f76519176..c2c1929bc3 100644 --- a/util.c +++ b/util.c @@ -466,15 +466,16 @@ typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */ #define PUSH(ll,rr) do { top->LL = (ll); top->RR = (rr); ++top; } while (0) /* Push L,l,R,r */ #define POP(ll,rr) do { --top; ll = top->LL; rr = top->RR; } while (0) /* Pop L,l,R,r */ -#define med3(a,b,c) ((*cmp)(a,b)<0 ? \ - ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \ - ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c))) +#define med3(a,b,c) ((*cmp)(a,b,d)<0 ? \ + ((*cmp)(b,c,d)<0 ? b : ((*cmp)(a,c,d)<0 ? c : a)) : \ + ((*cmp)(b,c,d)>0 ? b : ((*cmp)(a,c,d)<0 ? a : c))) -void ruby_qsort (base, nel, size, cmp) +void ruby_qsort (base, nel, size, cmp, d) void* base; const int nel; const int size; int (*cmp)(); + void *d; { register char *l, *r, *m; /* l,r:left,right group m:median point */ register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ @@ -495,7 +496,7 @@ void ruby_qsort (base, nel, size, cmp) for (;;) { start: if (L + size == R) { /* 2 elements */ - if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt; + if ((*cmp)(L,R,d) > 0) mmswap(L,R); goto nxt; } l = L; r = R; @@ -526,49 +527,49 @@ void ruby_qsort (base, nel, size, cmp) m = med3(m1, m, m3); } - if ((t = (*cmp)(l,m)) < 0) { /*3-5-?*/ - if ((t = (*cmp)(m,r)) < 0) { /*3-5-7*/ + 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 0) goto fail; + for (p=l; p 0) goto fail; goto nxt; } fail: goto loopA; /*3-5-7*/ } if (t > 0) { - if ((*cmp)(l,r) <= 0) {mmswap(m,r); goto loopA;} /*3-5-4*/ + 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)) > 0) { /*7-5-3*/ + 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 0) {mmswap(l,r); goto loopB;} /*5-5-3*/ /* determining splitting type in case 5-5-5 */ /*5-5-5*/ for (;;) { if ((l += size) == r) goto nxt; /*5-5-5*/ if (l == m) continue; - if ((t = (*cmp)(l,m)) > 0) {mmswap(l,r); l = L; goto loopA;} /*575-5*/ + if ((t = (*cmp)(l,m,d)) > 0) {mmswap(l,r); l = L; goto loopA;}/*575-5*/ if (t < 0) {mmswap(L,l); l = L; goto loopB;} /*535-5*/ } @@ -578,14 +579,14 @@ void ruby_qsort (base, nel, size, cmp) 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)) > 0) {eq_r = 0; break;} + 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)) < 0) {eq_l = 0; break;} + if ((t = (*cmp)(r,m,d)) < 0) {eq_l = 0; break;} if (t == 0) break; } mmswap(l,r); /* swap left and right */ @@ -597,14 +598,14 @@ void ruby_qsort (base, nel, size, cmp) 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)) < 0) {eq_l = 0; break;} + 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)) > 0) {eq_r = 0; break;} + if ((t = (*cmp)(l,m,d)) > 0) {eq_r = 0; break;} if (t == 0) break; } mmswap(l,r); /* swap left and right */ diff --git a/util.h b/util.h index a0999ca872..ca879cab5e 100644 --- a/util.h +++ b/util.h @@ -43,8 +43,8 @@ unsigned long scan_hex _((const char*, int, int*)); void ruby_add_suffix(); #endif -void ruby_qsort _((void*, const int, const int, int (*)())); -#define qsort(b,n,s,c) ruby_qsort(b,n,s,c) +void ruby_qsort _((void*, const int, const int, int (*)(), void*)); +#define qsort(b,n,s,c,d) ruby_qsort(b,n,s,c,d) void ruby_setenv _((const char*, const char*)); void ruby_unsetenv _((const char*));