1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* eval.c (rb_f_require): searches ".rb" and ".so" at the same

time.  previous behavior (search ".rb", then ".so") has a
  security risk (ruby-bugs#PR140).

* array.c (rb_ary_to_ary): new function to replace internal
  rb_Array(), which never calls to_a, but to_ary (rb_Array() might
  call both). [new]

* regex.c (PUSH_FAILURE_POINT): push option status again.

* regex.c (re_compile_pattern): avoid pushing unnecessary
  option_set.

* eval.c (rb_load): tainted string is OK if wrapped *and*
  $SAFE >= 4.

* eval.c (rb_thread_start_0): should not nail down higher blocks
  before preserving original context (i.e. should not alter
  original context).

* eval.c (proc_yield): new method equivalent to Proc#call but no
  check for number of arguments. [new]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1526 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2001-06-19 04:35:17 +00:00
parent 6aa71d4c80
commit 9d51cf8a6a
10 changed files with 253 additions and 108 deletions

View file

@ -1,9 +1,42 @@
Mon Jun 18 17:38:50 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_f_require): searches ".rb" and ".so" at the same
time. previous behavior (search ".rb", then ".so") has a
security risk (ruby-bugs#PR140).
* array.c (rb_ary_to_ary): new function to replace internal
rb_Array(), which never calls to_a, but to_ary (rb_Array() might
call both). [new]
Mon Jun 18 00:43:20 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* regex.c (PUSH_FAILURE_POINT): push option status again.
* regex.c (re_compile_pattern): avoid pushing unnecessary
option_set.
Sat Jun 16 10:58:48 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_load): tainted string is OK if wrapped *and*
$SAFE >= 4.
Thu Jun 14 16:27:07 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_thread_start_0): should not nail down higher blocks
before preserving original context (i.e. should not alter
original context).
Wed Jun 13 19:34:59 2001 Akinori MUSHA <knu@iDaemons.org>
* dir.c (Init_Dir): add a new method File::fnmatch? along with
File::Constants::FNM_*. While I am here, FNM_NOCASE is renamed
to FNM_CASEFOLD which is commonly used by *BSD and GNU libc.
Wed Jun 13 09:33:45 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (proc_yield): new method equivalent to Proc#call but no
check for number of arguments. [new]
Tue Jun 12 14:21:28 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp>
* lib/mkmf.rb: target_prefix is only for installation, not for

1
ToDo
View file

@ -83,6 +83,7 @@ Standard Libraries
* hash etc. should handle self referenceing array/hash
* move NameError under StandardError.
* library to load per-user profile seeking .ruby_profile or ruby.ini file.
* warning framework
Extension Libraries

17
array.c
View file

@ -17,6 +17,7 @@
#include "st.h"
VALUE rb_cArray;
static ID cmp;
#define ARY_DEFAULT_SIZE 16
@ -729,6 +730,20 @@ to_ary(ary)
return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
}
VALUE
rb_ary_to_ary(obj)
VALUE obj;
{
if (NIL_P(obj)) return rb_ary_new2(0);
if (TYPE(obj) == T_ARRAY) {
return obj;
}
if (rb_respond_to(obj, rb_intern("to_ary"))) {
return rb_convert_type(obj, T_ARRAY, "Array", "to_ary");
}
return rb_ary_new3(1, obj);
}
extern VALUE rb_output_fs;
static VALUE
@ -958,8 +973,6 @@ rb_ary_reverse_m(ary)
return rb_ary_reverse(rb_obj_dup(ary));
}
static ID cmp;
static int
sort_1(a, b)
VALUE *a, *b;

111
eval.c
View file

@ -1676,7 +1676,7 @@ copy_node_scope(node, rval)
char *file = ruby_sourcefile;\
int line = ruby_sourceline;\
if (TYPE(args) != T_ARRAY)\
args = rb_Array(args);\
args = rb_ary_to_ary(args);\
argc = RARRAY(args)->len;\
argv = ALLOCA_N(VALUE, argc);\
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
@ -2129,7 +2129,7 @@ rb_eval(self, n)
VALUE v = rb_eval(self, tag->nd_head->nd_head);
int i;
if (TYPE(v) != T_ARRAY) v = rb_Array(v);
if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
for (i=0; i<RARRAY(v)->len; i++) {
if (RTEST(RARRAY(v)->ptr[i])) {
node = node->nd_body;
@ -2174,7 +2174,7 @@ rb_eval(self, n)
VALUE v = rb_eval(self, tag->nd_head->nd_head);
int i;
if (TYPE(v) != T_ARRAY) v = rb_Array(v);
if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
for (i=0; i<RARRAY(v)->len; i++) {
if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){
node = node->nd_body;
@ -2347,14 +2347,14 @@ rb_eval(self, n)
case NODE_RESTARY:
result = rb_eval(self, node->nd_head);
if (TYPE(result) != T_ARRAY) {
result = rb_Array(result);
result = rb_ary_to_ary(result);
}
break;
case NODE_REXPAND:
result = rb_eval(self, node->nd_head);
if (TYPE(result) != T_ARRAY) {
result = rb_Array(result);
result = rb_ary_to_ary(result);
}
if (RARRAY(result)->len == 0) {
result = Qnil;
@ -2520,7 +2520,7 @@ rb_eval(self, n)
case NODE_ARGSCAT:
result = rb_ary_concat(rb_eval(self, node->nd_head),
rb_Array(rb_eval(self, node->nd_body)));
rb_ary_to_ary(rb_eval(self, node->nd_body)));
break;
case NODE_ARGSPUSH:
@ -3546,16 +3546,20 @@ rb_f_block_given_p()
return Qfalse;
}
#define PC_NONE 0x0
#define PC_ACHECK 0x1
#define PC_PCALL 0x2
static VALUE
rb_yield_0(val, self, klass, acheck)
rb_yield_0(val, self, klass, pcall)
VALUE val, self, klass; /* OK */
int acheck;
int pcall;
{
NODE *node;
volatile VALUE result = Qnil;
volatile VALUE old_cref;
struct BLOCK *block;
struct SCOPE *old_scope;
struct BLOCK * volatile block;
struct SCOPE * volatile old_scope;
struct FRAME frame;
int state;
static unsigned serial = 1;
@ -3591,7 +3595,7 @@ rb_yield_0(val, self, klass, acheck)
PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) {
if (block->var == (NODE*)1) {
if (acheck && val != Qundef &&
if ((pcall&PC_ACHECK) && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
rb_raise(rb_eArgError, "wrong # of arguments (%d for 0)",
RARRAY(val)->len);
@ -3605,14 +3609,14 @@ rb_yield_0(val, self, klass, acheck)
}
else {
if (nd_type(block->var) == NODE_MASGN)
massign(self, block->var, val, acheck);
massign(self, block->var, val, (pcall&PC_ACHECK));
else {
/* argument adjust for proc_call etc. */
if (acheck && val != Qundef &&
if (pcall && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) {
val = RARRAY(val)->ptr[0];
}
assign(self, block->var, val, acheck);
assign(self, block->var, val, (pcall&PC_ACHECK));
}
}
}
@ -3621,7 +3625,7 @@ rb_yield_0(val, self, klass, acheck)
}
else {
/* argument adjust for proc_call etc. */
if (acheck && val != Qundef &&
if (pcall && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) {
val = RARRAY(val)->ptr[0];
}
@ -5171,7 +5175,12 @@ rb_load(fname, wrap)
NODE *saved_cref = ruby_cref;
TMP_PROTECT;
SafeStringValue(fname);
if (wrap && ruby_safe_level >= 4) {
StringValue(fname);
}
else {
SafeStringValue(fname);
}
file = rb_find_file(RSTRING(fname)->ptr);
if (!file) {
rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr);
@ -5402,28 +5411,20 @@ rb_f_require(obj, fname)
}
buf = ALLOCA_N(char, strlen(RSTRING(fname)->ptr) + 5);
strcpy(buf, RSTRING(fname)->ptr);
strcat(buf, ".rb");
if (rb_find_file(buf)) {
switch (rb_find_file_noext(buf)) {
case 0:
break;
case 1:
fname = rb_str_new2(buf);
feature = buf;
file = feature = buf;
goto load_rb;
}
strcpy(buf, RSTRING(fname)->ptr);
strcat(buf, DLEXT);
file = rb_find_file(buf);
if (file) {
default:
feature = buf;
file = rb_find_file(buf);
goto load_dyna;
}
#ifdef DLEXT2
strcpy(buf, RSTRING(fname)->ptr);
strcat(buf, DLEXT2);
file = rb_find_file(buf);
if (file) {
feature = buf;
goto load_dyna;
}
#endif
rb_raise(rb_eLoadError, "No such file to load -- %s",
RSTRING(fname)->ptr);
@ -6330,8 +6331,9 @@ callargs(args)
}
static VALUE
proc_call(proc, args)
proc_invoke(proc, args, pcall)
VALUE proc, args; /* OK */
int pcall;
{
struct BLOCK * volatile old_block;
struct BLOCK _block;
@ -6341,6 +6343,13 @@ proc_call(proc, args)
volatile int orphan;
volatile int safe = ruby_safe_level;
if (pcall) {
pcall = PC_ACHECK|PC_PCALL;
}
else {
pcall = PC_PCALL;
}
if (rb_block_given_p() && ruby_frame->last_func) {
rb_warning("block for %s#%s is useless",
rb_class2name(CLASS_OF(proc)),
@ -6367,7 +6376,7 @@ proc_call(proc, args)
state = EXEC_TAG();
if (state == 0) {
proc_set_safe_level(proc);
result = rb_yield_0(args, 0, 0, Qtrue);
result = rb_yield_0(args, 0, 0, pcall);
}
POP_TAG();
@ -6398,6 +6407,20 @@ proc_call(proc, args)
return result;
}
static VALUE
proc_call(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qtrue);
}
static VALUE
proc_yield(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qfalse);
}
static VALUE
proc_arity(proc)
VALUE proc;
@ -6899,6 +6922,7 @@ Init_Proc()
rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);
rb_define_method(rb_cProc, "call", proc_call, -2);
rb_define_method(rb_cProc, "yield", proc_yield, -2);
rb_define_method(rb_cProc, "arity", proc_arity, 0);
rb_define_method(rb_cProc, "[]", proc_call, -2);
rb_define_method(rb_cProc, "==", proc_eq, 1);
@ -8210,7 +8234,11 @@ rb_thread_start_0(fn, arg, th_arg)
}
#endif
if (ruby_block) { /* should nail down higher scopes */
if (THREAD_SAVE_CONTEXT(curr_thread)) {
return thread;
}
if (ruby_block) { /* should nail down higher blocks */
struct BLOCK dummy;
dummy.prev = ruby_block;
@ -8219,9 +8247,6 @@ rb_thread_start_0(fn, arg, th_arg)
}
scope_dup(ruby_scope);
FL_SET(ruby_scope, SCOPE_SHARED);
if (THREAD_SAVE_CONTEXT(curr_thread)) {
return thread;
}
if (!th->next) {
/* merge in thread list */
@ -8243,17 +8268,21 @@ rb_thread_start_0(fn, arg, th_arg)
POP_TAG();
status = th->status;
if (th == main_thread) ruby_stop(state);
rb_thread_remove(th);
while (saved_block) {
struct BLOCK *tmp = saved_block;
if (curr_thread == main_thread) {
printf("free(%p)\n", saved_block);
}
if (tmp->frame.argc > 0)
free(tmp->frame.argv);
saved_block = tmp->prev;
free(tmp);
}
if (th == main_thread) ruby_stop(state);
rb_thread_remove(th);
if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
th->flags |= THREAD_RAISED;
if (state == TAG_FATAL) {

110
file.c
View file

@ -2202,41 +2202,76 @@ is_macos_native_path(path)
}
#endif
static char*
file_load_ok(file)
char *file;
{
FILE *f;
f = fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
extern VALUE rb_load_path;
int
rb_find_file_noext(file)
char *file;
{
char *path, *e, *found;
char *fend = file + strlen(file);
VALUE fname;
int i, j;
static char *ext[] = {
".rb", DLEXT,
#ifdef DLEXT2
DLEXT2,
#endif
0
};
if (file[0] == '~') {
fname = rb_str_new2(file);
fname = rb_file_s_expand_path(1, &fname);
file = StringValuePtr(fname);
}
if (is_absolute_path(file)) {
for (i=0; ext[i]; i++) {
strcpy(fend, ext[i]);
if (file_load_ok(file)) return i+1;
}
return 0;
}
if (!rb_load_path) return 0;
Check_Type(rb_load_path, T_ARRAY);
for (i=0;i<RARRAY(rb_load_path)->len;i++) {
VALUE str = RARRAY(rb_load_path)->ptr[i];
SafeStringValue(str);
path = RSTRING(str)->ptr;
for (j=0; ext[j]; j++) {
strcpy(fend, ext[j]);
found = dln_find_file(file, path);
if (found && file_load_ok(found)) return j+1;
}
}
return 0;
}
char*
rb_find_file(file)
char *file;
{
extern VALUE rb_load_path;
VALUE vpath, fname;
char *path;
struct stat st;
#if defined(__MACOS__) || defined(riscos)
if (is_macos_native_path(file)) {
FILE *f;
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
f= fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
#endif
if (is_absolute_path(file)) {
FILE *f;
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
f = fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
if (file[0] == '~') {
fname = rb_str_new2(file);
fname = rb_file_s_expand_path(1, &fname);
@ -2246,6 +2281,22 @@ rb_find_file(file)
file = StringValuePtr(fname);
}
#if defined(__MACOS__) || defined(riscos)
if (is_macos_native_path(file)) {
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
return file_load_ok(file);
}
#endif
if (is_absolute_path(file)) {
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
return file_load_ok(file);
}
if (rb_load_path) {
int i;
@ -2269,10 +2320,7 @@ rb_find_file(file)
}
path = dln_find_file(file, path);
if (path && stat(path, &st) == 0) {
return path;
}
return 0;
return file_load_ok(path);
}
static void

View file

@ -27,6 +27,7 @@ VALUE rb_ary_new4 _((long, VALUE *));
VALUE rb_ary_freeze _((VALUE));
VALUE rb_ary_aref _((int, VALUE*, VALUE));
void rb_ary_store _((VALUE, long, VALUE));
VALUE rb_ary_to_ary _((VALUE));
VALUE rb_ary_to_s _((VALUE));
VALUE rb_ary_push _((VALUE, VALUE));
VALUE rb_ary_pop _((VALUE));
@ -179,6 +180,7 @@ void rb_thread_atfork _((void));
int eaccess _((const char*, int));
VALUE rb_file_s_expand_path _((int, VALUE *));
void rb_file_const _((const char*, VALUE));
int rb_find_file_noext _((char*));
char *rb_find_file _((char*));
/* gc.c */
void rb_gc_mark_locations _((VALUE*, VALUE*));

6
io.c
View file

@ -3462,10 +3462,8 @@ opt_i_set(val)
VALUE val;
{
if (ruby_inplace_mode) free(ruby_inplace_mode);
if (!RTEST(val)) {
ruby_inplace_mode = 0;
return;
}
ruby_inplace_mode = 0;
if (!RTEST(val)) return;
StringValue(val);
ruby_inplace_mode = strdup(RSTRING(val)->ptr);
}

View file

@ -854,7 +854,7 @@ class Resolv
raise DecodeError.new("limit exceed") if @limit < @index + len
arr = @data.unpack("@#{@index}#{template}")
@index += len
return *arr
return arr
end
def get_string

View file

@ -660,21 +660,24 @@ An end of a defun is found by moving forward from the beginning of one."
(cond
((featurep 'font-lock)
(or (boundp 'font-lock-variable-name-face)
(setq font-lock-variable-name-face font-lock-type-face))
(setq ruby-font-lock-syntactic-keywords
'(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil))
("\\(#\\)[{$@]" 1 (1 . nil))
("\\(/\\)\\([^/\n]\\|\\/\\)*\\(/\\)"
(1 (7 . ?'))
(3 (7 . ?')))
("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
(put major-mode 'font-lock-defaults
'((ruby-font-lock-keywords)
nil nil nil
beginning-of-line
(font-lock-syntactic-keywords
. ruby-font-lock-syntactic-keywords)))
(add-hook 'ruby-mode-hook
'(lambda ()
(make-local-variable 'font-lock-syntactic-keywords)
(setq font-lock-syntactic-keywords
'(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil))
("\\(#\\)[{$@]" 1 (1 . nil))
("\\(/\\)\\([^/\n]\\|\\/\\)*\\(/\\)"
(1 (7 . ?'))
(3 (7 . ?')))
("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
(setq font-lock-keywords ruby-font-lock-keywords)))
(defun ruby-font-lock-docs (limit)
(if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t)
@ -687,6 +690,21 @@ An end of a defun is found by moving forward from the beginning of one."
(set-match-data (list beg (point)))
t)))))
(defun ruby-font-lock-maybe-docs (limit)
(let (beg)
(save-excursion
(if (and (re-search-backward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t)
(string= (match-string-no-properties 1) "begin"))
(progn
(beginning-of-line)
(setq beg (point)))))
(if (and beg (and (re-search-forward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t)
(string= (match-string-no-properties 1) "end")))
(progn
(set-match-data (list beg (point)))
t)
nil)))
(defvar ruby-font-lock-keywords
(list
(cons (concat
@ -741,6 +759,8 @@ An end of a defun is found by moving forward from the beginning of one."
;; embedded document
'(ruby-font-lock-docs
0 font-lock-comment-face t)
'(ruby-font-lock-maybe-docs
0 font-lock-comment-face t)
;; constants
'("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
2 font-lock-type-face)

31
regex.c
View file

@ -1874,8 +1874,10 @@ re_compile_pattern(pattern, size, bufp)
if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) {
BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on);
}
BUFPUSH(option_set);
BUFPUSH(stackp[-1]);
if ((options ^ stackp[-1]) != RE_OPTION_IGNORECASE) {
BUFPUSH(option_set);
BUFPUSH(stackp[-1]);
}
}
p0 = b;
options = *--stackp;
@ -3262,7 +3264,8 @@ re_search(bufp, string, size, startpos, range, regs)
}
if (startpos > size) return -1;
if (anchor && size > 0 && startpos == size) return -1;
if ((anchor || !bufp->can_be_null) && size > 0 && startpos == size)
return -1;
val = re_match(bufp, string, size, startpos, regs);
if (val >= 0) return startpos;
if (val == -2) return -2;
@ -3362,7 +3365,7 @@ re_search(bufp, string, size, startpos, range, regs)
#define NUM_COUNT_ITEMS 2
/* Individual items aside from the registers. */
#define NUM_NONREG_ITEMS 3
#define NUM_NONREG_ITEMS 4
/* We push at most this many things on the stack whenever we
fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are
@ -3412,6 +3415,7 @@ re_search(bufp, string, size, startpos, range, regs)
\
*stackp++ = pattern_place; \
*stackp++ = string_place; \
*stackp++ = (unsigned char*)options; /* current option status */ \
*stackp++ = (unsigned char*)0; /* non-greedy flag */ \
} while(0)
@ -3735,15 +3739,11 @@ re_match(bufp, string_arg, size, pos, regs)
int regno = *p++; /* Get which register to match against */
register unsigned char *d2, *dend2;
#if 0
/* Check if corresponding group is still open */
if (IS_ACTIVE(reg_info[regno])) goto fail;
/* Where in input to try to start matching. */
d2 = regstart[regno];
#else
d2 = IS_ACTIVE(reg_info[regno])?old_regstart[regno]:regstart[regno];
#endif
if (REG_UNSET(d2)) goto fail;
/* Where to stop matching; if both the place to start and
@ -3791,7 +3791,7 @@ re_match(bufp, string_arg, size, pos, regs)
case stop_nowidth:
EXTRACT_NUMBER_AND_INCR(mcnt, p);
stackp = stackb + mcnt;
d = stackp[-2];
d = stackp[-3];
POP_FAILURE_POINT();
continue;
@ -4015,8 +4015,8 @@ re_match(bufp, string_arg, size, pos, regs)
because didn't fail. Also remove the register information
put on by the on_failure_jump. */
case finalize_jump:
if (stackp > stackb && stackp[-2] == d) {
p = stackp[-3];
if (stackp > stackb && stackp[-3] == d) {
p = stackp[-4];
POP_FAILURE_POINT();
continue;
}
@ -4032,7 +4032,7 @@ re_match(bufp, string_arg, size, pos, regs)
case jump:
nofinalize:
EXTRACT_NUMBER_AND_INCR(mcnt, p);
if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */
if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */
goto fail;
p += mcnt;
continue;
@ -4123,7 +4123,7 @@ re_match(bufp, string_arg, size, pos, regs)
case finalize_push:
POP_FAILURE_POINT();
EXTRACT_NUMBER_AND_INCR(mcnt, p);
if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */
if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */
goto fail;
PUSH_FAILURE_POINT(p + mcnt, d);
stackp[-1] = NON_GREEDY;
@ -4288,11 +4288,12 @@ re_match(bufp, string_arg, size, pos, regs)
/* If this failure point is from a dummy_failure_point, just
skip it. */
if (stackp[-3] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) {
if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) {
POP_FAILURE_POINT();
goto fail;
}
stackp--; /* discard flag */
stackp--; /* discard greedy flag */
options = (int)*--stackp;
d = *--stackp;
p = *--stackp;
/* Restore register info. */