[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#986742: unblock: ruby2.7/2.7.3-1



Control: tags -1 confirmed

On 2021-04-16 12:18:53, Antonio Terceiro wrote:
> On Fri, Apr 16, 2021 at 02:15:54PM +0200, Sebastian Ramacher wrote:
> > Control: tags -1 + moreinfo
> > 
> > On 2021-04-15 20:13:34 -0300, Antonio Terceiro wrote:
> > > On Sun, 11 Apr 2021 03:04:42 +0530 Utkarsh Gupta <utkarsh@debian.org> wrote:
> > > > Package: release.debian.org
> > > > Severity: normal
> > > > User: release.debian.org@packages.debian.org
> > > > Usertags: unblock
> > > > X-Debbugs-Cc: debian-ruby@lists.debian.org
> > > > 
> > > > Hello,
> > > > 
> > > > Upstream has recently released a bug-fix only release after a
> > > > vulnerability, CVE-2021-28965, was discovered.
> > > > 
> > > > Upstream release note:
> > > > https://www.ruby-lang.org/en/news/2021/04/05/ruby-2-7-3-released/
> > > > Upstream git logs b/w 2.7.2 and 2.7.3:
> > > > https://github.com/ruby/ruby/compare/v2_7_2...v2_7_3
> > > > 
> > > > This is clearly a bug-fix only release and it'd be *really great* to
> > > > have this included in Bullseye. (I'd be sad not to but..) I understand
> > > > it's your call to make after analyzing so attaching the debdiff for
> > > > your reference and help (snipping ChangeLog entries for noise
> > > > reduction).
> > > > 
> > > > Hopefully, it'd be OK to get this included and have an even nicer
> > > > ruby2.7 for Bullseye. Thanks.
> > > 
> > >  99 files changed, 39552 insertions(+), 23134 deletions(-)
> > > 
> > > The debian diff looks very big because of 3 generated files: ChangeLog,
> > > parse.c, and ext/ripper/ripper.c (the last two being bison/yacc
> > > generated parsers). If you filter those out, the result is a lot more
> > > palatable:
> > > 
> > >  96 files changed, 3761 insertions(+), 886 deletions(-)
> > > 
> > > Roughtly 1/3 of the insertions are test cases:
> > > 
> > >  32 files changed, 1150 insertions(+), 97 deletions(-)
> > 
> > Since the initial bug report didn't reach the list due the size of the
> > diff, could you or Utkarsh please prepare a filtered debdiff including
> > the changes to debian/? This would make it easier for us to reach a
> > decision. Thanks
> > 
> > Cheers
> > 
> > > 
> > > I have reviewed the upstream patches and compared the upstream diff with
> > > the debian diff, and indeed all the changes are bug fixes.
> > > 
> > > There was one marked as a "Feature" in the commit message, but it was
> > > really a follwup to fix an inconsistency in a feature that has been
> > > added in the 2.7 series already. It will cause formerly invalid syntax
> > > to be valid, but won't break any currently working code.
> > > 
> > > I think the risk with this update is low, and releasing with the latest
> > > available ruby bugfix release will make it easier to provide stable
> > > support in bullseye.
> > > 
> > > Full disclosure: I am trying to get ruby into new hands, but I'm still a
> > > comaintainer and care a lot about it, so I'm not an uninterested party
> > > here.
> 
> It turns out there also a 2 autogenerated autotools files.
> 
> Generated a filtered diff with
> 
> filterdiff --exclude=ChangeLog --exclude='*/parse.c' --exclude='*/ripper.c' --exclude='*/config.guess' --exclude='*/config.sub' ruby2.7.debdiff
> 
> and attached: 112 files changed, 3290 insertions(+), 995 deletions(-)

Thanks, please go ahead and remove the moreinfo tag once the version is
available in unstable.

Cheers


> diff -Nru ruby2.7-2.7.2/array.c ruby2.7-2.7.3/array.c
> --- ruby2.7-2.7.2/array.c 2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/array.c 2021-04-05 18:09:38.000000000 +0530
> @@ -5149,7 +5149,7 @@
>  {
>      long i;
>      VALUE stack, result, tmp, elt, vmemo;
> -    st_table *memo;
> +    st_table *memo = 0;
>      st_data_t id;
> 
>      for (i = 0; i < RARRAY_LEN(ary); i++) {
> @@ -5161,8 +5161,6 @@
>      }
>      if (i == RARRAY_LEN(ary)) {
>          return ary;
> -    } else if (tmp == ary) {
> -        rb_raise(rb_eArgError, "tried to flatten recursive array");
>      }
> 
>      result = ary_new(0, RARRAY_LEN(ary));
> @@ -5173,12 +5171,14 @@
>      rb_ary_push(stack, ary);
>      rb_ary_push(stack, LONG2NUM(i + 1));
> 
> -    vmemo = rb_hash_new();
> -    RBASIC_CLEAR_CLASS(vmemo);
> -    memo = st_init_numtable();
> -    rb_hash_st_table_set(vmemo, memo);
> -    st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
> -    st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue);
> +    if (level < 0) {
> + vmemo = rb_hash_new();
> + RBASIC_CLEAR_CLASS(vmemo);
> + memo = st_init_numtable();
> + rb_hash_st_table_set(vmemo, memo);
> + st_insert(memo, (st_data_t)ary, (st_data_t)Qtrue);
> + st_insert(memo, (st_data_t)tmp, (st_data_t)Qtrue);
> +    }
> 
>      ary = tmp;
>      i = 0;
> @@ -5192,20 +5192,24 @@
>       }
>       tmp = rb_check_array_type(elt);
>       if (RBASIC(result)->klass) {
> -                RB_GC_GUARD(vmemo);
> -                st_clear(memo);
> +   if (memo) {
> +       RB_GC_GUARD(vmemo);
> +       st_clear(memo);
> +   }
>     rb_raise(rb_eRuntimeError, "flatten reentered");
>       }
>       if (NIL_P(tmp)) {
>     rb_ary_push(result, elt);
>       }
>       else {
> -   id = (st_data_t)tmp;
> -   if (st_is_member(memo, id)) {
> -                    st_clear(memo);
> -       rb_raise(rb_eArgError, "tried to flatten recursive array");
> +   if (memo) {
> +       id = (st_data_t)tmp;
> +       if (st_is_member(memo, id)) {
> +     st_clear(memo);
> +     rb_raise(rb_eArgError, "tried to flatten recursive array");
> +       }
> +       st_insert(memo, id, (st_data_t)Qtrue);
>     }
> -   st_insert(memo, id, (st_data_t)Qtrue);
>     rb_ary_push(stack, ary);
>     rb_ary_push(stack, LONG2NUM(i));
>     ary = tmp;
> @@ -5215,14 +5219,18 @@
>   if (RARRAY_LEN(stack) == 0) {
>       break;
>   }
> - id = (st_data_t)ary;
> - st_delete(memo, &id, 0);
> + if (memo) {
> +     id = (st_data_t)ary;
> +     st_delete(memo, &id, 0);
> + }
>   tmp = rb_ary_pop(stack);
>   i = NUM2LONG(tmp);
>   ary = rb_ary_pop(stack);
>      }
> 
> -    st_clear(memo);
> +    if (memo) {
> + st_clear(memo);
> +    }
> 
>      RBASIC_SET_CLASS(result, rb_obj_class(ary));
>      return result;
> diff -Nru ruby2.7-2.7.2/class.c ruby2.7-2.7.3/class.c
> --- ruby2.7-2.7.2/class.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/class.c	2021-04-05 18:09:38.000000000 +0530
> @@ -32,6 +32,9 @@
>  
>  #define id_attached id__attached__
>  
> +#define METACLASS_OF(k) RBASIC(k)->klass
> +#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
> +
>  void
>  rb_class_subclass_add(VALUE super, VALUE klass)
>  {
> @@ -372,22 +375,35 @@
>      return rb_singleton_class_clone_and_attach(obj, Qundef);
>  }
>  
> +// Clone and return the singleton class of `obj` if it has been created and is attached to `obj`.
>  VALUE
>  rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
>  {
>      const VALUE klass = RBASIC(obj)->klass;
>  
> -    if (!FL_TEST(klass, FL_SINGLETON))
> -	return klass;
> +    // Note that `rb_singleton_class()` can create situations where `klass` is
> +    // attached to an object other than `obj`. In which case `obj` does not have
> +    // a material singleton class attached yet and there is no singleton class
> +    // to clone.
> +    if (!(FL_TEST(klass, FL_SINGLETON) && rb_attr_get(klass, id_attached) == obj)) {
> +        // nothing to clone
> +        return klass;
> +    }
>      else {
>  	/* copy singleton(unnamed) class */
> +        bool klass_of_clone_is_new;
>  	VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
>  
>  	if (BUILTIN_TYPE(obj) == T_CLASS) {
> +            klass_of_clone_is_new = true;
>  	    RBASIC_SET_CLASS(clone, clone);
>  	}
>  	else {
> -	    RBASIC_SET_CLASS(clone, rb_singleton_class_clone(klass));
> +            VALUE klass_metaclass_clone = rb_singleton_class_clone(klass);
> +            // When `METACLASS_OF(klass) == klass_metaclass_clone`, it means the
> +            // recursive call did not clone `METACLASS_OF(klass)`.
> +            klass_of_clone_is_new = (METACLASS_OF(klass) != klass_metaclass_clone);
> +            RBASIC_SET_CLASS(clone, klass_metaclass_clone);
>  	}
>  
>  	RCLASS_SET_SUPER(clone, RCLASS_SUPER(klass));
> @@ -411,7 +427,9 @@
>  	    arg.new_klass = clone;
>  	    rb_id_table_foreach(RCLASS_M_TBL(klass), clone_method_i, &arg);
>  	}
> -	rb_singleton_class_attached(RBASIC(clone)->klass, clone);
> +        if (klass_of_clone_is_new) {
> +            rb_singleton_class_attached(RBASIC(clone)->klass, clone);
> +        }
>  	FL_SET(clone, FL_SINGLETON);
>  
>  	return clone;
> @@ -433,11 +451,6 @@
>      }
>  }
>  
> -
> -
> -#define METACLASS_OF(k) RBASIC(k)->klass
> -#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
> -
>  /*!
>   * whether k is a meta^(n)-class of Class class
>   * @retval 1 if \a k is a meta^(n)-class of Class class (n >= 0)
> diff -Nru ruby2.7-2.7.2/compile.c ruby2.7-2.7.3/compile.c
> --- ruby2.7-2.7.2/compile.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/compile.c	2021-04-05 18:09:38.000000000 +0530
> @@ -2737,7 +2737,6 @@
>  	    goto again;
>  	}
>          else if (IS_INSN_ID(diobj, leave)) {
> -	    INSN *pop;
>  	    /*
>  	     *  jump LABEL
>  	     *  ...
> @@ -2745,7 +2744,6 @@
>  	     *  leave
>  	     * =>
>  	     *  leave
> -	     *  pop
>  	     *  ...
>  	     * LABEL:
>  	     *  leave
> @@ -2755,9 +2753,6 @@
>              iobj->insn_id = BIN(leave);
>  	    iobj->operand_size = 0;
>  	    iobj->insn_info = diobj->insn_info;
> -	    /* adjust stack depth */
> -	    pop = new_insn_body(iseq, diobj->insn_info.line_no, BIN(pop), 0);
> -            ELEM_INSERT_NEXT(&iobj->link, &pop->link);
>  	    goto again;
>  	}
>         else if (IS_INSN(iobj->link.prev) &&
> @@ -5247,6 +5242,9 @@
>  		branches);
>  	    end_label = NEW_LABEL(line);
>  	    ADD_INSNL(then_seq, line, jump, end_label);
> +            if (!popped) {
> +                ADD_INSN(then_seq, line, pop);
> +            }
>  	}
>  	ADD_SEQ(ret, then_seq);
>      }
> @@ -9849,14 +9847,13 @@
>      const char *name = (char *)ibf_load_ptr(load, offset, len);
>  
>      if (0) {
> -        for (int i=0; i<len; i++) fprintf(stderr, "%c", name[i]);
> -        fprintf(stderr, "!!\n");
> +        fprintf(stderr, "%.*s!!\n", len, name);
>      }
>  
>      const struct rb_builtin_function *table = GET_VM()->builtin_function_table;
> -    if (table == NULL) rb_bug("%s: table is not provided.", RUBY_FUNCTION_NAME_STRING);
> +    if (table == NULL) rb_raise(rb_eArgError, "builtin function table is not provided");
>      if (strncmp(table[i].name, name, len) != 0) {
> -        rb_bug("%s: index (%d) mismatch (expect %s but %s).", RUBY_FUNCTION_NAME_STRING, i, name, table[i].name);
> +        rb_raise(rb_eArgError, "builtin function index (%d) mismatch (expect %s but %s)", i, name, table[i].name);
>      }
>      // fprintf(stderr, "load-builtin: name:%s(%d)\n", table[i].name, table[i].argc);
>  
> diff -Nru ruby2.7-2.7.2/configure ruby2.7-2.7.3/configure
> --- ruby2.7-2.7.2/configure	2020-10-01 17:45:40.000000000 +0530
> +++ ruby2.7-2.7.3/configure	2021-04-05 18:09:40.000000000 +0530
> @@ -6521,7 +6521,7 @@
>  fi
>  # RUBY_UNIVERSAL_ARCH end
>  
> -if test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "$universal_binary" = no; then :
> +if test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "${universal_binary:-no}" = no; then :
>  
>  
>  { $as_echo "$as_me:${as_lineno-$LINENO}: checking arch option" >&5
> @@ -6540,6 +6540,11 @@
>  
>  
>  fi
> +host_os=$target_os
> +host_vendor=$target_vendor
> +host_cpu=$target_cpu
> +host=$target
> +host_alias=$target_alias
>  
>  case "$target_os" in #(
>    darwin*) :
> @@ -18372,7 +18377,7 @@
>  
>  	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>  /* end confdefs.h.  */
> -unsigned char atomic_var;
> +unsigned int atomic_var;
>  int
>  main ()
>  {
> @@ -18412,7 +18417,7 @@
>  
>  	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
>  /* end confdefs.h.  */
> -unsigned char atomic_var;
> +unsigned int atomic_var;
>  int
>  main ()
>  {
> @@ -23627,6 +23632,28 @@
>  fi
>  done
>  
> +for ac_func in getlogin
> +do :
> +  ac_fn_c_check_func "$LINENO" "getlogin" "ac_cv_func_getlogin"
> +if test "x$ac_cv_func_getlogin" = xyes; then :
> +  cat >>confdefs.h <<_ACEOF
> +#define HAVE_GETLOGIN 1
> +_ACEOF
> +
> +fi
> +done
> +
> +for ac_func in getlogin_r
> +do :
> +  ac_fn_c_check_func "$LINENO" "getlogin_r" "ac_cv_func_getlogin_r"
> +if test "x$ac_cv_func_getlogin_r" = xyes; then :
> +  cat >>confdefs.h <<_ACEOF
> +#define HAVE_GETLOGIN_R 1
> +_ACEOF
> +
> +fi
> +done
> +
>  for ac_func in getpgid
>  do :
>    ac_fn_c_check_func "$LINENO" "getpgid" "ac_cv_func_getpgid"
> @@ -23660,6 +23687,17 @@
>  fi
>  done
>  
> +for ac_func in getpwnam
> +do :
> +  ac_fn_c_check_func "$LINENO" "getpwnam" "ac_cv_func_getpwnam"
> +if test "x$ac_cv_func_getpwnam" = xyes; then :
> +  cat >>confdefs.h <<_ACEOF
> +#define HAVE_GETPWNAM 1
> +_ACEOF
> +
> +fi
> +done
> +
>  for ac_func in getpwnam_r
>  do :
>    ac_fn_c_check_func "$LINENO" "getpwnam_r" "ac_cv_func_getpwnam_r"
> @@ -23671,6 +23709,28 @@
>  fi
>  done
>  
> +for ac_func in getpwuid
> +do :
> +  ac_fn_c_check_func "$LINENO" "getpwuid" "ac_cv_func_getpwuid"
> +if test "x$ac_cv_func_getpwuid" = xyes; then :
> +  cat >>confdefs.h <<_ACEOF
> +#define HAVE_GETPWUID 1
> +_ACEOF
> +
> +fi
> +done
> +
> +for ac_func in getpwuid_r
> +do :
> +  ac_fn_c_check_func "$LINENO" "getpwuid_r" "ac_cv_func_getpwuid_r"
> +if test "x$ac_cv_func_getpwuid_r" = xyes; then :
> +  cat >>confdefs.h <<_ACEOF
> +#define HAVE_GETPWUID_R 1
> +_ACEOF
> +
> +fi
> +done
> +
>  for ac_func in getrandom
>  do :
>    ac_fn_c_check_func "$LINENO" "getrandom" "ac_cv_func_getrandom"
> @@ -26824,11 +26884,11 @@
>  else
>    rb_cv_func_pthread_setname_np_arguments=
>  	    # Linux,AIX,  (pthread_self(), name)
> -	    # NetBSD (pthread_self(), name, \"%s\")
> +	    # NetBSD (pthread_self(), \"%s\", name)
>  	    # Darwin (name)
>  	    for mac in \
>  		"(pthread_self(), name)" \
> -		"(pthread_self(), name, \"%s\")" \
> +		"(pthread_self(), \"%s\", name)" \
>  		"(name)" \
>  		; do
>  		cat confdefs.h - <<_ACEOF >conftest.$ac_ext
> @@ -27974,12 +28034,12 @@
>      stack_t ss;
>      struct sigaction sa;
>  
> -    ss.ss_sp = malloc(SIGSTKSZ);
> +    ss.ss_sp = malloc(16*1024);
>      if (ss.ss_sp == NULL) {
>  	fprintf(stderr, "cannot allocate memory for sigaltstack\n");
>  	return EXIT_FAILURE;
>      }
> -    ss.ss_size = SIGSTKSZ;
> +    ss.ss_size = 16*1024;
>      ss.ss_flags = 0;
>      if (sigaltstack(&ss, NULL) == -1) {
>  	fprintf(stderr, "sigaltstack failed\n");
> diff -Nru ruby2.7-2.7.2/configure.ac ruby2.7-2.7.3/configure.ac
> --- ruby2.7-2.7.2/configure.ac	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/configure.ac	2021-04-05 18:09:38.000000000 +0530
> @@ -309,9 +309,14 @@
>  : ${DLDFLAGS="$LDFLAGS"}
>  
>  RUBY_UNIVERSAL_ARCH
> -AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "$universal_binary" = no], [
> +AS_IF([test "$target_cpu" != "$host_cpu" -a "$GCC" = yes -a "$cross_compiling" = no -a "${universal_binary:-no}" = no], [
>      RUBY_DEFAULT_ARCH("$target_cpu")
>  ])
> +host_os=$target_os
> +host_vendor=$target_vendor
> +host_cpu=$target_cpu
> +host=$target
> +host_alias=$target_alias
>  
>  AS_CASE(["$target_os"], [darwin*], [
>  if libtool 2>&1 | grep no_warning_for_no_symbols > /dev/null; then
> @@ -1452,7 +1457,7 @@
>      ])
>  
>      AC_CACHE_CHECK([for __atomic builtins], [rb_cv_gcc_atomic_builtins], [
> -	AC_TRY_LINK([unsigned char atomic_var;],
> +	AC_TRY_LINK([unsigned int atomic_var;],
>  		    [
>  			__atomic_exchange_n(&atomic_var, 0, __ATOMIC_SEQ_CST);
>  			__atomic_exchange_n(&atomic_var, 1, __ATOMIC_SEQ_CST);
> @@ -1467,7 +1472,7 @@
>      ])
>  
>      AC_CACHE_CHECK([for __sync builtins], [rb_cv_gcc_sync_builtins], [
> -	AC_TRY_LINK([unsigned char atomic_var;],
> +	AC_TRY_LINK([unsigned int atomic_var;],
>  		    [
>  			__sync_lock_test_and_set(&atomic_var, 0);
>  			__sync_lock_test_and_set(&atomic_var, 1);
> @@ -1828,10 +1833,15 @@
>  AC_CHECK_FUNCS(getgrnam)
>  AC_CHECK_FUNCS(getgrnam_r)
>  AC_CHECK_FUNCS(getgroups)
> +AC_CHECK_FUNCS(getlogin)
> +AC_CHECK_FUNCS(getlogin_r)
>  AC_CHECK_FUNCS(getpgid)
>  AC_CHECK_FUNCS(getpgrp)
>  AC_CHECK_FUNCS(getpriority)
> +AC_CHECK_FUNCS(getpwnam)
>  AC_CHECK_FUNCS(getpwnam_r)
> +AC_CHECK_FUNCS(getpwuid)
> +AC_CHECK_FUNCS(getpwuid_r)
>  AC_CHECK_FUNCS(getrandom)
>  AC_CHECK_FUNCS(getresgid)
>  AC_CHECK_FUNCS(getresuid)
> @@ -2410,11 +2420,11 @@
>  	AC_CACHE_CHECK([arguments of pthread_setname_np], [rb_cv_func_pthread_setname_np_arguments],
>  	    [rb_cv_func_pthread_setname_np_arguments=
>  	    # Linux,AIX,  (pthread_self(), name)
> -	    # NetBSD (pthread_self(), name, \"%s\")
> +	    # NetBSD (pthread_self(), \"%s\", name)
>  	    # Darwin (name)
>  	    for mac in \
>  		"(pthread_self(), name)" \
> -		"(pthread_self(), name, \"%s\")" \
> +		"(pthread_self(), \"%s\", name)" \
>  		"(name)" \
>  		; do
>  		AC_TRY_COMPILE([
> @@ -2860,12 +2870,12 @@
>      stack_t ss;
>      struct sigaction sa;
>  
> -    ss.ss_sp = malloc(SIGSTKSZ);
> +    ss.ss_sp = malloc(16*1024);
>      if (ss.ss_sp == NULL) {
>  	fprintf(stderr, "cannot allocate memory for sigaltstack\n");
>  	return EXIT_FAILURE;
>      }
> -    ss.ss_size = SIGSTKSZ;
> +    ss.ss_size = 16*1024;
>      ss.ss_flags = 0;
>      if (sigaltstack(&ss, NULL) == -1) {
>  	fprintf(stderr, "sigaltstack failed\n");
> diff -Nru ruby2.7-2.7.2/cont.c ruby2.7-2.7.3/cont.c
> --- ruby2.7-2.7.2/cont.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/cont.c	2021-04-05 18:09:38.000000000 +0530
> @@ -324,6 +324,7 @@
>  #ifdef FIBER_POOL_ALLOCATION_FREE
>      if (head) {
>          head->previous = vacancy;
> +        vacancy->previous = NULL;
>      }
>  #endif
>  
> @@ -919,9 +920,7 @@
>      else {
>          rb_fiber_t *fiber = (rb_fiber_t*)cont;
>          coroutine_destroy(&fiber->context);
> -        if (!fiber_is_root_p(fiber)) {
> -            fiber_stack_release(fiber);
> -        }
> +        fiber_stack_release(fiber);
>      }
>  
>      RUBY_FREE_UNLESS_NULL(cont->saved_vm_stack.ptr);
> diff -Nru ruby2.7-2.7.2/coroutine/copy/Context.c ruby2.7-2.7.3/coroutine/copy/Context.c
> --- ruby2.7-2.7.2/coroutine/copy/Context.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/coroutine/copy/Context.c	2021-04-05 18:09:38.000000000 +0530
> @@ -7,6 +7,8 @@
>  
>  #include "Context.h"
>  
> +#include <stdint.h>
> +
>  // http://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
>  #ifndef __GNUC__
>  #define __asm__ asm
> @@ -35,13 +37,22 @@
>  static void coroutine_flush_register_windows() {}
>  #endif
>  
> -int coroutine_save_stack(struct coroutine_context * context) {
> -    void *stack_pointer = &stack_pointer;
> +__attribute__((noinline))
> +void *coroutine_stack_pointer() {
> +    return (void*)(
> +        (char*)__builtin_frame_address(0)
> +    );
> +}
>  
> +// Save the current stack to a private area. It is likely that when restoring the stack, this stack frame will be incomplete. But that is acceptable since the previous stack frame which called `setjmp` should be correctly restored.
> +__attribute__((noinline))
> +int coroutine_save_stack_1(struct coroutine_context * context) {
>      assert(context->stack);
>      assert(context->base);
>  
> -    // At this point, you may need to ensure on architectures that use register windows, that all registers are flushed to the stack.
> +    void *stack_pointer = coroutine_stack_pointer();
> +
> +    // At this point, you may need to ensure on architectures that use register windows, that all registers are flushed to the stack, otherwise the copy of the stack will not contain the valid registers:
>      coroutine_flush_register_windows();
>  
>      // Save stack to private area:
> @@ -59,16 +70,30 @@
>          context->used = size;
>      }
>  
> -    // Save registers / restore point:
> -    return _setjmp(context->state);
> +    // Initialized:
> +    return 0;
> +}
> +
> +// Copy the current stack to a private memory buffer.
> +int coroutine_save_stack(struct coroutine_context * context) {
> +    if (_setjmp(context->state)) {
> +        // Restored.
> +        return 1;
> +    }
> +
> +    // We need to invoke the memory copy from one stack frame deeper than the one that calls setjmp. That is because if you don't do this, the setjmp might be restored into an invalid stack frame (truncated, etc):
> +    return coroutine_save_stack_1(context);
>  }
>  
>  __attribute__((noreturn, noinline))
> -static void coroutine_restore_stack_padded(struct coroutine_context *context, void * buffer) {
> -    void *stack_pointer = &stack_pointer;
> +void coroutine_restore_stack_padded(struct coroutine_context *context, void * buffer) {
> +    void *stack_pointer = coroutine_stack_pointer();
>  
>      assert(context->base);
>  
> +    // At this point, you may need to ensure on architectures that use register windows, that all registers are flushed to the stack, otherwise when we copy in the new stack, the registers would not be updated:
> +    coroutine_flush_register_windows();
> +
>      // Restore stack from private area:
>      if (stack_pointer < context->base) {
>          void * bottom = (char*)context->base - context->used;
> @@ -82,28 +107,24 @@
>          memcpy(context->base, context->stack, context->used);
>      }
>  
> -    // Restore registers:
> -    // The `| (int)buffer` is to force the compiler NOT to elide he buffer and `alloca`.
> -    _longjmp(context->state, 1 | (int)buffer);
> +    // Restore registers. The `buffer` is to force the compiler NOT to elide he buffer and `alloca`:
> +    _longjmp(context->state, (int)(1 | (intptr_t)buffer));
>  }
>  
> -static const size_t GAP = 128;
> -
>  // In order to swap between coroutines, we need to swap the stack and registers.
>  // `setjmp` and `longjmp` are able to swap registers, but what about swapping stacks? You can use `memcpy` to copy the current stack to a private area and `memcpy` to copy the private stack of the next coroutine to the main stack.
>  // But if the stack yop are copying in to the main stack is bigger than the currently executing stack, the `memcpy` will clobber the current stack frame (including the context argument). So we use `alloca` to push the current stack frame *beyond* the stack we are about to copy in. This ensures the current stack frame in `coroutine_restore_stack_padded` remains valid for calling `longjmp`.
>  __attribute__((noreturn))
>  void coroutine_restore_stack(struct coroutine_context *context) {
> -    void *stack_pointer = &stack_pointer;
> +    void *stack_pointer = coroutine_stack_pointer();
>      void *buffer = NULL;
> -    ssize_t offset = 0;
>  
>      // We must ensure that the next stack frame is BEYOND the stack we are restoring:
>      if (stack_pointer < context->base) {
> -        offset = (char*)stack_pointer - ((char*)context->base - context->used) + GAP;
> +        intptr_t offset = (intptr_t)stack_pointer - ((intptr_t)context->base - context->used);
>          if (offset > 0) buffer = alloca(offset);
>      } else {
> -        offset = ((char*)context->base + context->used) - (char*)stack_pointer + GAP;
> +        intptr_t offset = ((intptr_t)context->base + context->used) - (intptr_t)stack_pointer;
>          if (offset > 0) buffer = alloca(offset);
>      }
>  
> @@ -128,9 +149,9 @@
>      // It's possible to come here, even thought the current fiber has been terminated. We are never going to return so we don't bother saving the stack.
>  
>      if (current->stack) {
> -      if (coroutine_save_stack(current) == 0) {
> -          coroutine_restore_stack(target);
> -      }
> +        if (coroutine_save_stack(current) == 0) {
> +            coroutine_restore_stack(target);
> +        }
>      } else {
>          coroutine_restore_stack(target);
>      }
> diff -Nru ruby2.7-2.7.2/debian/changelog ruby2.7-2.7.3/debian/changelog
> --- ruby2.7-2.7.2/debian/changelog	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/changelog	2021-04-10 21:26:26.000000000 +0530
> @@ -1,3 +1,19 @@
> +ruby2.7 (2.7.3-1) unstable; urgency=medium
> +
> +  [ Chris Hofstaedtler ]
> +  * Remove myself from Uploaders
> +
> +  [ Utkarsh Gupta ]
> +  * New upstream version 2.7.3
> +    - Fixes CVE-2021-28965: XML round-trip vulnerability in REXML.
> +  * Refresh d/patches
> +  * Drop patches that have been merged upstream
> +    - d/p/0008-Fix-priority-order-of-paths-in-I-option.patch
> +    - d/p/0010-Fix-IRBTestIRBHistory-tests.patch
> +    - d/p/0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch
> +
> + -- Utkarsh Gupta <utkarsh@debian.org>  Sat, 10 Apr 2021 21:26:26 +0530
> +
>  ruby2.7 (2.7.2-4) unstable; urgency=medium
>  
>    [ Antonio Terceiro ]
> diff -Nru ruby2.7-2.7.2/debian/control ruby2.7-2.7.3/debian/control
> --- ruby2.7-2.7.2/debian/control	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/control	2021-04-10 21:24:04.000000000 +0530
> @@ -3,7 +3,6 @@
>  Priority: optional
>  Maintainer: Debian Ruby Team <pkg-ruby-extras-maintainers@lists.alioth.debian.org>
>  Uploaders: Antonio Terceiro <terceiro@debian.org>,
> -           Chris Hofstaedtler <zeha@debian.org>,
>             Lucas Kanashiro <kanashiro@debian.org>,
>             Utkarsh Gupta <utkarsh@debian.org>
>  Build-Depends: bison,
> diff -Nru ruby2.7-2.7.2/debian/gbp.conf ruby2.7-2.7.3/debian/gbp.conf
> --- ruby2.7-2.7.2/debian/gbp.conf	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/debian/gbp.conf	2021-04-10 21:24:04.000000000 +0530
> @@ -0,0 +1,2 @@
> +[DEFAULT]
> +pristine-tar = True
> diff -Nru ruby2.7-2.7.2/debian/patches/0001-rdoc-build-reproducible-documentation.patch ruby2.7-2.7.3/debian/patches/0001-rdoc-build-reproducible-documentation.patch
> --- ruby2.7-2.7.2/debian/patches/0001-rdoc-build-reproducible-documentation.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0001-rdoc-build-reproducible-documentation.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -12,11 +12,9 @@
>   lib/rdoc/rdoc.rb                 | 2 +-
>   2 files changed, 3 insertions(+), 3 deletions(-)
>  
> -diff --git a/lib/rdoc/generator/json_index.rb b/lib/rdoc/generator/json_index.rb
> -index 3a10000..f40bb37 100644
>  --- a/lib/rdoc/generator/json_index.rb
>  +++ b/lib/rdoc/generator/json_index.rb
> -@@ -178,7 +178,7 @@ class RDoc::Generator::JsonIndex
> +@@ -178,7 +178,7 @@
>       debug_msg "Writing gzipped search index to %s" % outfile
>   
>       Zlib::GzipWriter.open(outfile) do |gz|
> @@ -25,7 +23,7 @@
>         gz.orig_name = search_index_file.basename.to_s
>         gz.write search_index
>         gz.close
> -@@ -196,7 +196,7 @@ class RDoc::Generator::JsonIndex
> +@@ -196,7 +196,7 @@
>           debug_msg "Writing gzipped file to %s" % outfile
>   
>           Zlib::GzipWriter.open(outfile) do |gz|
> @@ -34,11 +32,9 @@
>             gz.orig_name = dest.basename.to_s
>             gz.write data
>             gz.close
> -diff --git a/lib/rdoc/rdoc.rb b/lib/rdoc/rdoc.rb
> -index c60e017..368c9dc 100644
>  --- a/lib/rdoc/rdoc.rb
>  +++ b/lib/rdoc/rdoc.rb
> -@@ -312,7 +312,7 @@ option)
> +@@ -312,7 +312,7 @@
>         end
>       end
>   
> diff -Nru ruby2.7-2.7.2/debian/patches/0002-lib-mkmf.rb-sort-list-of-object-files-in-generated-M.patch ruby2.7-2.7.3/debian/patches/0002-lib-mkmf.rb-sort-list-of-object-files-in-generated-M.patch
> --- ruby2.7-2.7.2/debian/patches/0002-lib-mkmf.rb-sort-list-of-object-files-in-generated-M.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0002-lib-mkmf.rb-sort-list-of-object-files-in-generated-M.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -13,11 +13,9 @@
>   lib/mkmf.rb | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>  
> -diff --git a/lib/mkmf.rb b/lib/mkmf.rb
> -index eabccd4..ce18e82 100644
>  --- a/lib/mkmf.rb
>  +++ b/lib/mkmf.rb
> -@@ -2315,7 +2315,7 @@ LOCAL_LIBS = #{$LOCAL_LIBS}
> +@@ -2315,7 +2315,7 @@
>   LIBS = #{$LIBRUBYARG} #{$libs} #{$LIBS}
>   ORIG_SRCS = #{orig_srcs.collect(&File.method(:basename)).join(' ')}
>   SRCS = $(ORIG_SRCS) #{(srcs - orig_srcs).collect(&File.method(:basename)).join(' ')}
> diff -Nru ruby2.7-2.7.2/debian/patches/0003-Mark-Gemspec-reproducible-change-fixing-784225-too.patch ruby2.7-2.7.3/debian/patches/0003-Mark-Gemspec-reproducible-change-fixing-784225-too.patch
> --- ruby2.7-2.7.2/debian/patches/0003-Mark-Gemspec-reproducible-change-fixing-784225-too.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0003-Mark-Gemspec-reproducible-change-fixing-784225-too.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -11,11 +11,9 @@
>   lib/rubygems/specification.rb | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
>  
> -diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb
> -index f925480..e737586 100644
>  --- a/lib/rubygems/specification.rb
>  +++ b/lib/rubygems/specification.rb
> -@@ -1702,7 +1702,9 @@ class Gem::Specification < Gem::BasicSpecification
> +@@ -1702,7 +1702,9 @@
>                   raise(Gem::InvalidSpecificationException,
>                         "invalid date format in specification: #{date.inspect}")
>                 end
> diff -Nru ruby2.7-2.7.2/debian/patches/0004-Disable-tests-failing-on-Ubuntu-builders.patch ruby2.7-2.7.3/debian/patches/0004-Disable-tests-failing-on-Ubuntu-builders.patch
> --- ruby2.7-2.7.2/debian/patches/0004-Disable-tests-failing-on-Ubuntu-builders.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0004-Disable-tests-failing-on-Ubuntu-builders.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -9,16 +9,10 @@
>   create mode 100644 test/excludes/TestFileUtils.rb
>   create mode 100644 test/excludes/TestProcess.rb
>  
> -diff --git a/test/excludes/TestFileUtils.rb b/test/excludes/TestFileUtils.rb
> -new file mode 100644
> -index 0000000..ee8b15c
>  --- /dev/null
>  +++ b/test/excludes/TestFileUtils.rb
>  @@ -0,0 +1 @@
>  +exclude :test_chown, "fails on Launchpad builders"
> -diff --git a/test/excludes/TestProcess.rb b/test/excludes/TestProcess.rb
> -new file mode 100644
> -index 0000000..37b406e
>  --- /dev/null
>  +++ b/test/excludes/TestProcess.rb
>  @@ -0,0 +1 @@
> diff -Nru ruby2.7-2.7.2/debian/patches/0005-Make-gemspecs-reproducible.patch ruby2.7-2.7.3/debian/patches/0005-Make-gemspecs-reproducible.patch
> --- ruby2.7-2.7.2/debian/patches/0005-Make-gemspecs-reproducible.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0005-Make-gemspecs-reproducible.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -12,11 +12,9 @@
>   lib/rdoc/rdoc.gemspec             | 1 +
>   5 files changed, 5 insertions(+), 1 deletion(-)
>  
> -diff --git a/ext/bigdecimal/bigdecimal.gemspec b/ext/bigdecimal/bigdecimal.gemspec
> -index 7d767f5..26de3e0 100644
>  --- a/ext/bigdecimal/bigdecimal.gemspec
>  +++ b/ext/bigdecimal/bigdecimal.gemspec
> -@@ -6,6 +6,7 @@ Gem::Specification.new do |s|
> +@@ -6,6 +6,7 @@
>     s.name          = "bigdecimal"
>     s.version       = bigdecimal_version
>     s.authors       = ["Kenta Murata", "Zachary Scott", "Shigeo Kobayashi"]
> @@ -24,8 +22,6 @@
>     s.email         = ["mrkn@mrkn.jp"]
>   
>     s.summary       = "Arbitrary-precision decimal floating-point number library."
> -diff --git a/ext/fiddle/fiddle.gemspec b/ext/fiddle/fiddle.gemspec
> -index b29f4ec..36ed213 100644
>  --- a/ext/fiddle/fiddle.gemspec
>  +++ b/ext/fiddle/fiddle.gemspec
>  @@ -2,6 +2,7 @@
> @@ -36,11 +32,9 @@
>     spec.authors       = ["Aaron Patterson", "SHIBATA Hiroshi"]
>     spec.email         = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org"]
>   
> -diff --git a/ext/io/console/io-console.gemspec b/ext/io/console/io-console.gemspec
> -index 814bd4e..2e50587 100644
>  --- a/ext/io/console/io-console.gemspec
>  +++ b/ext/io/console/io-console.gemspec
> -@@ -5,7 +5,7 @@ date = %w$Date::                           $[1]
> +@@ -5,7 +5,7 @@
>   Gem::Specification.new do |s|
>     s.name = "io-console"
>     s.version = _VERSION
> @@ -49,11 +43,9 @@
>     s.summary = "Console interface"
>     s.email = "nobu@ruby-lang.org"
>     s.description = "add console capabilities to IO instances."
> -diff --git a/lib/ipaddr.gemspec b/lib/ipaddr.gemspec
> -index 2de9ef4..4f8072a 100644
>  --- a/lib/ipaddr.gemspec
>  +++ b/lib/ipaddr.gemspec
> -@@ -6,6 +6,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
> +@@ -6,6 +6,7 @@
>   Gem::Specification.new do |spec|
>     spec.name          = "ipaddr"
>     spec.version       = "1.2.2"
> @@ -61,11 +53,9 @@
>     spec.authors       = ["Akinori MUSHA", "Hajimu UMEMOTO"]
>     spec.email         = ["knu@idaemons.org", "ume@mahoroba.org"]
>   
> -diff --git a/lib/rdoc/rdoc.gemspec b/lib/rdoc/rdoc.gemspec
> -index 9b274c7..eb7a47e 100644
>  --- a/lib/rdoc/rdoc.gemspec
>  +++ b/lib/rdoc/rdoc.gemspec
> -@@ -7,6 +7,7 @@ end
> +@@ -7,6 +7,7 @@
>   
>   Gem::Specification.new do |s|
>     s.name = "rdoc"
> diff -Nru ruby2.7-2.7.2/debian/patches/0006-Fix-FTBS-on-hurd.patch ruby2.7-2.7.3/debian/patches/0006-Fix-FTBS-on-hurd.patch
> --- ruby2.7-2.7.2/debian/patches/0006-Fix-FTBS-on-hurd.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0006-Fix-FTBS-on-hurd.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -10,11 +10,9 @@
>   io.c | 6 +++++-
>   1 file changed, 5 insertions(+), 1 deletion(-)
>  
> -diff --git a/io.c b/io.c
> -index 868756f..fc00ed0 100644
>  --- a/io.c
>  +++ b/io.c
> -@@ -1753,7 +1753,11 @@ io_writev(int argc, VALUE *argv, VALUE io)
> +@@ -1753,7 +1753,11 @@
>   
>       for (i = 0; i < argc; i += cnt) {
>   #ifdef HAVE_WRITEV
> diff -Nru ruby2.7-2.7.2/debian/patches/0007-Port-to-kfreebsd-amd64.patch ruby2.7-2.7.3/debian/patches/0007-Port-to-kfreebsd-amd64.patch
> --- ruby2.7-2.7.2/debian/patches/0007-Port-to-kfreebsd-amd64.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0007-Port-to-kfreebsd-amd64.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -13,11 +13,9 @@
>   test/socket/test_socket.rb |  2 +-
>   4 files changed, 26 insertions(+), 2 deletions(-)
>  
> -diff --git a/ext/socket/option.c b/ext/socket/option.c
> -index 5ad44cd..87ddbc9 100644
>  --- a/ext/socket/option.c
>  +++ b/ext/socket/option.c
> -@@ -10,6 +10,7 @@ VALUE rb_cSockOpt;
> +@@ -10,6 +10,7 @@
>   #if defined(__linux__) || \
>       defined(__GNU__) /* GNU/Hurd */ || \
>       defined(__FreeBSD__) || \
> @@ -25,11 +23,9 @@
>       defined(__DragonFly__) || \
>       defined(__APPLE__) || \
>       defined(_WIN32) || \
> -diff --git a/ext/socket/raddrinfo.c b/ext/socket/raddrinfo.c
> -index 9ec2fdc..2e3eeb5 100644
>  --- a/ext/socket/raddrinfo.c
>  +++ b/ext/socket/raddrinfo.c
> -@@ -1788,10 +1788,21 @@ addrinfo_mload(VALUE self, VALUE ary)
> +@@ -1788,10 +1788,21 @@
>           INIT_SOCKADDR_UN(&uaddr, sizeof(struct sockaddr_un));
>   
>           StringValue(v);
> @@ -51,7 +47,7 @@
>           memcpy(uaddr.sun_path, RSTRING_PTR(v), RSTRING_LEN(v));
>           len = (socklen_t)sizeof(uaddr);
>           memcpy(&ss, &uaddr, len);
> -@@ -2435,10 +2446,21 @@ addrinfo_unix_path(VALUE self)
> +@@ -2435,10 +2446,21 @@
>       if (n < 0)
>           rb_raise(rb_eSocket, "too short AF_UNIX address: %"PRIuSIZE" bytes given for minimum %"PRIuSIZE" bytes.",
>                    (size_t)rai->sockaddr_len, offsetof(struct sockaddr_un, sun_path));
> @@ -73,11 +69,9 @@
>       return rb_str_new(addr->sun_path, n);
>   }
>   #endif
> -diff --git a/test/fiddle/test_handle.rb b/test/fiddle/test_handle.rb
> -index 17f9c92..2862585 100644
>  --- a/test/fiddle/test_handle.rb
>  +++ b/test/fiddle/test_handle.rb
> -@@ -150,6 +150,7 @@ module Fiddle
> +@@ -150,6 +150,7 @@
>       end unless /mswin|mingw/ =~ RUBY_PLATFORM
>   
>       def test_dlerror
> @@ -85,7 +79,7 @@
>         # FreeBSD (at least 7.2 to 7.2) calls nsdispatch(3) when it calls
>         # getaddrinfo(3). And nsdispatch(3) doesn't call dlerror(3) even if
>         # it calls _nss_cache_cycle_prevention_function with dlsym(3).
> -@@ -158,7 +159,7 @@ module Fiddle
> +@@ -158,7 +159,7 @@
>         require 'socket'
>         Socket.gethostbyname("localhost")
>         Fiddle.dlopen("/lib/libc.so.7").sym('strcpy')
> @@ -94,11 +88,9 @@
>   
>       def test_no_memory_leak
>         assert_no_memory_leak(%w[-W0 -rfiddle.so], '', '100_000.times {Fiddle::Handle.allocate}; GC.start', rss: true)
> -diff --git a/test/socket/test_socket.rb b/test/socket/test_socket.rb
> -index f1ec927..4d22a3c 100644
>  --- a/test/socket/test_socket.rb
>  +++ b/test/socket/test_socket.rb
> -@@ -530,7 +530,7 @@ class TestSocket < Test::Unit::TestCase
> +@@ -530,7 +530,7 @@
>     end
>   
>     def test_bintime
> diff -Nru ruby2.7-2.7.2/debian/patches/0008-Fix-priority-order-of-paths-in-I-option.patch ruby2.7-2.7.3/debian/patches/0008-Fix-priority-order-of-paths-in-I-option.patch
> --- ruby2.7-2.7.2/debian/patches/0008-Fix-priority-order-of-paths-in-I-option.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0008-Fix-priority-order-of-paths-in-I-option.patch	1970-01-01 05:30:00.000000000 +0530
> @@ -1,43 +0,0 @@
> -From: =?utf-8?q?C=C3=A9dric_Boutillier?= <boutil@debian.org>
> -Date: Tue, 4 Feb 2020 18:55:42 +0100
> -Subject: Fix priority order of paths in -I option
> -
> -Origin: https://github.com/rubygems/rubygems/pull/3124
> -Author: deivid <deivid.rodriguez@riseup.net>
> ----
> - lib/rubygems/core_ext/kernel_require.rb | 20 ++++++++++----------
> - 1 file changed, 10 insertions(+), 10 deletions(-)
> -
> -diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb
> -index 60f4d18..3828338 100644
> ---- a/lib/rubygems/core_ext/kernel_require.rb
> -+++ b/lib/rubygems/core_ext/kernel_require.rb
> -@@ -43,18 +43,18 @@ module Kernel
> -     # https://github.com/rubygems/rubygems/pull/1868
> -     resolved_path = begin
> -       rp = nil
> --      $LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp|
> --        safe_lp = lp.dup.tap(&Gem::UNTAINT)
> --        begin
> --          if File.symlink? safe_lp # for backward compatibility
> --            next
> -+      Gem.suffixes.each do |s|
> -+        $LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp|
> -+          safe_lp = lp.dup.tap(&Gem::UNTAINT)
> -+          begin
> -+            if File.symlink? safe_lp # for backward compatibility
> -+              next
> -+            end
> -+          rescue SecurityError
> -+            RUBYGEMS_ACTIVATION_MONITOR.exit
> -+            raise
> -           end
> --        rescue SecurityError
> --          RUBYGEMS_ACTIVATION_MONITOR.exit
> --          raise
> --        end
> - 
> --        Gem.suffixes.each do |s|
> -           full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
> -           if File.file?(full_path)
> -             rp = full_path
> diff -Nru ruby2.7-2.7.2/debian/patches/0009-Fix-FTBFS-on-x32-misdetected-as-i386-or-amd64.patch ruby2.7-2.7.3/debian/patches/0009-Fix-FTBFS-on-x32-misdetected-as-i386-or-amd64.patch
> --- ruby2.7-2.7.2/debian/patches/0009-Fix-FTBFS-on-x32-misdetected-as-i386-or-amd64.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0009-Fix-FTBFS-on-x32-misdetected-as-i386-or-amd64.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -8,11 +8,9 @@
>   configure.ac | 3 +++
>   1 file changed, 3 insertions(+)
>  
> -diff --git a/configure.ac b/configure.ac
> -index 6766df2..429c35b 100644
>  --- a/configure.ac
>  +++ b/configure.ac
> -@@ -2312,6 +2312,9 @@ AS_CASE([$rb_cv_coroutine], [yes|''], [
> +@@ -2322,6 +2322,9 @@
>           [arm64-darwin*], [
>               rb_cv_coroutine=arm64
>           ],
> diff -Nru ruby2.7-2.7.2/debian/patches/0010-Fix-IRBTestIRBHistory-tests.patch ruby2.7-2.7.3/debian/patches/0010-Fix-IRBTestIRBHistory-tests.patch
> --- ruby2.7-2.7.2/debian/patches/0010-Fix-IRBTestIRBHistory-tests.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0010-Fix-IRBTestIRBHistory-tests.patch	1970-01-01 05:30:00.000000000 +0530
> @@ -1,237 +0,0 @@
> -From: aycabta <aycabta@gmail.com>
> -Date: Mon, 5 Oct 2020 18:57:47 +0900
> -Subject: [PATCH] Remove system method for E2E testing because depends on ruby
> - command
> -
> ----
> - test/irb/test_history.rb | 146 +++++++++++++++++++++++++++--------------------
> - 1 file changed, 83 insertions(+), 63 deletions(-)
> -
> -diff --git a/test/irb/test_history.rb b/test/irb/test_history.rb
> -index 3591f88..392a6af 100644
> ---- a/test/irb/test_history.rb
> -+++ b/test/irb/test_history.rb
> -@@ -1,6 +1,7 @@
> - # frozen_string_literal: false
> - require 'test/unit'
> - require 'irb'
> -+require 'irb/ext/save-history'
> - require 'readline'
> - 
> - module TestIRB
> -@@ -13,133 +14,152 @@ module TestIRB
> -       IRB.conf[:RC_NAME_GENERATOR] = nil
> -     end
> - 
> -+    class TestInputMethod < ::IRB::InputMethod
> -+      HISTORY = Array.new
> -+
> -+      include IRB::HistorySavingAbility
> -+
> -+      attr_reader :list, :line_no
> -+
> -+      def initialize(list = [])
> -+        super("test")
> -+        @line_no = 0
> -+        @list = list
> -+      end
> -+
> -+      def gets
> -+        @list[@line_no]&.tap {@line_no += 1}
> -+      end
> -+
> -+      def eof?
> -+        @line_no >= @list.size
> -+      end
> -+
> -+      def encoding
> -+        Encoding.default_external
> -+      end
> -+
> -+      def reset
> -+        @line_no = 0
> -+      end
> -+
> -+      def winsize
> -+        [10, 20]
> -+      end
> -+    end
> -+
> -     def test_history_save_1
> -       omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> --      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> --        IRB.conf[:USE_READLINE] = true
> --        IRB.conf[:SAVE_HISTORY] = 1
> --        IRB.conf[:USE_READLINE] = true
> --      IRBRC
> -+      IRB.conf[:SAVE_HISTORY] = 1
> -+      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
> -+        exit
> -+      EXPECTED_HISTORY
> -         1
> -         2
> -         3
> -         4
> --      IRB_HISTORY
> --        stdin.write("5\nexit\n")
> --      end
> --
> --      assert_equal(<<~HISTORY_FILE, result_history_file)
> -+      INITIAL_HISTORY
> -+        5
> -         exit
> --      HISTORY_FILE
> -+      INPUT
> -     end
> - 
> -     def test_history_save_100
> -       omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> --      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> --        IRB.conf[:USE_READLINE] = true
> --        IRB.conf[:SAVE_HISTORY] = 100
> --        IRB.conf[:USE_READLINE] = true
> --      IRBRC
> -+      IRB.conf[:SAVE_HISTORY] = 100
> -+      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
> -         1
> -         2
> -         3
> -         4
> --      IRB_HISTORY
> --        stdin.write("5\nexit\n")
> --      end
> --
> --      assert_equal(<<~HISTORY_FILE, result_history_file)
> -+        5
> -+        exit
> -+      EXPECTED_HISTORY
> -         1
> -         2
> -         3
> -         4
> -+      INITIAL_HISTORY
> -         5
> -         exit
> --      HISTORY_FILE
> -+      INPUT
> -     end
> - 
> -     def test_history_save_bignum
> -       omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> --      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> --        IRB.conf[:USE_READLINE] = true
> --        IRB.conf[:SAVE_HISTORY] = 10 ** 19
> --        IRB.conf[:USE_READLINE] = true
> --      IRBRC
> -+      IRB.conf[:SAVE_HISTORY] = 10 ** 19
> -+      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
> -         1
> -         2
> -         3
> -         4
> --      IRB_HISTORY
> --        stdin.write("5\nexit\n")
> --      end
> --
> --      assert_equal(<<~HISTORY_FILE, result_history_file)
> -+        5
> -+        exit
> -+      EXPECTED_HISTORY
> -         1
> -         2
> -         3
> -         4
> -+      INITIAL_HISTORY
> -         5
> -         exit
> --      HISTORY_FILE
> -+      INPUT
> -     end
> - 
> -     def test_history_save_minus_as_infinity
> -       omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> --      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> --        IRB.conf[:USE_READLINE] = true
> --        IRB.conf[:SAVE_HISTORY] = -1 # infinity
> --        IRB.conf[:USE_READLINE] = true
> --      IRBRC
> -+      IRB.conf[:SAVE_HISTORY] = -1 # infinity
> -+      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
> -         1
> -         2
> -         3
> -         4
> --      IRB_HISTORY
> --        stdin.write("5\nexit\n")
> --      end
> --
> --      assert_equal(<<~HISTORY_FILE, result_history_file)
> -+        5
> -+        exit
> -+      EXPECTED_HISTORY
> -         1
> -         2
> -         3
> -         4
> -+      INITIAL_HISTORY
> -         5
> -         exit
> --      HISTORY_FILE
> -+      INPUT
> -     end
> - 
> -     private
> - 
> --    def launch_irb_with_irbrc_and_irb_history(irbrc, irb_history)
> --      result = nil
> --      result_history = nil
> --      backup_irbrc = ENV.delete("IRBRC")
> -+    def assert_history(expected_history, initial_irb_history, input)
> -+      backup_verbose, $VERBOSE = $VERBOSE, nil
> -       backup_home = ENV["HOME"]
> -+      IRB.conf[:LC_MESSAGES] = IRB::Locale.new
> -+      actual_history = nil
> -       Dir.mktmpdir("test_irb_history_#{$$}") do |tmpdir|
> -         ENV["HOME"] = tmpdir
> --        open(IRB.rc_file, "w") do |f|
> --          f.write(irbrc)
> --        end
> -         open(IRB.rc_file("_history"), "w") do |f|
> --          f.write(irb_history)
> -+          f.write(initial_irb_history)
> -         end
> - 
> --        with_temp_stdio do |stdin, stdout|
> --          yield(stdin, stdout)
> --          stdin.close
> --          stdout.flush
> --          system('ruby', '-Ilib', '-Itest', '-W0', '-rirb', '-e', 'IRB.start(__FILE__)', in: stdin.path, out: stdout.path)
> --          result = stdout.read
> --          stdout.close
> --        end
> -+        io = TestInputMethod.new
> -+        io.class::HISTORY.clear
> -+        io.load_history
> -+        io.class::HISTORY.concat(input.split)
> -+        io.save_history
> -+
> -+        io.load_history
> -         open(IRB.rc_file("_history"), "r") do |f|
> --          result_history = f.read
> -+          actual_history = f.read
> -         end
> -       end
> --      [result, result_history]
> -+      assert_equal(expected_history, actual_history, <<~MESSAGE)
> -+        expected:
> -+        #{expected_history}
> -+        but actual:
> -+        #{actual_history}
> -+      MESSAGE
> -     ensure
> -+      $VERBOSE = backup_verbose
> -       ENV["HOME"] = backup_home
> --      ENV["IRBRC"] = backup_irbrc
> -     end
> - 
> -     def with_temp_stdio
> diff -Nru ruby2.7-2.7.2/debian/patches/0011-Dont-use-relative-path.patch ruby2.7-2.7.3/debian/patches/0011-Dont-use-relative-path.patch
> --- ruby2.7-2.7.2/debian/patches/0011-Dont-use-relative-path.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0011-Dont-use-relative-path.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -8,11 +8,9 @@
>   test/rubygems/test_gem_stub_specification.rb     | 8 ++++----
>   3 files changed, 5 insertions(+), 7 deletions(-)
>  
> -diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb
> -index 8940320..53ba84a 100644
>  --- a/lib/rubygems/test_case.rb
>  +++ b/lib/rubygems/test_case.rb
> -@@ -96,8 +96,6 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni
> +@@ -96,8 +96,6 @@
>   
>     TEST_PATH = ENV.fetch('RUBYGEMS_TEST_PATH', File.expand_path('../../../test/rubygems', __FILE__))
>   
> @@ -21,11 +19,9 @@
>     def assert_activate(expected, *specs)
>       specs.each do |spec|
>         case spec
> -diff --git a/test/rubygems/test_gem_commands_build_command.rb b/test/rubygems/test_gem_commands_build_command.rb
> -index 309e15f..aaca54f 100644
>  --- a/test/rubygems/test_gem_commands_build_command.rb
>  +++ b/test/rubygems/test_gem_commands_build_command.rb
> -@@ -123,7 +123,7 @@ class TestGemCommandsBuildCommand < Gem::TestCase
> +@@ -123,7 +123,7 @@
>     end
>   
>     def test_execute_rubyforge_project_warning
> @@ -34,11 +30,9 @@
>   
>       @cmd.options[:args] = [rubyforge_gemspec]
>   
> -diff --git a/test/rubygems/test_gem_stub_specification.rb b/test/rubygems/test_gem_stub_specification.rb
> -index 91a46d7..2579f8a 100644
>  --- a/test/rubygems/test_gem_stub_specification.rb
>  +++ b/test/rubygems/test_gem_stub_specification.rb
> -@@ -4,14 +4,14 @@ require "rubygems/stub_specification"
> +@@ -4,14 +4,14 @@
>   
>   class TestStubSpecification < Gem::TestCase
>   
> diff -Nru ruby2.7-2.7.2/debian/patches/0012-Fix-getcwd-ENOENT.patch ruby2.7-2.7.3/debian/patches/0012-Fix-getcwd-ENOENT.patch
> --- ruby2.7-2.7.2/debian/patches/0012-Fix-getcwd-ENOENT.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0012-Fix-getcwd-ENOENT.patch	2021-04-10 21:26:26.000000000 +0530
> @@ -15,11 +15,9 @@
>   lib/rubygems/bundler_version_finder.rb | 17 ++++++++++++-----
>   1 file changed, 12 insertions(+), 5 deletions(-)
>  
> -diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb
> -index 38da773..ea6698f 100644
>  --- a/lib/rubygems/bundler_version_finder.rb
>  +++ b/lib/rubygems/bundler_version_finder.rb
> -@@ -82,12 +82,19 @@ To install the missing version, run `gem install bundler:#{vr.first}`
> +@@ -82,12 +82,19 @@
>     def self.lockfile_contents
>       gemfile = ENV["BUNDLE_GEMFILE"]
>       gemfile = nil if gemfile && gemfile.empty?
> diff -Nru ruby2.7-2.7.2/debian/patches/0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch ruby2.7-2.7.3/debian/patches/0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch
> --- ruby2.7-2.7.2/debian/patches/0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch	1970-01-01 05:30:00.000000000 +0530
> @@ -1,172 +0,0 @@
> -From: AGSaidi <AGSaidi@users.noreply.github.com>
> -Date: Thu, 13 Aug 2020 12:15:54 -0500
> -Subject: Enable arm64 optimizations that exist for power/x86 (#3393)
> -
> -* Enable unaligned accesses on arm64
> -
> -64-bit Arm platforms support unaligned accesses.
> -
> -Running the string benchmarks this change improves performance
> -by an average of 1.04x, min .96x, max 1.21x, median 1.01x
> -
> -* arm64 enable gc optimizations
> -
> -Similar to x86 and powerpc optimizations.
> -
> -|       |compare-ruby|built-ruby|
> -|:------|-----------:|---------:|
> -|hash1  |       0.225|     0.237|
> -|       |           -|     1.05x|
> -|hash2  |       0.110|     0.110|
> -|       |       1.00x|         -|
> -
> -* vm_exec.c: improve performance for arm64
> -
> -|                               |compare-ruby|built-ruby|
> -|:------------------------------|-----------:|---------:|
> -|vm_array                       |     26.501M|   27.959M|
> -|                               |           -|     1.06x|
> -|vm_attr_ivar                   |     21.606M|   31.429M|
> -|                               |           -|     1.45x|
> -|vm_attr_ivar_set               |     21.178M|   26.113M|
> -|                               |           -|     1.23x|
> -|vm_backtrace                   |       6.621|     6.668|
> -|                               |           -|     1.01x|
> -|vm_bigarray                    |     26.205M|   29.958M|
> -|                               |           -|     1.14x|
> -|vm_bighash                     |    504.155k|  479.306k|
> -|                               |       1.05x|         -|
> -|vm_block                       |     16.692M|   21.315M|
> -|                               |           -|     1.28x|
> -|block_handler_type_iseq        |       5.083|     7.004|
> -|                               |           -|     1.38x|
> -
> -Origin: upstream, https://github.com/ruby/ruby/commit/511b55bcefc81c03
> -Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/ruby2.7/+bug/1901074
> -Reviewed-By: Lucas Kanashiro <kanashiro@debian.org>
> -Last-Updated: 2020-10-30
> ----
> - gc.c                   | 13 +++++++++++++
> - gc.h                   |  2 ++
> - include/ruby/defines.h |  2 +-
> - regint.h               |  2 +-
> - siphash.c              |  2 +-
> - st.c                   |  2 +-
> - vm_exec.c              |  8 ++++++++
> - 7 files changed, 27 insertions(+), 4 deletions(-)
> -
> -diff --git a/gc.c b/gc.c
> -index 73faf46..b06fdc5 100644
> ---- a/gc.c
> -+++ b/gc.c
> -@@ -1153,6 +1153,19 @@ tick(void)
> -     return val;
> - }
> - 
> -+#elif defined(__aarch64__) &&  defined(__GNUC__)
> -+typedef unsigned long tick_t;
> -+#define PRItick "lu"
> -+
> -+static __inline__ tick_t
> -+tick(void)
> -+{
> -+    unsigned long val;
> -+    __asm__ __volatile__ ("mrs %0, cntvct_el0", : "=r" (val));
> -+    return val;
> -+}
> -+
> -+
> - #elif defined(_WIN32) && defined(_MSC_VER)
> - #include <intrin.h>
> - typedef unsigned __int64 tick_t;
> -diff --git a/gc.h b/gc.h
> -index cf794fa..72e3935 100644
> ---- a/gc.h
> -+++ b/gc.h
> -@@ -8,6 +8,8 @@
> - #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
> - #elif defined(__powerpc64__) && defined(__GNUC__)
> - #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
> -+#elif defined(__aarch64__) && defined(__GNUC__)
> -+#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
> - #else
> - NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
> - #define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
> -diff --git a/include/ruby/defines.h b/include/ruby/defines.h
> -index 5e03d49..e953b05 100644
> ---- a/include/ruby/defines.h
> -+++ b/include/ruby/defines.h
> -@@ -485,7 +485,7 @@ void rb_sparc_flush_register_windows(void);
> - #ifndef UNALIGNED_WORD_ACCESS
> - # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
> -      defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> --     defined(__powerpc64__) || \
> -+     defined(__powerpc64__) || defined(__aarch64__) || \
> -      defined(__mc68020__)
> - #   define UNALIGNED_WORD_ACCESS 1
> - # else
> -diff --git a/regint.h b/regint.h
> -index a2f5bbb..0740429 100644
> ---- a/regint.h
> -+++ b/regint.h
> -@@ -52,7 +52,7 @@
> - #ifndef UNALIGNED_WORD_ACCESS
> - # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
> -      defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> --     defined(__powerpc64__) || \
> -+     defined(__powerpc64__) || defined(__aarch64__) || \
> -      defined(__mc68020__)
> - #  define UNALIGNED_WORD_ACCESS 1
> - # else
> -diff --git a/siphash.c b/siphash.c
> -index 153d2c6..ddf8ee2 100644
> ---- a/siphash.c
> -+++ b/siphash.c
> -@@ -30,7 +30,7 @@
> - #ifndef UNALIGNED_WORD_ACCESS
> - # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
> -      defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> --     defined(__powerpc64__) || \
> -+     defined(__powerpc64__) || defined(__aarch64__) || \
> -      defined(__mc68020__)
> - #   define UNALIGNED_WORD_ACCESS 1
> - # endif
> -diff --git a/st.c b/st.c
> -index 2b973ea..4258f93 100644
> ---- a/st.c
> -+++ b/st.c
> -@@ -1815,7 +1815,7 @@ st_values_check(st_table *tab, st_data_t *values, st_index_t size,
> - #ifndef UNALIGNED_WORD_ACCESS
> - # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
> -      defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> --     defined(__powerpc64__) || \
> -+     defined(__powerpc64__) || defined(__aarch64__) || \
> -      defined(__mc68020__)
> - #   define UNALIGNED_WORD_ACCESS 1
> - # endif
> -diff --git a/vm_exec.c b/vm_exec.c
> -index 0adaa7b..cb09738 100644
> ---- a/vm_exec.c
> -+++ b/vm_exec.c
> -@@ -27,6 +27,9 @@ static void vm_analysis_insn(int insn);
> - #elif defined(__GNUC__) && defined(__powerpc64__)
> - #define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
> - 
> -+#elif defined(__GNUC__) && defined(__aarch64__)
> -+#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("x" reg)
> -+
> - #else
> - #define DECL_SC_REG(type, r, reg) register type reg_##r
> - #endif
> -@@ -74,6 +77,11 @@ vm_exec_core(rb_execution_context_t *ec, VALUE initial)
> -     DECL_SC_REG(rb_control_frame_t *, cfp, "15");
> - #define USE_MACHINE_REGS 1
> - 
> -+#elif defined(__GNUC__) && defined(__aarch64__)
> -+    DECL_SC_REG(const VALUE *, pc, "19");
> -+    DECL_SC_REG(rb_control_frame_t *, cfp, "20");
> -+#define USE_MACHINE_REGS 1
> -+
> - #else
> -     register rb_control_frame_t *reg_cfp;
> -     const VALUE *reg_pc;
> diff -Nru ruby2.7-2.7.2/debian/patches/series ruby2.7-2.7.3/debian/patches/series
> --- ruby2.7-2.7.2/debian/patches/series	2021-02-02 19:42:23.000000000 +0530
> +++ ruby2.7-2.7.3/debian/patches/series	2021-04-10 21:26:26.000000000 +0530
> @@ -5,9 +5,6 @@
>  0005-Make-gemspecs-reproducible.patch
>  0006-Fix-FTBS-on-hurd.patch
>  0007-Port-to-kfreebsd-amd64.patch
> -0008-Fix-priority-order-of-paths-in-I-option.patch
>  0009-Fix-FTBFS-on-x32-misdetected-as-i386-or-amd64.patch
> -0010-Fix-IRBTestIRBHistory-tests.patch
>  0011-Dont-use-relative-path.patch
>  0012-Fix-getcwd-ENOENT.patch
> -0013-Enable-arm64-optimizations-that-exist-for-power-x86-.patch
> diff -Nru ruby2.7-2.7.2/debian/salsa-ci.yml ruby2.7-2.7.3/debian/salsa-ci.yml
> --- ruby2.7-2.7.2/debian/salsa-ci.yml	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/debian/salsa-ci.yml	2020-12-12 02:41:56.000000000 +0530
> @@ -0,0 +1,7 @@
> +---
> +include:
> +  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
> +  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
> +
> +variables:
> +  DEBIAN_RUBY_EXTRA_TEST_EXCLUDES: salsa
> diff -Nru ruby2.7-2.7.2/enum.c ruby2.7-2.7.3/enum.c
> --- ruby2.7-2.7.2/enum.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/enum.c	2021-04-05 18:09:38.000000000 +0530
> @@ -771,7 +771,7 @@
>                  if (FIXNUM_P(e)) {
>                      n += FIX2LONG(e); /* should not overflow long type */
>                      if (!FIXABLE(n)) {
> -                        v = rb_big_plus(ULONG2NUM(n), v);
> +                        v = rb_big_plus(LONG2NUM(n), v);
>                          n = 0;
>                      }
>                  }
> diff -Nru ruby2.7-2.7.2/enumerator.c ruby2.7-2.7.3/enumerator.c
> --- ruby2.7-2.7.2/enumerator.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/enumerator.c	2021-04-05 18:09:38.000000000 +0530
> @@ -3535,6 +3535,88 @@
>      return rb_call_super(argc, argv);
>  }
>  
> +static inline VALUE
> +num_plus(VALUE a, VALUE b)
> +{
> +    if (RB_INTEGER_TYPE_P(a)) {
> +        return rb_int_plus(a, b);
> +    }
> +    else if (RB_FLOAT_TYPE_P(a)) {
> +        return rb_float_plus(a, b);
> +    }
> +    else if (RB_TYPE_P(a, T_RATIONAL)) {
> +        return rb_rational_plus(a, b);
> +    }
> +    else {
> +        return rb_funcallv(a, '+', 1, &b);
> +    }
> +}
> +
> +static inline VALUE
> +num_minus(VALUE a, VALUE b)
> +{
> +    if (RB_INTEGER_TYPE_P(a)) {
> +        return rb_int_minus(a, b);
> +    }
> +    else if (RB_FLOAT_TYPE_P(a)) {
> +        return rb_float_minus(a, b);
> +    }
> +    else if (RB_TYPE_P(a, T_RATIONAL)) {
> +        return rb_rational_minus(a, b);
> +    }
> +    else {
> +        return rb_funcallv(a, '-', 1, &b);
> +    }
> +}
> +
> +static inline VALUE
> +num_mul(VALUE a, VALUE b)
> +{
> +    if (RB_INTEGER_TYPE_P(a)) {
> +        return rb_int_mul(a, b);
> +    }
> +    else if (RB_FLOAT_TYPE_P(a)) {
> +        return rb_float_mul(a, b);
> +    }
> +    else if (RB_TYPE_P(a, T_RATIONAL)) {
> +        return rb_rational_mul(a, b);
> +    }
> +    else {
> +        return rb_funcallv(a, '*', 1, &b);
> +    }
> +}
> +
> +static inline VALUE
> +num_idiv(VALUE a, VALUE b)
> +{
> +    VALUE q;
> +    if (RB_INTEGER_TYPE_P(a)) {
> +        q = rb_int_idiv(a, b);
> +    }
> +    else if (RB_FLOAT_TYPE_P(a)) {
> +        q = rb_float_div(a, b);
> +    }
> +    else if (RB_TYPE_P(a, T_RATIONAL)) {
> +        q = rb_rational_div(a, b);
> +    }
> +    else {
> +        q = rb_funcallv(a, idDiv, 1, &b);
> +    }
> +
> +    if (RB_INTEGER_TYPE_P(q)) {
> +        return q;
> +    }
> +    else if (RB_FLOAT_TYPE_P(q)) {
> +        return rb_float_floor(q, 0);
> +    }
> +    else if (RB_TYPE_P(q, T_RATIONAL)) {
> +        return rb_rational_floor(q, 0);
> +    }
> +    else {
> +        return rb_funcall(q, rb_intern("floor"), 0);
> +    }
> +}
> +
>  /*
>   * call-seq:
>   *   aseq.last    -> num or nil
> @@ -3559,7 +3641,7 @@
>      b = arith_seq_begin(self);
>      s = arith_seq_step(self);
>  
> -    len_1 = rb_int_idiv(rb_int_minus(e, b), s);
> +    len_1 = num_idiv(num_minus(e, b), s);
>      if (rb_num_negative_int_p(len_1)) {
>          if (argc == 0) {
>              return Qnil;
> @@ -3567,9 +3649,9 @@
>          return rb_ary_new_capa(0);
>      }
>  
> -    last = rb_int_plus(b, rb_int_mul(s, len_1));
> +    last = num_plus(b, num_mul(s, len_1));
>      if ((last_is_adjusted = arith_seq_exclude_end_p(self) && rb_equal(last, e))) {
> -        last = rb_int_minus(last, s);
> +        last = num_minus(last, s);
>      }
>  
>      if (argc == 0) {
> @@ -3778,22 +3860,22 @@
>          return self;
>      }
>  
> -    len_1 = rb_int_idiv(rb_int_minus(e, c), s);
> -    last = rb_int_plus(c, rb_int_mul(s, len_1));
> +    len_1 = num_idiv(num_minus(e, c), s);
> +    last = num_plus(c, num_mul(s, len_1));
>      if (x && rb_equal(last, e)) {
> -        last = rb_int_minus(last, s);
> +        last = num_minus(last, s);
>      }
>  
>      if (rb_num_negative_int_p(s)) {
>          while (NUM_GE(c, last)) {
>              rb_yield(c);
> -            c = rb_int_plus(c, s);
> +            c = num_plus(c, s);
>          }
>      }
>      else {
>          while (NUM_GE(last, c)) {
>              rb_yield(c);
> -            c = rb_int_plus(c, s);
> +            c = num_plus(c, s);
>          }
>      }
>  
> diff -Nru ruby2.7-2.7.2/eval_intern.h ruby2.7-2.7.3/eval_intern.h
> --- ruby2.7-2.7.2/eval_intern.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/eval_intern.h	2021-04-05 18:09:38.000000000 +0530
> @@ -291,7 +291,16 @@
>  
>  #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
>  # ifdef HAVE_MBLEN
> -#  define CharNext(p) ((p) + mblen((p), RUBY_MBCHAR_MAXSIZE))
> +#  define CharNext(p) rb_char_next(p)
> +static inline const char *
> +rb_char_next(const char *p)
> +{
> +    if (p) {
> +        int len = mblen(p, RUBY_MBCHAR_MAXSIZE);
> +        p += len > 0 ? len : 1;
> +    }
> +    return p;
> +}
>  # else
>  #  define CharNext(p) ((p) + 1)
>  # endif
> diff -Nru ruby2.7-2.7.2/ext/.document ruby2.7-2.7.3/ext/.document
> --- ruby2.7-2.7.2/ext/.document	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/ext/.document	2021-04-05 18:09:38.000000000 +0530
> @@ -30,6 +30,8 @@
>  json/generator/generator.c
>  json/lib
>  json/parser/parser.c
> +monitor/lib
> +monitor/monitor.c
>  nkf/lib
>  nkf/nkf.c
>  objspace/objspace.c
> diff -Nru ruby2.7-2.7.2/ext/pathname/pathname.c ruby2.7-2.7.3/ext/pathname/pathname.c
> --- ruby2.7-2.7.2/ext/pathname/pathname.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/ext/pathname/pathname.c	2021-04-05 18:09:38.000000000 +0530
> @@ -360,10 +360,10 @@
>      args[0] = get_strpath(self);
>      n = rb_scan_args(argc, argv, "03", &args[1], &args[2], &args[3]);
>      if (rb_block_given_p()) {
> -        return rb_block_call(rb_cFile, id_foreach, 1+n, args, 0, 0);
> +        return rb_block_call_kw(rb_cFile, id_foreach, 1+n, args, 0, 0, RB_PASS_CALLED_KEYWORDS);
>      }
>      else {
> -        return rb_funcallv(rb_cFile, id_foreach, 1+n, args);
> +        return rb_funcallv_kw(rb_cFile, id_foreach, 1+n, args, RB_PASS_CALLED_KEYWORDS);
>      }
>  }
>  
> diff -Nru ruby2.7-2.7.2/ext/ripper/ripper.y ruby2.7-2.7.3/ext/ripper/ripper.y
> --- ruby2.7-2.7.2/ext/ripper/ripper.y	2020-10-01 17:45:40.000000000 +0530
> +++ ruby2.7-2.7.3/ext/ripper/ripper.y	2021-04-05 18:09:40.000000000 +0530
> @@ -2418,6 +2418,32 @@
>  #endif
>  			{VALUE v1,v2;v1=escape_Qundef($2);v2=dispatch1(arg_paren,v1);$$=v2;}
>  		    }
> +		| '(' args ',' args_forward rparen
> +		    {
> +			if (!local_id(p, idFWD_REST) ||
> +#if idFWD_KWREST
> +			    !local_id(p, idFWD_KWREST) ||
> +#endif
> +			    !local_id(p, idFWD_BLOCK)) {
> +			    compile_error(p, "unexpected ...");
> +			    $$ = Qnone;
> +			}
> +			else {
> +#if 0
> +			    NODE *splat = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@4), &@4);
> +#if idFWD_KWREST
> +			    NODE *kwrest = list_append(p, NEW_LIST(0, &@4), NEW_LVAR(idFWD_KWREST, &@4));
> +#endif
> +			    NODE *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@4), &@4);
> +			    $$ = rest_arg_append(p, $2, splat, &@$);
> +#if idFWD_KWREST
> +			    $$ = arg_append(p, $$, new_hash(p, kwrest, &@4), &@4);
> +#endif
> +			    $$ = arg_blk_pass($$, block);
> +#endif
> +			{VALUE v1,v2,v3,v4,v5;v1=$2;v2=$4;v3=dispatch2(args_add,v1,v2);v4=v3;v5=dispatch1(arg_paren,v4);$$=v5;}
> +			}
> +		    }
>  		| '(' args_forward rparen
>  		    {
>  			if (!local_id(p, idFWD_REST) ||
> @@ -4818,6 +4844,21 @@
>  			SET_LEX_STATE(EXPR_BEG);
>  			p->command_start = TRUE;
>  		    }
> +		| '(' f_arg ',' args_forward rparen
> +		    {
> +			arg_var(p, idFWD_REST);
> +#if idFWD_KWREST
> +			arg_var(p, idFWD_KWREST);
> +#endif
> +			arg_var(p, idFWD_BLOCK);
> +#if 0
> +			$$ = new_args_tail(p, Qnone, idFWD_KWREST, idFWD_BLOCK, &@4);
> +			$$ = new_args(p, $2, Qnone, idFWD_REST, Qnone, $$, &@4);
> +#endif
> +			{VALUE v1,v2;v1=params_new($2, Qnone, $4, Qnone, Qnone, Qnone, Qnone);v2=dispatch1(paren,v1);$$=v2;}
> +			SET_LEX_STATE(EXPR_BEG);
> +			p->command_start = TRUE;
> +		    }
>  		| '(' args_forward rparen
>  		    {
>  			arg_var(p, idFWD_REST);
> @@ -12147,12 +12188,13 @@
>      NODE *node, *succ;
>  
>      if (!len) return ST_CONTINUE;
> -    if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len))
> -        return ST_CONTINUE;
>      if (rb_enc_symname_type(s, len, enc, (1U<<ID_LOCAL)) != ID_LOCAL)
>          return ST_CONTINUE;
>  
>      var = intern_cstr(s, len, enc);
> +    if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
> +        if (!lvar_defined(p, var)) return ST_CONTINUE;
> +    }
>      node = node_assign(p, assignable(p, var, 0, arg->loc), NEW_LIT(ID2SYM(var), arg->loc), arg->loc);
>      succ = arg->succ_block;
>      if (!succ) succ = NEW_BEGIN(0, arg->loc);
> @@ -12673,7 +12715,6 @@
>  RUBY_FUNC_EXPORTED size_t
>  rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr)
>  {
> -    YYUSE(p);
>      if (*yystr == '"') {
>  	size_t yyn = 0, bquote = 0;
>  	const char *yyp = yystr;
> diff -Nru ruby2.7-2.7.2/file.c ruby2.7-2.7.3/file.c
> --- ruby2.7-2.7.2/file.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/file.c	2021-04-05 18:09:38.000000000 +0530
> @@ -1224,7 +1224,7 @@
>          /* birthtime is not supported on the filesystem */
>          statx_notimplement("birthtime");
>      }
> -    return rb_time_nano_new(stx->stx_btime.tv_sec, stx->stx_btime.tv_nsec);
> +    return rb_time_nano_new((time_t)stx->stx_btime.tv_sec, stx->stx_btime.tv_nsec);
>  }
>  
>  typedef struct statx statx_data;
> @@ -3579,21 +3579,42 @@
>  
>  #if defined HAVE_PWD_H
>      if (!dir) {
> -	const char *login = getlogin();
> -	if (login) {
> -	    struct passwd *pw = getpwnam(login);
> -	    if (pw) {
> -		copy_home_path(result, pw->pw_dir);
> -		endpwent();
> -		return result;
> -	    }
> -	    endpwent();
> -	    rb_raise(rb_eArgError, "couldn't find HOME for login `%s' -- expanding `~'",
> -		     login);
> -	}
> -	else {
> -	    rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
> -	}
> +        /* We'll look up the user's default home dir in the password db by
> +         * login name, if possible, and failing that will fall back to looking
> +         * the information up by uid (as would be needed for processes that
> +         * are not a descendant of login(1) or a work-alike).
> +         *
> +         * While the lookup by uid is more likely to succeed (since we always
> +         * have a uid, but may or may not have a login name), we prefer first
> +         * looking up by name to accommodate the possibility of multiple login
> +         * names (each with its own record in the password database, so each
> +         * with a potentially different home directory) being mapped to the
> +         * same uid (as explicitly allowed for by POSIX; see getlogin(3posix)).
> +         */
> +        VALUE login_name = rb_getlogin();
> +
> +# if !defined(HAVE_GETPWUID_R) && !defined(HAVE_GETPWUID)
> +        /* This is a corner case, but for backward compatibility reasons we
> +         * want to emit this error if neither the lookup by login name nor
> +         * lookup by getuid() has a chance of succeeding.
> +         */
> +        if (NIL_P(login_name)) {
> +            rb_raise(rb_eArgError, "couldn't find login name -- expanding `~'");
> +        }
> +# endif
> +
> +        VALUE pw_dir = rb_getpwdirnam_for_login(login_name);
> +        if (NIL_P(pw_dir)) {
> +            pw_dir = rb_getpwdiruid();
> +            if (NIL_P(pw_dir)) {
> +                rb_raise(rb_eArgError, "couldn't find home for uid `%ld'", (long)getuid());
> +            }
> +        }
> +
> +        /* found it */
> +        copy_home_path(result, RSTRING_PTR(pw_dir));
> +        rb_str_resize(pw_dir, 0);
> +        return result;
>      }
>  #endif
>      if (!dir) {
> diff -Nru ruby2.7-2.7.2/gc.c ruby2.7-2.7.3/gc.c
> --- ruby2.7-2.7.2/gc.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/gc.c	2021-04-05 18:09:38.000000000 +0530
> @@ -1153,6 +1153,19 @@
>      return val;
>  }
>  
> +#elif defined(__aarch64__) &&  defined(__GNUC__)
> +typedef unsigned long tick_t;
> +#define PRItick "lu"
> +
> +static __inline__ tick_t
> +tick(void)
> +{
> +    unsigned long val;
> +    __asm__ __volatile__ ("mrs %0, cntvct_el0", : "=r" (val));
> +    return val;
> +}
> +
> +
>  #elif defined(_WIN32) && defined(_MSC_VER)
>  #include <intrin.h>
>  typedef unsigned __int64 tick_t;
> diff -Nru ruby2.7-2.7.2/gc.h ruby2.7-2.7.3/gc.h
> --- ruby2.7-2.7.2/gc.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/gc.h	2021-04-05 18:09:38.000000000 +0530
> @@ -8,6 +8,8 @@
>  #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("movl\t%%esp, %0" : "=r" (*(p)))
>  #elif defined(__powerpc64__) && defined(__GNUC__)
>  #define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mr\t%0, %%r1" : "=r" (*(p)))
> +#elif defined(__aarch64__) && defined(__GNUC__)
> +#define SET_MACHINE_STACK_END(p) __asm__ __volatile__ ("mov\t%0, sp" : "=r" (*(p)))
>  #else
>  NOINLINE(void rb_gc_set_stack_end(VALUE **stack_end_p));
>  #define SET_MACHINE_STACK_END(p) rb_gc_set_stack_end(p)
> diff -Nru ruby2.7-2.7.2/include/ruby/defines.h ruby2.7-2.7.3/include/ruby/defines.h
> --- ruby2.7-2.7.2/include/ruby/defines.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/include/ruby/defines.h	2021-04-05 18:09:38.000000000 +0530
> @@ -486,6 +486,7 @@
>  # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
>       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
>       defined(__powerpc64__) || \
> +     defined(__aarch64__) || \
>       defined(__mc68020__)
>  #   define UNALIGNED_WORD_ACCESS 1
>  # else
> diff -Nru ruby2.7-2.7.2/internal.h ruby2.7-2.7.3/internal.h
> --- ruby2.7-2.7.2/internal.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/internal.h	2021-04-05 18:09:38.000000000 +0530
> @@ -1812,6 +1812,7 @@
>  VALUE rb_int_plus(VALUE x, VALUE y);
>  VALUE rb_float_plus(VALUE x, VALUE y);
>  VALUE rb_int_minus(VALUE x, VALUE y);
> +VALUE rb_float_minus(VALUE x, VALUE y);
>  VALUE rb_int_mul(VALUE x, VALUE y);
>  VALUE rb_float_mul(VALUE x, VALUE y);
>  VALUE rb_float_div(VALUE x, VALUE y);
> @@ -1840,6 +1841,7 @@
>  int rb_int_negative_p(VALUE num);
>  VALUE rb_num_pow(VALUE x, VALUE y);
>  VALUE rb_float_ceil(VALUE num, int ndigits);
> +VALUE rb_float_floor(VALUE x, int ndigits);
>  
>  static inline VALUE
>  rb_num_compare_with_zero(VALUE num, ID mid)
> @@ -2096,13 +2098,16 @@
>  VALUE rb_rational_canonicalize(VALUE x);
>  VALUE rb_rational_uminus(VALUE self);
>  VALUE rb_rational_plus(VALUE self, VALUE other);
> +VALUE rb_rational_minus(VALUE self, VALUE other);
>  VALUE rb_rational_mul(VALUE self, VALUE other);
> +VALUE rb_rational_div(VALUE self, VALUE other);
>  VALUE rb_lcm(VALUE x, VALUE y);
>  VALUE rb_rational_reciprocal(VALUE x);
>  VALUE rb_cstr_to_rat(const char *, int);
>  VALUE rb_rational_abs(VALUE self);
>  VALUE rb_rational_cmp(VALUE self, VALUE other);
>  VALUE rb_rational_pow(VALUE self, VALUE other);
> +VALUE rb_rational_floor(VALUE self, int ndigits);
>  VALUE rb_numeric_quo(VALUE x, VALUE y);
>  VALUE rb_float_numerator(VALUE x);
>  VALUE rb_float_denominator(VALUE x);
> @@ -2431,6 +2436,12 @@
>  VALUE rb_backtrace_to_location_ary(VALUE obj);
>  void rb_backtrace_each(VALUE (*iter)(VALUE recv, VALUE str), VALUE output);
>  
> +#ifdef HAVE_PWD_H
> +VALUE rb_getlogin(void);
> +VALUE rb_getpwdirnam_for_login(VALUE login);  /* read as: "get pwd db home dir by username for login" */
> +VALUE rb_getpwdiruid(void);                   /* read as: "get pwd db home dir for getuid()" */
> +#endif
> +
>  RUBY_SYMBOL_EXPORT_BEGIN
>  const char *rb_objspace_data_type_name(VALUE obj);
>  
> diff -Nru ruby2.7-2.7.2/iseq.c ruby2.7-2.7.3/iseq.c
> --- ruby2.7-2.7.2/iseq.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/iseq.c	2021-04-05 18:09:38.000000000 +0530
> @@ -3094,7 +3094,7 @@
>      encoded_insn_data = st_init_numtable_with_size(VM_INSTRUCTION_SIZE / 2);
>  
>      for (insn = 0; insn < VM_INSTRUCTION_SIZE/2; insn++) {
> -        int traced_insn = insn;
> +        int traced_insn = (int)insn;
>          if (traced_insn == BIN(opt_invokebuiltin_delegate_leave)) {
>              traced_insn = BIN(opt_invokebuiltin_delegate); // to dispatch :return from leave
>          }
> diff -Nru ruby2.7-2.7.2/lib/exe/bundle ruby2.7-2.7.3/lib/exe/bundle
> --- ruby2.7-2.7.2/lib/exe/bundle	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/bundle	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,47 @@
> +#!/usr/bin/env ruby
> +# frozen_string_literal: true
> +
> +# Exit cleanly from an early interrupt
> +Signal.trap("INT") do
> +  Bundler.ui.debug("\n#{caller.join("\n")}") if defined?(Bundler)
> +  exit 1
> +end
> +
> +base_path = File.expand_path("../lib", __dir__)
> +
> +if File.exist?(base_path)
> +  require_relative "../lib/bundler"
> +else
> +  require "bundler"
> +end
> +
> +# Check if an older version of bundler is installed
> +$LOAD_PATH.each do |path|
> +  next unless path =~ %r{/bundler-0\.(\d+)} && $1.to_i < 9
> +  err = String.new
> +  err << "Looks like you have a version of bundler that's older than 0.9.\n"
> +  err << "Please remove your old versions.\n"
> +  err << "An easy way to do this is by running `gem cleanup bundler`."
> +  abort(err)
> +end
> +
> +if File.exist?(base_path)
> +  require_relative "../lib/bundler/friendly_errors"
> +else
> +  require "bundler/friendly_errors"
> +end
> +
> +Bundler.with_friendly_errors do
> +  if File.exist?(base_path)
> +    require_relative "../lib/bundler/cli"
> +  else
> +    require "bundler/cli"
> +  end
> +
> +  # Allow any command to use --help flag to show help for that command
> +  help_flags = %w[--help -h]
> +  help_flag_used = ARGV.any? {|a| help_flags.include? a }
> +  args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
> +
> +  Bundler::CLI.start(args, :debug => true)
> +end
> diff -Nru ruby2.7-2.7.2/lib/exe/bundler ruby2.7-2.7.3/lib/exe/bundler
> --- ruby2.7-2.7.2/lib/exe/bundler	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/bundler	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,4 @@
> +#!/usr/bin/env ruby
> +# frozen_string_literal: true
> +
> +load File.expand_path("../bundle", __FILE__)
> diff -Nru ruby2.7-2.7.2/lib/exe/irb ruby2.7-2.7.3/lib/exe/irb
> --- ruby2.7-2.7.2/lib/exe/irb	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/irb	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,11 @@
> +#!/usr/bin/env ruby
> +#
> +#   irb.rb - interactive ruby
> +#   	$Release Version: 0.9.6 $
> +#   	$Revision$
> +#   	by Keiju ISHITSUKA(keiju@ruby-lang.org)
> +#
> +
> +require "irb"
> +
> +IRB.start(__FILE__)
> diff -Nru ruby2.7-2.7.2/lib/exe/racc ruby2.7-2.7.3/lib/exe/racc
> --- ruby2.7-2.7.2/lib/exe/racc	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/racc	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,306 @@
> +#!/usr/bin/env ruby
> +#
> +# $Id$
> +#
> +# Copyright (c) 1999-2006 Minero Aoki
> +#
> +# This program is free software.
> +# You can distribute/modify this program under the same terms of ruby.
> +# see the file "COPYING".
> +
> +require 'racc/static'
> +require 'optparse'
> +
> +def main
> +  output = nil
> +  debug_parser = false
> +  make_logfile = false
> +  logfilename = nil
> +  make_executable = false
> +  rubypath = nil
> +  embed_runtime = false
> +  debug_flags = Racc::DebugFlags.new
> +  line_convert = true
> +  line_convert_all = false
> +  omit_action_call = true
> +  superclass = nil
> +  check_only = false
> +  verbose = false
> +  profiler = RaccProfiler.new(false)
> +
> +  parser = OptionParser.new
> +  parser.banner = "Usage: #{File.basename($0)} [options] <input>"
> +  parser.on('-o', '--output-file=PATH',
> +            'output file name [<input>.tab.rb]') {|name|
> +    output = name
> +  }
> +  parser.on('-t', '--debug', 'Outputs debugging parser.') {|fl|
> +    debug_parser = fl
> +  }
> +  parser.on('-g', 'Equivalent to -t (obsolete).') {|fl|
> +    $stderr.puts "racc -g is obsolete.  Use racc -t instead." if $VERBOSE
> +    debug_parser = fl
> +  }
> +  parser.on('-v', '--verbose',
> +            'Creates <filename>.output log file.') {|fl|
> +    make_logfile = fl
> +  }
> +  parser.on('-O', '--log-file=PATH',
> +            'Log file name [<input>.output]') {|path|
> +    make_logfile = true
> +    logfilename = path
> +  }
> +  parser.on('-e', '--executable [RUBYPATH]', 'Makes executable parser.') {|path|
> +    executable = true
> +    rubypath = (path == 'ruby' ? nil : path)
> +  }
> +  parser.on('-E', '--embedded', "Embeds Racc runtime in output.") {
> +    embed_runtime = true
> +  }
> +  parser.on('--line-convert-all', 'Converts line numbers of user codes.') {
> +    line_convert_all = true
> +  }
> +  parser.on('-l', '--no-line-convert', 'Never convert line numbers.') {
> +    line_convert = false
> +    line_convert_all = false
> +  }
> +  parser.on('-a', '--no-omit-actions', 'Never omit actions.') {
> +    omit_action_call = false
> +  }
> +  parser.on('--superclass=CLASSNAME',
> +            'Uses CLASSNAME instead of Racc::Parser.') {|name|
> +    superclass = name
> +  }
> +  parser.on('--runtime=FEATURE',
> +            "Uses FEATURE instead of 'racc/parser'") {|feat|
> +    runtime = feature
> +  }
> +  parser.on('-C', '--check-only', 'Checks syntax and quit immediately.') {|fl|
> +    check_only = fl
> +  }
> +  parser.on('-S', '--output-status', 'Outputs internal status time to time.') {
> +    verbose = true
> +  }
> +  parser.on('-P', 'Enables generator profile') {
> +    profiler = RaccProfiler.new(true)
> +  }
> +  parser.on('-D flags', "Flags for Racc debugging (do not use).") {|flags|
> +    debug_flags = Racc::DebugFlags.parse_option_string(flags)
> +  }
> +  #parser.on('--no-extensions', 'Run Racc without any Ruby extension.') {
> +  #  Racc.const_set :Racc_No_Extentions, true
> +  #}
> +  parser.on('--version', 'Prints version and quit.') {
> +    puts "racc version #{Racc::Version}"
> +    exit 0
> +  }
> +  parser.on('--runtime-version', 'Prints runtime version and quit.') {
> +    printf "racc runtime version %s (rev. %s); %s\n",
> +           Racc::Parser::Racc_Runtime_Version,
> +           Racc::Parser::Racc_Runtime_Revision,
> +           if Racc::Parser.racc_runtime_type == 'ruby'
> +             sprintf('ruby core version %s (rev. %s)',
> +                     Racc::Parser::Racc_Runtime_Core_Version_R,
> +                     Racc::Parser::Racc_Runtime_Core_Revision_R)
> +           else
> +             sprintf('c core version %s (rev. %s)',
> +                     Racc::Parser::Racc_Runtime_Core_Version_C,
> +                     Racc::Parser::Racc_Runtime_Core_Revision_C)
> +           end
> +    exit 0
> +  }
> +  parser.on('--copyright', 'Prints copyright and quit.') {
> +    puts Racc::Copyright
> +    exit 0
> +  }
> +  parser.on('--help', 'Prints this message and quit.') {
> +    puts parser.help
> +    exit 1
> +  }
> +  begin
> +    parser.parse!
> +  rescue OptionParser::ParseError => err
> +    $stderr.puts err.message
> +    $stderr.puts parser.help
> +    exit 1
> +  end
> +  if ARGV.empty?
> +    $stderr.puts 'no input'
> +    exit 1
> +  end
> +  if ARGV.size > 1
> +    $stderr.puts 'too many input'
> +    exit 1
> +  end
> +  input = ARGV[0]
> +
> +  begin
> +    $stderr.puts 'Parsing grammar file...' if verbose
> +    result = profiler.section('parse') {
> +      parser = Racc::GrammarFileParser.new(debug_flags)
> +      parser.parse(File.read(input), File.basename(input))
> +    }
> +    if check_only
> +      $stderr.puts 'syntax ok'
> +      exit 0
> +    end
> +
> +    $stderr.puts 'Generating LALR states...' if verbose
> +    states = profiler.section('nfa') {
> +      Racc::States.new(result.grammar).nfa
> +    }
> +
> +    $stderr.puts "Resolving #{states.size} states..." if verbose
> +    profiler.section('dfa') {
> +      states.dfa
> +    }
> +
> +    $stderr.puts 'Creating parser file...' if verbose
> +    params = result.params.dup
> +    # Overwrites parameters given by a grammar file with command line options.
> +    params.superclass = superclass if superclass
> +    params.omit_action_call = true if omit_action_call
> +    # From command line option
> +    if make_executable
> +      params.make_executable = true
> +      params.interpreter = rubypath
> +    end
> +    params.debug_parser = debug_parser
> +    params.convert_line = line_convert
> +    params.convert_line_all = line_convert_all
> +    params.embed_runtime = embed_runtime
> +    profiler.section('generation') {
> +      generator = Racc::ParserFileGenerator.new(states, params)
> +      generator.generate_parser_file(output || make_filename(input, '.tab.rb'))
> +    }
> +
> +    if make_logfile
> +      profiler.section('logging') {
> +        $stderr.puts 'Creating log file...' if verbose
> +        logfilename ||= make_filename(output || File.basename(input), '.output')
> +        File.open(logfilename, 'w') {|f|
> +          Racc::LogFileGenerator.new(states, debug_flags).output f
> +        }
> +      }
> +    end
> +    if debug_flags.status_logging
> +      log_useless states.grammar
> +      log_conflict states
> +    else
> +      report_useless states.grammar
> +      report_conflict states
> +    end
> +
> +    profiler.report
> +  rescue Racc::Error, Errno::ENOENT, Errno::EPERM => err
> +    raise if $DEBUG or debug_flags.any?
> +    lineno = err.message.slice(/\A\d+:/).to_s
> +    $stderr.puts "#{File.basename $0}: #{input}:#{lineno} #{err.message.strip}"
> +    exit 1
> +  end
> +end
> +
> +def make_filename(path, suffix)
> +  path.sub(/(?:\..*?)?\z/, suffix)
> +end
> +
> +def report_conflict(states)
> +  if states.should_report_srconflict?
> +    $stderr.puts "#{states.n_srconflicts} shift/reduce conflicts"
> +  end
> +  if states.rrconflict_exist?
> +    $stderr.puts "#{states.n_rrconflicts} reduce/reduce conflicts"
> +  end
> +end
> +
> +def log_conflict(states)
> +  logging('w') {|f|
> +    f.puts "ex#{states.grammar.n_expected_srconflicts}"
> +    if states.should_report_srconflict?
> +      f.puts "sr#{states.n_srconflicts}"
> +    end
> +    if states.rrconflict_exist?
> +      f.puts "rr#{states.n_rrconflicts}"
> +    end
> +  }
> +end
> +
> +def report_useless(grammar)
> +  if grammar.useless_nonterminal_exist?
> +    $stderr.puts "#{grammar.n_useless_nonterminals} useless nonterminals"
> +  end
> +  if grammar.useless_rule_exist?
> +    $stderr.puts "#{grammar.n_useless_rules} useless rules"
> +  end
> +  if grammar.start.useless?
> +    $stderr.puts 'fatal: start symbol does not derive any sentence'
> +  end
> +end
> +
> +def log_useless(grammar)
> +  logging('a') {|f|
> +    if grammar.useless_nonterminal_exist?
> +      f.puts "un#{grammar.n_useless_nonterminals}"
> +    end
> +    if grammar.useless_rule_exist?
> +      f.puts "ur#{grammar.n_useless_rules}"
> +    end
> +  }
> +end
> +
> +def logging(mode, &block)
> +  File.open("log/#{File.basename(ARGV[0])}", mode, &block)
> +end
> +
> +class RaccProfiler
> +  def initialize(really)
> +    @really = really
> +    @log = []
> +    unless ::Process.respond_to?(:times)
> +      # Ruby 1.6
> +      @class = ::Time
> +    else
> +      @class = ::Process
> +    end
> +  end
> +
> +  def section(name)
> +    if @really
> +      t1 = @class.times.utime
> +      result = yield
> +      t2 = @class.times.utime
> +      @log.push [name, t2 - t1]
> +      result
> +    else
> +      yield
> +    end
> +  end
> +
> +  def report
> +    return unless @really
> +    f = $stderr
> +    total = cumulative_time()
> +    f.puts '--task-----------+--sec------+---%-'
> +    @log.each do |name, time|
> +      f.printf "%-19s %s %3d%%\n", name, pjust(time,4,4), (time/total*100).to_i
> +    end
> +    f.puts '-----------------+-----------+-----'
> +    f.printf "%-20s%s\n", 'total', pjust(total,4,4)
> +  end
> +
> +  private
> +
> +  def cumulative_time
> +    t = @log.inject(0) {|sum, (name, time)| sum + time }
> +    t == 0 ? 0.01 : t
> +  end
> +
> +  def pjust(num, i, j)
> +    m = /(\d+)(\.\d+)?/.match(num.to_s)
> +    str = m[1].rjust(i)
> +    str.concat m[2].ljust(j+1)[0,j+1] if m[2]
> +    str
> +  end
> +end
> +
> +main
> diff -Nru ruby2.7-2.7.2/lib/exe/racc2y ruby2.7-2.7.3/lib/exe/racc2y
> --- ruby2.7-2.7.2/lib/exe/racc2y	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/racc2y	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,195 @@
> +#!/usr/local/bin/ruby
> +#
> +# $Id$
> +#
> +# Copyright (c) 1999-2006 Minero Aoki
> +#
> +# This program is feee software.
> +# You can distribute/modify this program under the terms of
> +# the GNU LGPL, Lesser General Public License version 2.1.
> +# For details of the LGPL, see the file "COPYING".
> +#
> +
> +require 'racc/grammarfileparser'
> +require 'racc/info'
> +require 'optparse'
> +
> +def main
> +  @with_action = true
> +  with_header = false
> +  with_inner = false
> +  with_footer = false
> +  output = nil
> +  parser = OptionParser.new
> +  parser.banner = "Usage: #{File.basename($0)} [-AHIF] [-oFILENAME] GRAMMARFILE"
> +  parser.on('-o', '--output=FILENAME', 'output file name [<input>.yacc]') {|name|
> +    output = name
> +  }
> +  parser.on('-A', '--without-action', 'Does not include actions.') {
> +    @with_action = false
> +  }
> +  parser.on('-H', '--with-header', 'Includes header part.') {
> +    with_header = true
> +  }
> +  parser.on('-I', '--with-inner', 'Includes inner part.') {
> +    with_inner = true
> +  }
> +  parser.on('-F', '--with-footer', 'Includes footer part.') {
> +    with_footer = true
> +  }
> +  parser.on('--version', 'Prints version and quit.') {
> +    puts "racc2y version #{Racc::Version}"
> +    exit 0
> +  }
> +  parser.on('--copyright', 'Prints copyright and quit.') {
> +    puts Racc::Copyright
> +    exit 0
> +  }
> +  parser.on('--help', 'Prints this message and quit.') {
> +    puts parser.help
> +    exit 1
> +  }
> +  begin
> +    parser.parse!
> +  rescue OptionParser::ParseError => err
> +    $stderr.puts err.message
> +    $stderr.puts parser.help
> +    exit 1
> +  end
> +  if ARGV.empty?
> +    $stderr.puts "no input file"
> +    exit 1
> +  end
> +  unless ARGV.size == 1
> +    $stderr.puts "too many inputs"
> +    exit 1
> +  end
> +  input = ARGV[0]
> +
> +  begin
> +    result = Racc::GrammarFileParser.parse_file(input)
> +    result.grammar.init
> +    File.open(output || "#{input}.yacc", 'w') {|f|
> +      f.puts "/* generated from #{input} */"
> +      if with_header
> +        f.puts
> +        f.puts '%{'
> +        print_user_codes f, result.params.header
> +        f.puts '%}'
> +      end
> +      f.puts
> +      print_terminals f, result.grammar
> +      f.puts
> +      print_precedence_table f, precedence_table(result.grammar)
> +      f.puts
> +      f.puts '%%'
> +      print_grammar f, result.grammar
> +      f.puts '%%'
> +      if with_inner
> +        f.puts '/*---- inner ----*/'
> +        print_user_codes f, result.params.inner
> +      end
> +      if with_footer
> +        f.puts '/*---- footer ----*/'
> +        print_user_codes f, result.params.footer
> +      end
> +    }
> +  rescue SystemCallError => err
> +    $stderr.puts err.message
> +    exit 1
> +  end
> +end
> +
> +def print_terminals(f, grammar)
> +  init_indent = '%token'.size
> +  f.print '%token'
> +  columns = init_indent
> +  grammar.symboltable.each_terminal do |t|
> +    next unless t.terminal?
> +    next if t.dummy?
> +    next if t == grammar.symboltable.anchor
> +    next if t == grammar.symboltable.error
> +    unless t.value.kind_of?(String)
> +      if columns > 60
> +        f.puts
> +        f.print ' ' * init_indent
> +        columns = init_indent
> +      end
> +      columns += f.write(" #{yacc_symbol(t)}")
> +    end
> +  end
> +  f.puts
> +end
> +
> +def precedence_table(grammar)
> +  table = []
> +  grammar.symboltable.select {|sym| sym.precedence }.each do |sym|
> +    (table[sym.prec] ||= [sym.assoc]).push sym
> +  end
> +  table.compact
> +end
> +
> +def print_precedence_table(f, table)
> +  return if table.empty?
> +  f.puts '/* precedance table */'
> +  table.each do |syms|
> +    assoc = syms.shift
> +    f.printf '%%%-8s ', assoc.to_s.downcase
> +    f.puts syms.map {|s| yacc_symbol(s) }.join(' ')
> +  end
> +  f.puts
> +end
> +
> +def print_grammar(f, grammar)
> +  prev_target = nil
> +  indent = 10
> +  embactions = []
> +  grammar.each do |rule|
> +    if rule.target.dummy?
> +      embactions.push rule.action  unless rule.action.empty?
> +      next
> +    end
> +    if rule.target == prev_target
> +      f.print ' ' * indent, '|'
> +    else
> +      prev_target = rule.target
> +      f.printf "\n%-10s:", yacc_symbol(prev_target)
> +    end
> +    rule.symbols.each do |s|
> +      if s.dummy?   # target of dummy rule for embedded action
> +        f.puts
> +        print_action f, embactions.shift, indent
> +        f.print ' ' * (indent + 1)
> +      else
> +        f.print ' ', yacc_symbol(s)
> +      end
> +    end
> +    if rule.specified_prec
> +      f.print ' %prec ', yacc_symbol(rule.specified_prec)
> +    end
> +    f.puts
> +    unless rule.action.empty?
> +      print_action f, rule.action, indent
> +    end
> +  end
> +end
> +
> +def print_action(f, action, indent)
> +  return unless @with_action
> +  f.print ' ' * (indent + 4), "{\n"
> +  f.print ' ' * (indent + 6), action.source.text.strip, "\n"
> +  f.print ' ' * (indent + 4) , "}\n"
> +end
> +
> +def print_user_codes(f, srcs)
> +  return if srcs.empty?
> +  srcs.each do |src|
> +    f.puts src.text
> +  end
> +end
> +
> +def yacc_symbol(s)
> +  s.to_s.gsub('"', "'")
> +end
> +
> +main
> diff -Nru ruby2.7-2.7.2/lib/exe/rdoc ruby2.7-2.7.3/lib/exe/rdoc
> --- ruby2.7-2.7.2/lib/exe/rdoc	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/rdoc	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,44 @@
> +#!/usr/bin/env ruby
> +#
> +#  RDoc: Documentation tool for source code
> +#        (see lib/rdoc/rdoc.rb for more information)
> +#
> +#  Copyright (c) 2003 Dave Thomas
> +#  Released under the same terms as Ruby
> +
> +begin
> +  gem 'rdoc'
> +rescue NameError => e # --disable-gems
> +  raise unless e.name == :gem
> +rescue Gem::LoadError
> +end
> +
> +require 'rdoc/rdoc'
> +
> +begin
> +  r = RDoc::RDoc.new
> +  r.document ARGV
> +rescue Errno::ENOSPC
> +  $stderr.puts 'Ran out of space creating documentation'
> +  $stderr.puts
> +  $stderr.puts 'Please free up some space and try again'
> +rescue SystemExit
> +  raise
> +rescue Exception => e
> +  if $DEBUG_RDOC then
> +    $stderr.puts e.message
> +    $stderr.puts "#{e.backtrace.join "\n\t"}"
> +    $stderr.puts
> +  elsif Interrupt === e then
> +    $stderr.puts
> +    $stderr.puts 'Interrupted'
> +  else
> +    $stderr.puts "uh-oh! RDoc had a problem:"
> +    $stderr.puts e.message
> +    $stderr.puts
> +    $stderr.puts "run with --debug for full backtrace"
> +  end
> +
> +  exit 1
> +end
> +
> diff -Nru ruby2.7-2.7.2/lib/exe/ri ruby2.7-2.7.3/lib/exe/ri
> --- ruby2.7-2.7.2/lib/exe/ri	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/ri	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,12 @@
> +#!/usr/bin/env ruby
> +
> +begin
> +  gem 'rdoc'
> +rescue NameError => e # --disable-gems
> +  raise unless e.name == :gem
> +rescue Gem::LoadError
> +end
> +
> +require 'rdoc/ri/driver'
> +
> +RDoc::RI::Driver.run ARGV
> diff -Nru ruby2.7-2.7.2/lib/exe/y2racc ruby2.7-2.7.3/lib/exe/y2racc
> --- ruby2.7-2.7.2/lib/exe/y2racc	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/exe/y2racc	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,339 @@
> +#!/usr/local/bin/ruby
> +#
> +# $Id$
> +#
> +# Copyright (c) 1999-2006 Minero Aoki
> +#
> +# This program is free software.
> +# You can distribute/modify this program under the terms of
> +# the GNU LGPL, Lesser General Public License version 2.1.
> +# For details of the GNU LGPL, see the file "COPYING".
> +#
> +
> +require 'racc/info'
> +require 'strscan'
> +require 'forwardable'
> +require 'optparse'
> +
> +def main
> +  @with_action = true
> +  @with_header = false
> +  @with_usercode = false
> +  cname = 'MyParser'
> +  input = nil
> +  output = nil
> +  parser = OptionParser.new
> +  parser.banner = "Usage: #{File.basename($0)} [-Ahu] [-c <classname>] [-o <filename>] <input>"
> +  parser.on('-o', '--output=FILENAME', 'output file name [<input>.racc]') {|name|
> +    output = name
> +  }
> +  parser.on('-c', '--classname=NAME', "Name of the parser class. [#{cname}]") {|name|
> +    cname = name
> +  }
> +  parser.on('-A', '--without-action', 'Does not include actions.') {
> +    @with_action = false
> +  }
> +  parser.on('-h', '--with-header', 'Includes header (%{...%}).') {
> +    @with_header = true
> +  }
> +  parser.on('-u', '--with-user-code', 'Includes user code.') {
> +    @with_usercode = true
> +  }
> +  parser.on('--version', 'Prints version and quit.') {
> +    puts "y2racc version #{Racc::Version}"
> +    exit 0
> +  }
> +  parser.on('--copyright', 'Prints copyright and quit.') {
> +    puts Racc::Copyright
> +    exit 0
> +  }
> +  parser.on('--help', 'Prints this message and quit.') {
> +    puts parser.help
> +    exit 1
> +  }
> +  begin
> +    parser.parse!
> +  rescue OptionParser::ParseError => err
> +    $stderr.puts err.message
> +    $stderr.puts parser.help
> +    exit 1
> +  end
> +  if ARGV.empty?
> +    $stderr.puts 'no input'
> +    exit 1
> +  end
> +  if ARGV.size > 1
> +    $stderr.puts 'too many input'
> +    exit 1
> +  end
> +  input = ARGV[0]
> +
> +  begin
> +    result = YaccFileParser.parse_file(input)
> +    File.open(output || "#{input}.racc", 'w') {|f|
> +      convert cname, result, f
> +    }
> +  rescue SystemCallError => err
> +    $stderr.puts err.message
> +    exit 1
> +  end
> +end
> +
> +def convert(classname, result, f)
> +  init_indent = 'token'.size
> +  f.puts %<# Converted from "#{result.filename}" by y2racc version #{Racc::Version}>
> +  f.puts
> +  f.puts "class #{classname}"
> +  unless result.terminals.empty?
> +    f.puts
> +    f.print 'token'
> +    columns = init_indent
> +    result.terminals.each do |t|
> +      if columns > 60
> +        f.puts
> +        f.print ' ' * init_indent
> +        columns = init_indent
> +      end
> +      columns += f.write(" #{t}")
> +    end
> +    f.puts
> +  end
> +  unless result.precedence_table.empty?
> +    f.puts
> +    f.puts 'preclow'
> +    result.precedence_table.each do |assoc, toks|
> +      f.printf "  %-8s %s\n", assoc, toks.join(' ')  unless toks.empty?
> +    end
> +    f.puts 'prechigh'
> +  end
> +  if result.start
> +    f.puts
> +    f.puts "start #{@start}"
> +  end
> +
> +  f.puts
> +  f.puts 'rule'
> +  texts = @with_action ? result.grammar : result.grammar_without_actions
> +  texts.each do |text|
> +    f.print text
> +  end
> +
> +  if @with_header and result.header
> +    f.puts
> +    f.puts '---- header'
> +    f.puts result.header
> +  end
> +  if @with_usercode and result.usercode
> +    f.puts
> +    f.puts '---- footer'
> +    f.puts result.usercode
> +  end
> +end
> +
> +class ParseError < StandardError; end
> +
> +class StringScanner_withlineno
> +  def initialize(src)
> +    @s = StringScanner.new(src)
> +    @lineno = 1
> +  end
> +
> +  extend Forwardable
> +  def_delegator "@s", :eos?
> +  def_delegator "@s", :rest
> +
> +  attr_reader :lineno
> +
> +  def scan(re)
> +    advance_lineno(@s.scan(re))
> +  end
> +
> +  def scan_until(re)
> +    advance_lineno(@s.scan_until(re))
> +  end
> +
> +  def skip(re)
> +    str = advance_lineno(@s.scan(re))
> +    str ? str.size : nil
> +  end
> +
> +  def getch
> +    advance_lineno(@s.getch)
> +  end
> +
> +  private
> +
> +  def advance_lineno(str)
> +    @lineno += str.count("\n") if str
> +    str
> +  end
> +end
> +
> +class YaccFileParser
> +
> +  Result = Struct.new(:terminals, :precedence_table, :start,
> +                      :header, :grammar, :usercode, :filename)
> +  class Result   # reopen
> +    def initialize
> +      super
> +      self.terminals = []
> +      self.precedence_table = []
> +      self.start = nil
> +      self.grammar = []
> +      self.header = nil
> +      self.usercode = nil
> +      self.filename = nil
> +    end
> +
> +    def grammar_without_actions
> +      grammar().map {|text| text[0,1] == '{' ? '{}' : text }
> +    end
> +  end
> +
> +  def YaccFileParser.parse_file(filename)
> +    new().parse(File.read(filename), filename)
> +  end
> +
> +  def parse(src, filename = '-')
> +    @result = Result.new
> +    @filename = filename
> +    @result.filename = filename
> +    s = StringScanner_withlineno.new(src)
> +    parse_header s
> +    parse_grammar s
> +    @result
> +  end
> +
> +  private
> +
> +  COMMENT = %r</\*[^*]*\*+(?:[^/*][^*]*\*+)*/>
> +  CHAR = /'((?:[^'\\]+|\\.)*)'/
> +  STRING = /"((?:[^"\\]+|\\.)*)"/
> +
> +  def parse_header(s)
> +    skip_until_percent s
> +    until s.eos?
> +      case
> +      when t = s.scan(/left/)
> +        @result.precedence_table.push ['left', scan_symbols(s)]
> +      when t = s.scan(/right/)
> +        @result.precedence_table.push ['right', scan_symbols(s)]
> +      when t = s.scan(/nonassoc/)
> +        @result.precedence_table.push ['nonassoc', scan_symbols(s)]
> +      when t = s.scan(/token/)
> +        list = scan_symbols(s)
> +        list.shift if /\A<(.*)>\z/ =~ list[0]
> +        @result.terminals.concat list
> +      when t = s.scan(/start/)
> +        @result.start = scan_symbols(s)[0]
> +      when s.skip(%r<(?:
> +            type | union | expect | thong | binary |
> +            semantic_parser | pure_parser | no_lines |
> +            raw | token_table
> +            )\b>x)
> +        skip_until_percent s
> +      when s.skip(/\{/)   # header (%{...%})
> +        str = s.scan_until(/\%\}/)
> +        str.chop!
> +        str.chop!
> +        @result.header = str
> +        skip_until_percent s
> +      when s.skip(/\%/)   # grammar (%%...)
> +        return
> +      else
> +        raise ParseError, "#{@filename}:#{s.lineno}: scan error"
> +      end
> +    end
> +  end
> +
> +  def skip_until_percent(s)
> +    until s.eos?
> +      s.skip /[^\%\/]+/
> +      next if s.skip(COMMENT)
> +      return if s.getch == '%'
> +    end
> +  end
> +
> +  def scan_symbols(s)
> +    list = []
> +    until s.eos?
> +      s.skip /\s+/
> +      if s.skip(COMMENT)
> +        ;
> +      elsif t = s.scan(CHAR)
> +        list.push t
> +      elsif t = s.scan(STRING)
> +        list.push t
> +      elsif s.skip(/\%/)
> +        break
> +      elsif t = s.scan(/\S+/)
> +        list.push t
> +      else
> +        raise ParseError, "#{@filename}:#{@lineno}: scan error"
> +      end
> +    end
> +    list
> +  end
> +
> +  def parse_grammar(s)
> +    buf = []
> +    until s.eos?
> +      if t = s.scan(/[^%'"{\/]+/)
> +        buf.push t
> +        break if s.eos?
> +      end
> +      if s.skip(/\{/)
> +        buf.push scan_action(s)
> +      elsif t = s.scan(/'(?:[^'\\]+|\\.)*'/) then buf.push t
> +      elsif t = s.scan(/"(?:[^"\\]+|\\.)*"/) then buf.push t
> +      elsif t = s.scan(COMMENT) then buf.push t
> +      elsif s.skip(/%prec\b/)   then buf.push '='
> +      elsif s.skip(/%%/)
> +        @result.usercode = s.rest
> +        break
> +      else
> +        buf.push s.getch
> +      end
> +    end
> +    @result.grammar = buf
> +  end
> +
> +  def scan_action(s)
> +    buf = '{'
> +    nest = 1
> +    until s.eos?
> +      if t = s.scan(%r<[^/{}'"]+>)
> +        buf << t
> +        break if s.eos?
> +      elsif t = s.scan(COMMENT)
> +        buf << t
> +      elsif t = s.scan(CHAR)
> +        buf << t
> +      elsif t = s.scan(STRING)
> +        buf << t
> +      else
> +        c = s.getch
> +        buf << c
> +        case c
> +        when '{'
> +          nest += 1
> +        when '}'
> +          nest -= 1
> +          return buf if nest == 0
> +        end
> +      end
> +    end
> +    $stderr.puts "warning: unterminated action in #{@filename}"
> +    buf
> +  end
> +
> +end
> +
> +unless Object.method_defined?(:funcall)
> +  class Object
> +    alias funcall __send__
> +  end
> +end
> +
> +
> +main
> diff -Nru ruby2.7-2.7.2/lib/resolv.rb ruby2.7-2.7.3/lib/resolv.rb
> --- ruby2.7-2.7.2/lib/resolv.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/resolv.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -706,7 +706,7 @@
>        end
>  
>        def sender_for(addr, msg)
> -        @senders[[addr,msg.id]]
> +        @senders.delete([addr,msg.id])
>        end
>  
>        def close
> diff -Nru ruby2.7-2.7.2/lib/rexml/doctype.rb ruby2.7-2.7.3/lib/rexml/doctype.rb
> --- ruby2.7-2.7.2/lib/rexml/doctype.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rexml/doctype.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -7,6 +7,44 @@
>  require_relative 'xmltokens'
>  
>  module REXML
> +  class ReferenceWriter
> +    def initialize(id_type,
> +                   public_id_literal,
> +                   system_literal,
> +                   context=nil)
> +      @id_type = id_type
> +      @public_id_literal = public_id_literal
> +      @system_literal = system_literal
> +      if context and context[:prologue_quote] == :apostrophe
> +        @default_quote = "'"
> +      else
> +        @default_quote = "\""
> +      end
> +    end
> +
> +    def write(output)
> +      output << " #{@id_type}"
> +      if @public_id_literal
> +        if @public_id_literal.include?("'")
> +          quote = "\""
> +        else
> +          quote = @default_quote
> +        end
> +        output << " #{quote}#{@public_id_literal}#{quote}"
> +      end
> +      if @system_literal
> +        if @system_literal.include?("'")
> +          quote = "\""
> +        elsif @system_literal.include?("\"")
> +          quote = "'"
> +        else
> +          quote = @default_quote
> +        end
> +        output << " #{quote}#{@system_literal}#{quote}"
> +      end
> +    end
> +  end
> +
>    # Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
>    # ... >.  DOCTYPES can be used to declare the DTD of a document, as well as
>    # being used to declare entities used in the document.
> @@ -50,6 +88,8 @@
>          super( parent )
>          @name = first.name
>          @external_id = first.external_id
> +        @long_name = first.instance_variable_get(:@long_name)
> +        @uri = first.instance_variable_get(:@uri)
>        elsif first.kind_of? Array
>          super( parent )
>          @name = first[0]
> @@ -108,19 +148,17 @@
>      #   Ignored
>      def write( output, indent=0, transitive=false, ie_hack=false )
>        f = REXML::Formatters::Default.new
> -      c = context
> -      if c and c[:prologue_quote] == :apostrophe
> -        quote = "'"
> -      else
> -        quote = "\""
> -      end
>        indent( output, indent )
>        output << START
>        output << ' '
>        output << @name
> -      output << " #{@external_id}" if @external_id
> -      output << " #{quote}#{@long_name}#{quote}" if @long_name
> -      output << " #{quote}#{@uri}#{quote}" if @uri
> +      if @external_id
> +        reference_writer = ReferenceWriter.new(@external_id,
> +                                               @long_name,
> +                                               @uri,
> +                                               context)
> +        reference_writer.write(output)
> +      end
>        unless @children.empty?
>          output << ' ['
>          @children.each { |child|
> @@ -259,16 +297,11 @@
>      end
>  
>      def to_s
> -      c = nil
> -      c = parent.context if parent
> -      if c and c[:prologue_quote] == :apostrophe
> -        quote = "'"
> -      else
> -        quote = "\""
> -      end
> -      notation = "<!NOTATION #{@name} #{@middle}"
> -      notation << " #{quote}#{@public}#{quote}" if @public
> -      notation << " #{quote}#{@system}#{quote}" if @system
> +      context = nil
> +      context = parent.context if parent
> +      notation = "<!NOTATION #{@name}"
> +      reference_writer = ReferenceWriter.new(@middle, @public, @system, context)
> +      reference_writer.write(notation)
>        notation << ">"
>        notation
>      end
> diff -Nru ruby2.7-2.7.2/lib/rexml/parsers/baseparser.rb ruby2.7-2.7.3/lib/rexml/parsers/baseparser.rb
> --- ruby2.7-2.7.2/lib/rexml/parsers/baseparser.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rexml/parsers/baseparser.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -50,7 +50,6 @@
>  
>        DOCTYPE_START = /\A\s*<!DOCTYPE\s/um
>        DOCTYPE_END = /\A\s*\]\s*>/um
> -      DOCTYPE_PATTERN = /\s*<!DOCTYPE\s+(.*?)(\[|>)/um
>        ATTRIBUTE_PATTERN = /\s*(#{QNAME_STR})\s*=\s*(["'])(.*?)\4/um
>        COMMENT_START = /\A<!--/u
>        COMMENT_PATTERN = /<!--(.*?)-->/um
> @@ -61,15 +60,14 @@
>        XMLDECL_PATTERN = /<\?xml\s+(.*?)\?>/um
>        INSTRUCTION_START = /\A<\?/u
>        INSTRUCTION_PATTERN = /<\?#{NAME}(\s+.*?)?\?>/um
> -      TAG_MATCH = /^<((?>#{QNAME_STR}))/um
> -      CLOSE_MATCH = /^\s*<\/(#{QNAME_STR})\s*>/um
> +      TAG_MATCH = /\A<((?>#{QNAME_STR}))/um
> +      CLOSE_MATCH = /\A\s*<\/(#{QNAME_STR})\s*>/um
>  
>        VERSION = /\bversion\s*=\s*["'](.*?)['"]/um
>        ENCODING = /\bencoding\s*=\s*["'](.*?)['"]/um
>        STANDALONE = /\bstandalone\s*=\s*["'](.*?)['"]/um
>  
>        ENTITY_START = /\A\s*<!ENTITY/
> -      IDENTITY = /^([!\*\w\-]+)(\s+#{NCNAME_STR})?(\s+["'](.*?)['"])?(\s+['"](.*?)["'])?/u
>        ELEMENTDECL_START = /\A\s*<!ELEMENT/um
>        ELEMENTDECL_PATTERN = /\A\s*(<!ELEMENT.*?)>/um
>        SYSTEMENTITY = /\A\s*(%.*?;)\s*$/um
> @@ -83,9 +81,6 @@
>        ATTDEF_RE = /#{ATTDEF}/
>        ATTLISTDECL_START = /\A\s*<!ATTLIST/um
>        ATTLISTDECL_PATTERN = /\A\s*<!ATTLIST\s+#{NAME}(?:#{ATTDEF})*\s*>/um
> -      NOTATIONDECL_START = /\A\s*<!NOTATION/um
> -      PUBLIC = /\A\s*<!NOTATION\s+(\w[\-\w]*)\s+(PUBLIC)\s+(["'])(.*?)\3(?:\s+(["'])(.*?)\5)?\s*>/um
> -      SYSTEM = /\A\s*<!NOTATION\s+(\w[\-\w]*)\s+(SYSTEM)\s+(["'])(.*?)\3\s*>/um
>  
>        TEXT_PATTERN = /\A([^<]*)/um
>  
> @@ -103,6 +98,11 @@
>        GEDECL = "<!ENTITY\\s+#{NAME}\\s+#{ENTITYDEF}\\s*>"
>        ENTITYDECL = /\s*(?:#{GEDECL})|(?:#{PEDECL})/um
>  
> +      NOTATIONDECL_START = /\A\s*<!NOTATION/um
> +      EXTERNAL_ID_PUBLIC = /\A\s*PUBLIC\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}\s*/um
> +      EXTERNAL_ID_SYSTEM = /\A\s*SYSTEM\s+#{SYSTEMLITERAL}\s*/um
> +      PUBLIC_ID = /\A\s*PUBLIC\s+#{PUBIDLITERAL}\s*/um
> +
>        EREFERENCE = /&(?!#{NAME};)/
>  
>        DEFAULT_ENTITIES = {
> @@ -195,11 +195,9 @@
>          return [ :end_document ] if empty?
>          return @stack.shift if @stack.size > 0
>          #STDERR.puts @source.encoding
> -        @source.read if @source.buffer.size<2
>          #STDERR.puts "BUFFER = #{@source.buffer.inspect}"
>          if @document_status == nil
> -          #@source.consume( /^\s*/um )
> -          word = @source.match( /^((?:\s+)|(?:<[^>]*>))/um )
> +          word = @source.match( /\A((?:\s+)|(?:<[^>]*>))/um )
>            word = word[1] unless word.nil?
>            #STDERR.puts "WORD = #{word.inspect}"
>            case word
> @@ -224,38 +222,49 @@
>            when INSTRUCTION_START
>              return process_instruction
>            when DOCTYPE_START
> -            md = @source.match( DOCTYPE_PATTERN, true )
> +            base_error_message = "Malformed DOCTYPE"
> +            @source.match(DOCTYPE_START, true)
>              @nsstack.unshift(curr_ns=Set.new)
> -            identity = md[1]
> -            close = md[2]
> -            identity =~ IDENTITY
> -            name = $1
> -            raise REXML::ParseException.new("DOCTYPE is missing a name") if name.nil?
> -            pub_sys = $2.nil? ? nil : $2.strip
> -            long_name = $4.nil? ? nil : $4.strip
> -            uri = $6.nil? ? nil : $6.strip
> -            args = [ :start_doctype, name, pub_sys, long_name, uri ]
> -            if close == ">"
> +            name = parse_name(base_error_message)
> +            if @source.match(/\A\s*\[/um, true)
> +              id = [nil, nil, nil]
> +              @document_status = :in_doctype
> +            elsif @source.match(/\A\s*>/um, true)
> +              id = [nil, nil, nil]
>                @document_status = :after_doctype
> -              @source.read if @source.buffer.size<2
> -              md = @source.match(/^\s*/um, true)
> -              @stack << [ :end_doctype ]
>              else
> -              @document_status = :in_doctype
> +              id = parse_id(base_error_message,
> +                            accept_external_id: true,
> +                            accept_public_id: false)
> +              if id[0] == "SYSTEM"
> +                # For backward compatibility
> +                id[1], id[2] = id[2], nil
> +              end
> +              if @source.match(/\A\s*\[/um, true)
> +                @document_status = :in_doctype
> +              elsif @source.match(/\A\s*>/um, true)
> +                @document_status = :after_doctype
> +              else
> +                message = "#{base_error_message}: garbage after external ID"
> +                raise REXML::ParseException.new(message, @source)
> +              end
> +            end
> +            args = [:start_doctype, name, *id]
> +            if @document_status == :after_doctype
> +              @source.match(/\A\s*/um, true)
> +              @stack << [ :end_doctype ]
>              end
>              return args
> -          when /^\s+/
> +          when /\A\s+/
>            else
>              @document_status = :after_doctype
> -            @source.read if @source.buffer.size<2
> -            md = @source.match(/\s*/um, true)
>              if @source.encoding == "UTF-8"
>                @source.buffer.force_encoding(::Encoding::UTF_8)
>              end
>            end
>          end
>          if @document_status == :in_doctype
> -          md = @source.match(/\s*(.*?>)/um)
> +          md = @source.match(/\A\s*(.*?>)/um)
>            case md[1]
>            when SYSTEMENTITY
>              match = @source.match( SYSTEMENTITY, true )[1]
> @@ -312,24 +321,35 @@
>              end
>              return [ :attlistdecl, element, pairs, contents ]
>            when NOTATIONDECL_START
> -            md = nil
> -            if @source.match( PUBLIC )
> -              md = @source.match( PUBLIC, true )
> -              vals = [md[1],md[2],md[4],md[6]]
> -            elsif @source.match( SYSTEM )
> -              md = @source.match( SYSTEM, true )
> -              vals = [md[1],md[2],nil,md[4]]
> -            else
> -              raise REXML::ParseException.new( "error parsing notation: no matching pattern", @source )
> +            base_error_message = "Malformed notation declaration"
> +            unless @source.match(/\A\s*<!NOTATION\s+/um, true)
> +              if @source.match(/\A\s*<!NOTATION\s*>/um)
> +                message = "#{base_error_message}: name is missing"
> +              else
> +                message = "#{base_error_message}: invalid declaration name"
> +              end
> +              raise REXML::ParseException.new(message, @source)
>              end
> -            return [ :notationdecl, *vals ]
> +            name = parse_name(base_error_message)
> +            id = parse_id(base_error_message,
> +                          accept_external_id: true,
> +                          accept_public_id: true)
> +            unless @source.match(/\A\s*>/um, true)
> +              message = "#{base_error_message}: garbage before end >"
> +              raise REXML::ParseException.new(message, @source)
> +            end
> +            return [:notationdecl, name, *id]
>            when DOCTYPE_END
>              @document_status = :after_doctype
>              @source.match( DOCTYPE_END, true )
>              return [ :end_doctype ]
>            end
>          end
> +        if @document_status == :after_doctype
> +          @source.match(/\A\s*/um, true)
> +        end
>          begin
> +          @source.read if @source.buffer.size<2
>            if @source.buffer[0] == ?<
>              if @source.buffer[1] == ?/
>                @nsstack.shift
> @@ -372,6 +392,7 @@
>                unless md
>                  raise REXML::ParseException.new("malformed XML: missing tag start", @source)
>                end
> +              @document_status = :in_element
>                prefixes = Set.new
>                prefixes << md[2] if md[2]
>                @nsstack.unshift(curr_ns=Set.new)
> @@ -477,6 +498,85 @@
>          true
>        end
>  
> +      def parse_name(base_error_message)
> +        md = @source.match(/\A\s*#{NAME}/um, true)
> +        unless md
> +          if @source.match(/\A\s*\S/um)
> +            message = "#{base_error_message}: invalid name"
> +          else
> +            message = "#{base_error_message}: name is missing"
> +          end
> +          raise REXML::ParseException.new(message, @source)
> +        end
> +        md[1]
> +      end
> +
> +      def parse_id(base_error_message,
> +                   accept_external_id:,
> +                   accept_public_id:)
> +        if accept_external_id and (md = @source.match(EXTERNAL_ID_PUBLIC, true))
> +          pubid = system = nil
> +          pubid_literal = md[1]
> +          pubid = pubid_literal[1..-2] if pubid_literal # Remove quote
> +          system_literal = md[2]
> +          system = system_literal[1..-2] if system_literal # Remove quote
> +          ["PUBLIC", pubid, system]
> +        elsif accept_public_id and (md = @source.match(PUBLIC_ID, true))
> +          pubid = system = nil
> +          pubid_literal = md[1]
> +          pubid = pubid_literal[1..-2] if pubid_literal # Remove quote
> +          ["PUBLIC", pubid, nil]
> +        elsif accept_external_id and (md = @source.match(EXTERNAL_ID_SYSTEM, true))
> +          system = nil
> +          system_literal = md[1]
> +          system = system_literal[1..-2] if system_literal # Remove quote
> +          ["SYSTEM", nil, system]
> +        else
> +          details = parse_id_invalid_details(accept_external_id: accept_external_id,
> +                                             accept_public_id: accept_public_id)
> +          message = "#{base_error_message}: #{details}"
> +          raise REXML::ParseException.new(message, @source)
> +        end
> +      end
> +
> +      def parse_id_invalid_details(accept_external_id:,
> +                                   accept_public_id:)
> +        public = /\A\s*PUBLIC/um
> +        system = /\A\s*SYSTEM/um
> +        if (accept_external_id or accept_public_id) and @source.match(/#{public}/um)
> +          if @source.match(/#{public}(?:\s+[^'"]|\s*[\[>])/um)
> +            return "public ID literal is missing"
> +          end
> +          unless @source.match(/#{public}\s+#{PUBIDLITERAL}/um)
> +            return "invalid public ID literal"
> +          end
> +          if accept_public_id
> +            if @source.match(/#{public}\s+#{PUBIDLITERAL}\s+[^'"]/um)
> +              return "system ID literal is missing"
> +            end
> +            unless @source.match(/#{public}\s+#{PUBIDLITERAL}\s+#{SYSTEMLITERAL}/um)
> +              return "invalid system literal"
> +            end
> +            "garbage after system literal"
> +          else
> +            "garbage after public ID literal"
> +          end
> +        elsif accept_external_id and @source.match(/#{system}/um)
> +          if @source.match(/#{system}(?:\s+[^'"]|\s*[\[>])/um)
> +            return "system literal is missing"
> +          end
> +          unless @source.match(/#{system}\s+#{SYSTEMLITERAL}/um)
> +            return "invalid system literal"
> +          end
> +          "garbage after system literal"
> +        else
> +          unless @source.match(/\A\s*(?:PUBLIC|SYSTEM)\s/um)
> +            return "invalid ID type"
> +          end
> +          "ID type is missing"
> +        end
> +      end
> +
>        def process_instruction
>          match_data = @source.match(INSTRUCTION_PATTERN, true)
>          unless match_data
> diff -Nru ruby2.7-2.7.2/lib/rexml/rexml.rb ruby2.7-2.7.3/lib/rexml/rexml.rb
> --- ruby2.7-2.7.2/lib/rexml/rexml.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rexml/rexml.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -24,7 +24,7 @@
>  module REXML
>    COPYRIGHT = "Copyright © 2001-2008 Sean Russell <ser@germane-software.com>"
>    DATE = "2008/019"
> -  VERSION = "3.2.3"
> +  VERSION = "3.2.3.1"
>    REVISION = ""
>  
>    Copyright = COPYRIGHT
> diff -Nru ruby2.7-2.7.2/lib/rubygems/core_ext/kernel_require.rb ruby2.7-2.7.3/lib/rubygems/core_ext/kernel_require.rb
> --- ruby2.7-2.7.2/lib/rubygems/core_ext/kernel_require.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rubygems/core_ext/kernel_require.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -39,49 +39,40 @@
>  
>      path = path.to_path if path.respond_to? :to_path
>  
> -    # Ensure -I beats a default gem
> -    # https://github.com/rubygems/rubygems/pull/1868
> -    resolved_path = begin
> -      rp = nil
> -      $LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp|
> -        safe_lp = lp.dup.tap(&Gem::UNTAINT)
> -        begin
> -          if File.symlink? safe_lp # for backward compatibility
> -            next
> -          end
> -        rescue SecurityError
> -          RUBYGEMS_ACTIVATION_MONITOR.exit
> -          raise
> -        end
> -
> +    if spec = Gem.find_unresolved_default_spec(path)
> +      # Ensure -I beats a default gem
> +      resolved_path = begin
> +        rp = nil
> +        load_path_check_index = Gem.load_path_insert_index - Gem.activated_gem_paths
>          Gem.suffixes.each do |s|
> -          full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
> -          if File.file?(full_path)
> -            rp = full_path
> -            break
> +          $LOAD_PATH[0...load_path_check_index].each do |lp|
> +            safe_lp = lp.dup.tap(&Gem::UNTAINT)
> +            begin
> +              if File.symlink? safe_lp # for backward compatibility
> +                next
> +              end
> +            rescue SecurityError
> +              RUBYGEMS_ACTIVATION_MONITOR.exit
> +              raise
> +            end
> +
> +            full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}"))
> +            if File.file?(full_path)
> +              rp = full_path
> +              break
> +            end
>            end
> +          break if rp
>          end
> -        break if rp
> -      end
> -      rp
> -    end
> -
> -    if resolved_path
> -      begin
> -        RUBYGEMS_ACTIVATION_MONITOR.exit
> -        return gem_original_require(resolved_path)
> -      rescue LoadError
> -        RUBYGEMS_ACTIVATION_MONITOR.enter
> +        rp
>        end
> -    end
>  
> -    if spec = Gem.find_unresolved_default_spec(path)
>        begin
>          Kernel.send(:gem, spec.name, Gem::Requirement.default_prerelease)
>        rescue Exception
>          RUBYGEMS_ACTIVATION_MONITOR.exit
>          raise
> -      end
> +      end unless resolved_path
>      end
>  
>      # If there are no unresolved deps, then we can use just try
> @@ -157,8 +148,7 @@
>      RUBYGEMS_ACTIVATION_MONITOR.enter
>  
>      begin
> -      if load_error.message.start_with?("Could not find") or
> -          (load_error.message.end_with?(path) and Gem.try_activate(path))
> +      if load_error.message.end_with?(path) and Gem.try_activate(path)
>          require_again = true
>        end
>      ensure
> diff -Nru ruby2.7-2.7.2/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem ruby2.7-2.7.3/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem
> --- ruby2.7-2.7.2/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA.pem	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,21 @@
> +-----BEGIN CERTIFICATE-----
> +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
> +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
> +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
> +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
> +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
> +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
> +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
> +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
> +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
> +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
> +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
> +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
> +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
> +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
> +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
> +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
> +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
> +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
> +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
> +-----END CERTIFICATE-----
> diff -Nru ruby2.7-2.7.2/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem ruby2.7-2.7.3/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem
> --- ruby2.7-2.7.2/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem	1970-01-01 05:30:00.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rubygems/ssl_certs/rubygems.org/GlobalSignRootCA_R3.pem	2021-04-05 18:09:38.000000000 +0530
> @@ -0,0 +1,21 @@
> +-----BEGIN CERTIFICATE-----
> +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
> +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
> +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
> +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
> +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
> +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
> +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
> +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
> +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
> +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
> +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
> +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
> +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
> +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
> +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
> +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
> +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
> +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
> +WD9f
> +-----END CERTIFICATE-----
> diff -Nru ruby2.7-2.7.2/lib/rubygems/test_case.rb ruby2.7-2.7.3/lib/rubygems/test_case.rb
> --- ruby2.7-2.7.2/lib/rubygems/test_case.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rubygems/test_case.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -385,6 +385,7 @@
>      Gem::Security.reset
>  
>      Gem.loaded_specs.clear
> +    Gem.instance_variable_set(:@activated_gem_paths, 0)
>      Gem.clear_default_specs
>      Bundler.reset!
>  
> diff -Nru ruby2.7-2.7.2/lib/rubygems.rb ruby2.7-2.7.3/lib/rubygems.rb
> --- ruby2.7-2.7.2/lib/rubygems.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/rubygems.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -9,7 +9,7 @@
>  require 'rbconfig'
>  
>  module Gem
> -  VERSION = "3.1.4".freeze
> +  VERSION = "3.1.6".freeze
>  end
>  
>  # Must be first since it unloads the prelude from 1.9.2
> @@ -659,22 +659,25 @@
>  
>      index = $LOAD_PATH.index RbConfig::CONFIG['sitelibdir']
>  
> -    index
> +    index || 0
> +  end
> +
> +  ##
> +  # The number of paths in the `$LOAD_PATH` from activated gems. Used to
> +  # prioritize `-I` and `ENV['RUBYLIB`]` entries during `require`.
> +
> +  def self.activated_gem_paths
> +    @activated_gem_paths ||= 0
>    end
>  
>    ##
>    # Add a list of paths to the $LOAD_PATH at the proper place.
>  
>    def self.add_to_load_path(*paths)
> -    insert_index = load_path_insert_index
> +    @activated_gem_paths = activated_gem_paths + paths.size
>  
> -    if insert_index
> -      # gem directories must come after -I and ENV['RUBYLIB']
> -      $LOAD_PATH.insert(insert_index, *paths)
> -    else
> -      # we are probably testing in core, -I and RUBYLIB don't apply
> -      $LOAD_PATH.unshift(*paths)
> -    end
> +    # gem directories must come after -I and ENV['RUBYLIB']
> +    $LOAD_PATH.insert(Gem.load_path_insert_index, *paths)
>    end
>  
>    @yaml_loaded = false
> diff -Nru ruby2.7-2.7.2/lib/tmpdir.rb ruby2.7-2.7.3/lib/tmpdir.rb
> --- ruby2.7-2.7.2/lib/tmpdir.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/tmpdir.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -108,7 +108,7 @@
>        Dir.tmpdir
>      end
>  
> -    UNUSABLE_CHARS = [File::SEPARATOR, File::ALT_SEPARATOR, File::PATH_SEPARATOR, ":"].uniq.join("").freeze
> +    UNUSABLE_CHARS = "^,-.0-9A-Z_a-z~"
>  
>      def create(basename, tmpdir=nil, max_try: nil, **opts)
>        origdir = tmpdir
> diff -Nru ruby2.7-2.7.2/lib/webrick/httpservlet/filehandler.rb ruby2.7-2.7.3/lib/webrick/httpservlet/filehandler.rb
> --- ruby2.7-2.7.2/lib/webrick/httpservlet/filehandler.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/webrick/httpservlet/filehandler.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -214,7 +214,7 @@
>  
>        def service(req, res)
>          # if this class is mounted on "/" and /~username is requested.
> -        # we're going to override path information before invoking service.
> +        # we're going to override path informations before invoking service.
>          if defined?(Etc) && @options[:UserDir] && req.script_name.empty?
>            if %r|^(/~([^/]+))| =~ req.path_info
>              script_name, user = $1, $2
> diff -Nru ruby2.7-2.7.2/lib/webrick/version.rb ruby2.7-2.7.3/lib/webrick/version.rb
> --- ruby2.7-2.7.2/lib/webrick/version.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/lib/webrick/version.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -14,5 +14,5 @@
>    ##
>    # The WEBrick version
>  
> -  VERSION      = "1.6.0"
> +  VERSION      = "1.6.1"
>  end
> diff -Nru ruby2.7-2.7.2/numeric.c ruby2.7-2.7.3/numeric.c
> --- ruby2.7-2.7.2/numeric.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/numeric.c	2021-04-05 18:09:38.000000000 +0530
> @@ -1044,8 +1044,8 @@
>   * Returns a new Float which is the difference of +float+ and +other+.
>   */
>  
> -static VALUE
> -flo_minus(VALUE x, VALUE y)
> +VALUE
> +rb_float_minus(VALUE x, VALUE y)
>  {
>      if (RB_TYPE_P(y, T_FIXNUM)) {
>  	return DBL2NUM(RFLOAT_VALUE(x) - (double)FIX2LONG(y));
> @@ -1894,6 +1894,31 @@
>      return DBL2NUM(y);
>  }
>  
> +VALUE
> +rb_float_floor(VALUE num, int ndigits)
> +{
> +    double number, f;
> +    number = RFLOAT_VALUE(num);
> +    if (number == 0.0) {
> +	return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
> +    }
> +    if (ndigits > 0) {
> +	int binexp;
> +	frexp(number, &binexp);
> +	if (float_round_overflow(ndigits, binexp)) return num;
> +	if (number > 0.0 && float_round_underflow(ndigits, binexp))
> +	    return DBL2NUM(0.0);
> +	f = pow(10, ndigits);
> +	f = floor(number * f) / f;
> +	return DBL2NUM(f);
> +    }
> +    else {
> +	num = dbl2ival(floor(number));
> +	if (ndigits < 0) num = rb_int_floor(num, ndigits);
> +	return num;
> +    }
> +}
> +
>  /*
>   *  call-seq:
>   *     float.floor([ndigits])  ->  integer or float
> @@ -1936,31 +1961,11 @@
>  static VALUE
>  flo_floor(int argc, VALUE *argv, VALUE num)
>  {
> -    double number, f;
>      int ndigits = 0;
> -
>      if (rb_check_arity(argc, 0, 1)) {
>  	ndigits = NUM2INT(argv[0]);
>      }
> -    number = RFLOAT_VALUE(num);
> -    if (number == 0.0) {
> -	return ndigits > 0 ? DBL2NUM(number) : INT2FIX(0);
> -    }
> -    if (ndigits > 0) {
> -	int binexp;
> -	frexp(number, &binexp);
> -	if (float_round_overflow(ndigits, binexp)) return num;
> -	if (number > 0.0 && float_round_underflow(ndigits, binexp))
> -	    return DBL2NUM(0.0);
> -	f = pow(10, ndigits);
> -	f = floor(number * f) / f;
> -	return DBL2NUM(f);
> -    }
> -    else {
> -	num = dbl2ival(floor(number));
> -	if (ndigits < 0) num = rb_int_floor(num, ndigits);
> -	return num;
> -    }
> +    return rb_float_floor(num, ndigits);
>  }
>  
>  /*
> @@ -5790,7 +5795,7 @@
>      rb_define_method(rb_cFloat, "coerce", flo_coerce, 1);
>      rb_define_method(rb_cFloat, "-@", rb_float_uminus, 0);
>      rb_define_method(rb_cFloat, "+", rb_float_plus, 1);
> -    rb_define_method(rb_cFloat, "-", flo_minus, 1);
> +    rb_define_method(rb_cFloat, "-", rb_float_minus, 1);
>      rb_define_method(rb_cFloat, "*", rb_float_mul, 1);
>      rb_define_method(rb_cFloat, "/", rb_float_div, 1);
>      rb_define_method(rb_cFloat, "quo", flo_quo, 1);
> diff -Nru ruby2.7-2.7.2/parse.h ruby2.7-2.7.3/parse.h
> --- ruby2.7-2.7.2/parse.h	2020-10-01 17:45:40.000000000 +0530
> +++ ruby2.7-2.7.3/parse.h	2021-04-05 18:09:40.000000000 +0530
> @@ -1,8 +1,9 @@
> -/* A Bison parser, made by GNU Bison 3.0.4.  */
> +/* A Bison parser, made by GNU Bison 3.5.1.  */
>  
>  /* Bison interface for Yacc-like parsers in C
>  
> -   Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
> +   Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation,
> +   Inc.
>  
>     This program is free software: you can redistribute it and/or modify
>     it under the terms of the GNU General Public License as published by
> @@ -30,6 +31,9 @@
>     This special exception was added by the Free Software Foundation in
>     version 2.2 of Bison.  */
>  
> +/* Undocumented macros, especially those whose name start with YY_,
> +   are private implementation details.  Do not rely on them.  */
> +
>  #ifndef YY_YY_Y_TAB_H_INCLUDED
>  # define YY_YY_Y_TAB_H_INCLUDED
>  /* Debug traces.  */
> @@ -170,7 +174,6 @@
>  
>  /* Value type.  */
>  #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
> -
>  union YYSTYPE
>  {
>  
> @@ -182,8 +185,8 @@
>      const struct vtable *vars;
>      struct rb_strterm_struct *strterm;
>  
> -};
>  
> +};
>  typedef union YYSTYPE YYSTYPE;
>  # define YYSTYPE_IS_TRIVIAL 1
>  # define YYSTYPE_IS_DECLARED 1
> diff -Nru ruby2.7-2.7.2/parse.y ruby2.7-2.7.3/parse.y
> --- ruby2.7-2.7.2/parse.y	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/parse.y	2021-04-05 18:09:38.000000000 +0530
> @@ -2418,6 +2418,32 @@
>  		    /*% %*/
>  		    /*% ripper: arg_paren!(escape_Qundef($2)) %*/
>  		    }
> +		| '(' args ',' args_forward rparen
> +		    {
> +			if (!local_id(p, idFWD_REST) ||
> +#if idFWD_KWREST
> +			    !local_id(p, idFWD_KWREST) ||
> +#endif
> +			    !local_id(p, idFWD_BLOCK)) {
> +			    compile_error(p, "unexpected ...");
> +			    $$ = Qnone;
> +			}
> +			else {
> +			/*%%%*/
> +			    NODE *splat = NEW_SPLAT(NEW_LVAR(idFWD_REST, &@4), &@4);
> +#if idFWD_KWREST
> +			    NODE *kwrest = list_append(p, NEW_LIST(0, &@4), NEW_LVAR(idFWD_KWREST, &@4));
> +#endif
> +			    NODE *block = NEW_BLOCK_PASS(NEW_LVAR(idFWD_BLOCK, &@4), &@4);
> +			    $$ = rest_arg_append(p, $2, splat, &@$);
> +#if idFWD_KWREST
> +			    $$ = arg_append(p, $$, new_hash(p, kwrest, &@4), &@4);
> +#endif
> +			    $$ = arg_blk_pass($$, block);
> +			/*% %*/
> +			/*% ripper: arg_paren!(args_add!($2, $4)) %*/
> +			}
> +		    }
>  		| '(' args_forward rparen
>  		    {
>  			if (!local_id(p, idFWD_REST) ||
> @@ -4818,6 +4844,21 @@
>  			SET_LEX_STATE(EXPR_BEG);
>  			p->command_start = TRUE;
>  		    }
> +		| '(' f_arg ',' args_forward rparen
> +		    {
> +			arg_var(p, idFWD_REST);
> +#if idFWD_KWREST
> +			arg_var(p, idFWD_KWREST);
> +#endif
> +			arg_var(p, idFWD_BLOCK);
> +		    /*%%%*/
> +			$$ = new_args_tail(p, Qnone, idFWD_KWREST, idFWD_BLOCK, &@4);
> +			$$ = new_args(p, $2, Qnone, idFWD_REST, Qnone, $$, &@4);
> +		    /*% %*/
> +		    /*% ripper: paren!(params_new($2, Qnone, $4, Qnone, Qnone, Qnone, Qnone)) %*/
> +			SET_LEX_STATE(EXPR_BEG);
> +			p->command_start = TRUE;
> +		    }
>  		| '(' args_forward rparen
>  		    {
>  			arg_var(p, idFWD_REST);
> @@ -12147,12 +12188,13 @@
>      NODE *node, *succ;
>  
>      if (!len) return ST_CONTINUE;
> -    if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len))
> -        return ST_CONTINUE;
>      if (rb_enc_symname_type(s, len, enc, (1U<<ID_LOCAL)) != ID_LOCAL)
>          return ST_CONTINUE;
>  
>      var = intern_cstr(s, len, enc);
> +    if (len < MAX_WORD_LENGTH && rb_reserved_word(s, (int)len)) {
> +        if (!lvar_defined(p, var)) return ST_CONTINUE;
> +    }
>      node = node_assign(p, assignable(p, var, 0, arg->loc), NEW_LIT(ID2SYM(var), arg->loc), arg->loc);
>      succ = arg->succ_block;
>      if (!succ) succ = NEW_BEGIN(0, arg->loc);
> @@ -12673,7 +12715,6 @@
>  RUBY_FUNC_EXPORTED size_t
>  rb_yytnamerr(struct parser_params *p, char *yyres, const char *yystr)
>  {
> -    YYUSE(p);
>      if (*yystr == '"') {
>  	size_t yyn = 0, bquote = 0;
>  	const char *yyp = yystr;
> diff -Nru ruby2.7-2.7.2/proc.c ruby2.7-2.7.3/proc.c
> --- ruby2.7-2.7.2/proc.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/proc.c	2021-04-05 18:09:38.000000000 +0530
> @@ -3024,6 +3024,8 @@
>      return procval;
>  }
>  
> +extern VALUE rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner);
> +
>  /*
>   * call-seq:
>   *   meth.super_method  -> method
> @@ -3043,8 +3045,15 @@
>      TypedData_Get_Struct(method, struct METHOD, &method_data_type, data);
>      iclass = data->iclass;
>      if (!iclass) return Qnil;
> -    super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
> -    mid = data->me->called_id;
> +    if (data->me->def->type == VM_METHOD_TYPE_ALIAS) {
> +        super_class = RCLASS_SUPER(rb_find_defined_class_by_owner(data->me->defined_class,
> +            data->me->def->body.alias.original_me->owner));
> +        mid = data->me->def->body.alias.original_me->def->original_id;
> +    }
> +    else {
> +        super_class = RCLASS_SUPER(RCLASS_ORIGIN(iclass));
> +        mid = data->me->def->original_id;
> +    }
>      if (!super_class) return Qnil;
>      me = (rb_method_entry_t *)rb_callable_method_entry_with_refinements(super_class, mid, &iclass);
>      if (!me) return Qnil;
> diff -Nru ruby2.7-2.7.2/process.c ruby2.7-2.7.3/process.c
> --- ruby2.7-2.7.2/process.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/process.c	2021-04-05 18:09:38.000000000 +0530
> @@ -154,12 +154,40 @@
>  #define p_gid_from_name p_gid_from_name
>  #endif
>  
> +#if defined(HAVE_UNISTD_H)
> +# if defined(HAVE_GETLOGIN_R)
> +#  define USE_GETLOGIN_R 1
> +#  define GETLOGIN_R_SIZE_DEFAULT   0x100
> +#  define GETLOGIN_R_SIZE_LIMIT    0x1000
> +#  if defined(_SC_LOGIN_NAME_MAX)
> +#    define GETLOGIN_R_SIZE_INIT sysconf(_SC_LOGIN_NAME_MAX)
> +#  else
> +#    define GETLOGIN_R_SIZE_INIT GETLOGIN_R_SIZE_DEFAULT
> +#  endif
> +# elif defined(HAVE_GETLOGIN)
> +#  define USE_GETLOGIN 1
> +# endif
> +#endif
> +
>  #if defined(HAVE_PWD_H)
> -# if defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
> +# if defined(HAVE_GETPWUID_R)
> +#  define USE_GETPWUID_R 1
> +# elif defined(HAVE_GETPWUID)
> +#  define USE_GETPWUID 1
> +# endif
> +# if defined(HAVE_GETPWNAM_R)
>  #  define USE_GETPWNAM_R 1
> -#  define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
> +# elif defined(HAVE_GETPWNAM)
> +#  define USE_GETPWNAM 1
> +# endif
> +# if defined(HAVE_GETPWNAM_R) || defined(HAVE_GETPWUID_R)
>  #  define GETPW_R_SIZE_DEFAULT 0x1000
>  #  define GETPW_R_SIZE_LIMIT  0x10000
> +#  if defined(_SC_GETPW_R_SIZE_MAX)
> +#   define GETPW_R_SIZE_INIT sysconf(_SC_GETPW_R_SIZE_MAX)
> +#  else
> +#   define GETPW_R_SIZE_INIT GETPW_R_SIZE_DEFAULT
> +#  endif
>  # endif
>  # ifdef USE_GETPWNAM_R
>  #   define PREPARE_GETPWNAM \
> @@ -5509,6 +5537,240 @@
>  }
>  
>  
> +#if defined(HAVE_PWD_H)
> +/**
> + * Best-effort attempt to obtain the name of the login user, if any,
> + * associated with the process. Processes not descended from login(1) (or
> + * similar) may not have a logged-in user; returns Qnil in that case.
> + */
> +VALUE
> +rb_getlogin(void)
> +{
> +#if ( !defined(USE_GETLOGIN_R) && !defined(USE_GETLOGIN) )
> +    return Qnil;
> +#else
> +    char MAYBE_UNUSED(*login) = NULL;
> +
> +# ifdef USE_GETLOGIN_R
> +
> +    long loginsize = GETLOGIN_R_SIZE_INIT;  /* maybe -1 */
> +
> +    if (loginsize < 0)
> +        loginsize = GETLOGIN_R_SIZE_DEFAULT;
> +
> +    VALUE maybe_result = rb_str_buf_new(loginsize);
> +
> +    login = RSTRING_PTR(maybe_result);
> +    loginsize = rb_str_capacity(maybe_result);
> +    rb_str_set_len(maybe_result, loginsize);
> +
> +    int gle;
> +    errno = 0;
> +    while ((gle = getlogin_r(login, loginsize)) != 0) {
> +
> +        if (gle == ENOTTY || gle == ENXIO || gle == ENOENT) {
> +            rb_str_resize(maybe_result, 0);
> +            return Qnil;
> +        }
> +
> +        if (gle != ERANGE || loginsize >= GETLOGIN_R_SIZE_LIMIT) {
> +            rb_str_resize(maybe_result, 0);
> +            rb_syserr_fail(gle, "getlogin_r");
> +        }
> +
> +        rb_str_modify_expand(maybe_result, loginsize);
> +        login = RSTRING_PTR(maybe_result);
> +        loginsize = rb_str_capacity(maybe_result);
> +    }
> +
> +    if (login == NULL) {
> +        rb_str_resize(maybe_result, 0);
> +        return Qnil;
> +    }
> +
> +    return maybe_result;
> +
> +# elif USE_GETLOGIN
> +
> +    errno = 0;
> +    login = getlogin();
> +    if (errno) {
> +        if (errno == ENOTTY || errno == ENXIO || errno == ENOENT) {
> +            return Qnil;
> +        }
> +        rb_syserr_fail(errno, "getlogin");
> +    }
> +
> +    return login ? rb_str_new_cstr(login) : Qnil;
> +# endif
> +
> +#endif
> +}
> +
> +VALUE
> +rb_getpwdirnam_for_login(VALUE login_name)
> +{
> +#if ( !defined(USE_GETPWNAM_R) && !defined(USE_GETPWNAM) )
> +    return Qnil;
> +#else
> +
> +    if (NIL_P(login_name)) {
> +        /* nothing to do; no name with which to query the password database */
> +        return Qnil;
> +    }
> +
> +    char *login = RSTRING_PTR(login_name);
> +
> +    struct passwd *pwptr;
> +
> +# ifdef USE_GETPWNAM_R
> +
> +    struct passwd pwdnm;
> +    char *bufnm;
> +    long bufsizenm = GETPW_R_SIZE_INIT;  /* maybe -1 */
> +
> +    if (bufsizenm < 0)
> +        bufsizenm = GETPW_R_SIZE_DEFAULT;
> +
> +    VALUE getpwnm_tmp = rb_str_tmp_new(bufsizenm);
> +
> +    bufnm = RSTRING_PTR(getpwnm_tmp);
> +    bufsizenm = rb_str_capacity(getpwnm_tmp);
> +    rb_str_set_len(getpwnm_tmp, bufsizenm);
> +
> +    int enm;
> +    errno = 0;
> +    while ((enm = getpwnam_r(login, &pwdnm, bufnm, bufsizenm, &pwptr)) != 0) {
> +
> +        if (enm == ENOENT || enm== ESRCH || enm == EBADF || enm == EPERM) {
> +            /* not found; non-errors */
> +            rb_str_resize(getpwnm_tmp, 0);
> +            return Qnil;
> +        }
> +
> +        if (enm != ERANGE || bufsizenm >= GETPW_R_SIZE_LIMIT) {
> +            rb_str_resize(getpwnm_tmp, 0);
> +            rb_syserr_fail(enm, "getpwnam_r");
> +        }
> +
> +        rb_str_modify_expand(getpwnm_tmp, bufsizenm);
> +        bufnm = RSTRING_PTR(getpwnm_tmp);
> +        bufsizenm = rb_str_capacity(getpwnm_tmp);
> +    }
> +
> +    if (pwptr == NULL) {
> +        /* no record in the password database for the login name */
> +        rb_str_resize(getpwnm_tmp, 0);
> +        return Qnil;
> +    }
> +
> +    /* found it */
> +    VALUE result = rb_str_new_cstr(pwptr->pw_dir);
> +    rb_str_resize(getpwnm_tmp, 0);
> +    return result;
> +
> +# elif USE_GETPWNAM
> +
> +    errno = 0;
> +    pwptr = getpwnam(login);
> +    if (pwptr) {
> +        /* found it */
> +        return rb_str_new_cstr(pwptr->pw_dir);
> +    }
> +    if (errno
> +        /*   avoid treating as errors errno values that indicate "not found" */
> +        && ( errno != ENOENT && errno != ESRCH && errno != EBADF && errno != EPERM)) {
> +        rb_syserr_fail(errno, "getpwnam");
> +    }
> +
> +    return Qnil;  /* not found */
> +# endif
> +
> +#endif
> +}
> +
> +/**
> + * Look up the user's dflt home dir in the password db, by uid.
> + */
> +VALUE
> +rb_getpwdiruid(void)
> +{
> +# if !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID)
> +    /* Should never happen... </famous-last-words> */
> +    return Qnil;
> +# else
> +    uid_t ruid = getuid();
> +
> +    struct passwd *pwptr;
> +
> +# ifdef USE_GETPWUID_R
> +
> +    struct passwd pwdid;
> +    char *bufid;
> +    long bufsizeid = GETPW_R_SIZE_INIT;  /* maybe -1 */
> +
> +    if (bufsizeid < 0)
> +        bufsizeid = GETPW_R_SIZE_DEFAULT;
> +
> +    VALUE getpwid_tmp = rb_str_tmp_new(bufsizeid);
> +
> +    bufid = RSTRING_PTR(getpwid_tmp);
> +    bufsizeid = rb_str_capacity(getpwid_tmp);
> +    rb_str_set_len(getpwid_tmp, bufsizeid);
> +
> +    int eid;
> +    errno = 0;
> +    while ((eid = getpwuid_r(ruid, &pwdid, bufid, bufsizeid, &pwptr)) != 0) {
> +
> +        if (eid == ENOENT || eid== ESRCH || eid == EBADF || eid == EPERM) {
> +            /* not found; non-errors */
> +            rb_str_resize(getpwid_tmp, 0);
> +            return Qnil;
> +        }
> +
> +        if (eid != ERANGE || bufsizeid >= GETPW_R_SIZE_LIMIT) {
> +            rb_str_resize(getpwid_tmp, 0);
> +            rb_syserr_fail(eid, "getpwuid_r");
> +        }
> +
> +        rb_str_modify_expand(getpwid_tmp, bufsizeid);
> +        bufid = RSTRING_PTR(getpwid_tmp);
> +        bufsizeid = rb_str_capacity(getpwid_tmp);
> +    }
> +
> +    if (pwptr == NULL) {
> +        /* no record in the password database for the uid */
> +        rb_str_resize(getpwid_tmp, 0);
> +        return Qnil;
> +    }
> +
> +    /* found it */
> +    VALUE result = rb_str_new_cstr(pwptr->pw_dir);
> +    rb_str_resize(getpwid_tmp, 0);
> +    return result;
> +
> +# elif defined(USE_GETPWUID)
> +
> +    errno = 0;
> +    pwptr = getpwuid(ruid);
> +    if (pwptr) {
> +        /* found it */
> +        return rb_str_new_cstr(pwptr->pw_dir);
> +    }
> +    if (errno
> +        /*   avoid treating as errors errno values that indicate "not found" */
> +        && ( errno == ENOENT || errno == ESRCH || errno == EBADF || errno == EPERM)) {
> +        rb_syserr_fail(errno, "getpwuid");
> +    }
> +
> +    return Qnil;  /* not found */
> +# endif
> +
> +#endif /* !defined(USE_GETPWUID_R) && !defined(USE_GETPWUID) */
> +}
> +#endif /* HAVE_PWD_H */
> +
> +
>  /*********************************************************************
>   * Document-class: Process::Sys
>   *
> diff -Nru ruby2.7-2.7.2/random.c ruby2.7-2.7.3/random.c
> --- ruby2.7-2.7.2/random.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/random.c	2021-04-05 18:09:38.000000000 +0530
> @@ -9,6 +9,10 @@
>  
>  **********************************************************************/
>  
> +#if defined __APPLE__
> +# include <AvailabilityMacros.h>
> +#endif
> +
>  #include "internal.h"
>  
>  #include <limits.h>
> diff -Nru ruby2.7-2.7.2/rational.c ruby2.7-2.7.3/rational.c
> --- ruby2.7-2.7.2/rational.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/rational.c	2021-04-05 18:09:38.000000000 +0530
> @@ -774,8 +774,8 @@
>   *    Rational(9, 8)  - 4                #=> (-23/8)
>   *    Rational(20, 9) - 9.8              #=> -7.577777777777778
>   */
> -static VALUE
> -nurat_sub(VALUE self, VALUE other)
> +VALUE
> +rb_rational_minus(VALUE self, VALUE other)
>  {
>      if (RB_INTEGER_TYPE_P(other)) {
>  	{
> @@ -912,8 +912,8 @@
>   *    Rational(9, 8)  / 4                #=> (9/32)
>   *    Rational(20, 9) / 9.8              #=> 0.22675736961451246
>   */
> -static VALUE
> -nurat_div(VALUE self, VALUE other)
> +VALUE
> +rb_rational_div(VALUE self, VALUE other)
>  {
>      if (RB_INTEGER_TYPE_P(other)) {
>  	if (f_zero_p(other))
> @@ -965,10 +965,10 @@
>  {
>      VALUE div;
>      if (f_zero_p(other))
> -        return nurat_div(self, rb_float_new(0.0));
> +        return rb_rational_div(self, rb_float_new(0.0));
>      if (FIXNUM_P(other) && other == LONG2FIX(1))
>  	return nurat_to_f(self);
> -    div = nurat_div(self, other);
> +    div = rb_rational_div(self, other);
>      if (RB_TYPE_P(div, T_RATIONAL))
>  	return nurat_to_f(div);
>      if (RB_FLOAT_TYPE_P(div))
> @@ -1403,7 +1403,7 @@
>  
>      s = (*func)(s);
>  
> -    s = nurat_div(f_rational_new_bang1(CLASS_OF(self), s), b);
> +    s = rb_rational_div(f_rational_new_bang1(CLASS_OF(self), s), b);
>  
>      if (RB_TYPE_P(s, T_RATIONAL) && FIX2INT(rb_int_cmp(n, ONE)) < 0)
>  	s = nurat_truncate(s);
> @@ -1411,6 +1411,18 @@
>      return s;
>  }
>  
> +VALUE
> +rb_rational_floor(VALUE self, int ndigits)
> +{
> +    if (ndigits == 0) {
> +        return nurat_floor(self);
> +    }
> +    else {
> +        VALUE n = INT2NUM(ndigits);
> +        return f_round_common(1, &n, self, nurat_floor);
> +    }
> +}
> +
>  /*
>   * call-seq:
>   *    rat.floor([ndigits])  ->  integer or rational
> @@ -1875,7 +1887,7 @@
>  rb_rational_reciprocal(VALUE x)
>  {
>      get_dat1(x);
> -    return f_rational_new_no_reduce2(CLASS_OF(x), dat->den, dat->num);
> +    return nurat_convert(CLASS_OF(x), dat->den, dat->num, FALSE);
>  }
>  
>  /*
> @@ -2027,7 +2039,7 @@
>      else {
>          x = rb_convert_type(x, T_RATIONAL, "Rational", "to_r");
>      }
> -    return nurat_div(x, y);
> +    return rb_rational_div(x, y);
>  }
>  
>  VALUE
> @@ -2734,10 +2746,10 @@
>  
>      rb_define_method(rb_cRational, "-@", rb_rational_uminus, 0);
>      rb_define_method(rb_cRational, "+", rb_rational_plus, 1);
> -    rb_define_method(rb_cRational, "-", nurat_sub, 1);
> +    rb_define_method(rb_cRational, "-", rb_rational_minus, 1);
>      rb_define_method(rb_cRational, "*", rb_rational_mul, 1);
> -    rb_define_method(rb_cRational, "/", nurat_div, 1);
> -    rb_define_method(rb_cRational, "quo", nurat_div, 1);
> +    rb_define_method(rb_cRational, "/", rb_rational_div, 1);
> +    rb_define_method(rb_cRational, "quo", rb_rational_div, 1);
>      rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1);
>      rb_define_method(rb_cRational, "**", nurat_expt, 1);
>  
> diff -Nru ruby2.7-2.7.2/regint.h ruby2.7-2.7.3/regint.h
> --- ruby2.7-2.7.2/regint.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/regint.h	2021-04-05 18:09:38.000000000 +0530
> @@ -52,7 +52,7 @@
>  #ifndef UNALIGNED_WORD_ACCESS
>  # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
>       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> -     defined(__powerpc64__) || \
> +     defined(__powerpc64__) || defined(__aarch64__) || \
>       defined(__mc68020__)
>  #  define UNALIGNED_WORD_ACCESS 1
>  # else
> diff -Nru ruby2.7-2.7.2/revision.h ruby2.7-2.7.3/revision.h
> --- ruby2.7-2.7.2/revision.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/revision.h	2021-04-05 18:09:38.000000000 +0530
> @@ -1,2 +1,2 @@
> -#define RUBY_REVISION "5445e04352"
> -#define RUBY_FULL_REVISION "5445e0435260b449decf2ac16f9d09bae3cafe72"
> +#define RUBY_REVISION "6847ee089d"
> +#define RUBY_FULL_REVISION "6847ee089d7655b2a0eea4fee3133aeacd4cc7cc"
> diff -Nru ruby2.7-2.7.2/ruby.c ruby2.7-2.7.3/ruby.c
> --- ruby2.7-2.7.2/ruby.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/ruby.c	2021-04-05 18:09:38.000000000 +0530
> @@ -1771,6 +1771,9 @@
>              rb_ary_replace(vm->load_path_snapshot, load_path);
>          }
>      }
> +
> +    rb_warning_category_update(opt->warn.mask, opt->warn.set);
> +
>      Init_ext();		/* load statically linked extensions before rubygems */
>      if (opt->features.set & FEATURE_BIT(gems)) {
>  	rb_define_module("Gem");
> @@ -1819,7 +1822,6 @@
>          ruby_set_script_name(progname);
>  	rb_parser_set_options(parser, opt->do_print, opt->do_loop,
>  			      opt->do_line, opt->do_split);
> -        rb_warning_category_update(opt->warn.mask, opt->warn.set);
>  	ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
>      }
>      else {
> @@ -2058,7 +2060,6 @@
>      }
>      rb_parser_set_options(parser, opt->do_print, opt->do_loop,
>  			  opt->do_line, opt->do_split);
> -    rb_warning_category_update(opt->warn.mask, opt->warn.set);
>      if (NIL_P(f)) {
>  	f = rb_str_new(0, 0);
>  	rb_enc_associate(f, enc);
> diff -Nru ruby2.7-2.7.2/siphash.c ruby2.7-2.7.3/siphash.c
> --- ruby2.7-2.7.2/siphash.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/siphash.c	2021-04-05 18:09:38.000000000 +0530
> @@ -30,7 +30,7 @@
>  #ifndef UNALIGNED_WORD_ACCESS
>  # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
>       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> -     defined(__powerpc64__) || \
> +     defined(__powerpc64__) || defined(__aarch64__) || \
>       defined(__mc68020__)
>  #   define UNALIGNED_WORD_ACCESS 1
>  # endif
> diff -Nru ruby2.7-2.7.2/spec/ruby/core/process/clock_getres_spec.rb ruby2.7-2.7.3/spec/ruby/core/process/clock_getres_spec.rb
> --- ruby2.7-2.7.2/spec/ruby/core/process/clock_getres_spec.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/spec/ruby/core/process/clock_getres_spec.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1,34 +1,6 @@
>  require_relative '../../spec_helper'
> -require_relative 'fixtures/clocks'
>  
>  describe "Process.clock_getres" do
> -  # clock_getres() seems completely buggy on FreeBSD:
> -  # https://rubyci.org/logs/rubyci.s3.amazonaws.com/freebsd11zfs/ruby-trunk/log/20190428T093003Z.fail.html.gz
> -  platform_is_not :freebsd, :openbsd do
> -    # NOTE: Look at fixtures/clocks.rb for clock and OS-specific exclusions
> -    ProcessSpecs.clock_constants_for_resolution_checks.each do |name, value|
> -      it "matches the clock in practice for Process::#{name}" do
> -        times = 10_000.times.map { Process.clock_gettime(value, :nanosecond) }
> -        reported = Process.clock_getres(value, :nanosecond)
> -
> -        # The clock should not be more accurate than reported (times should be
> -        # a multiple of reported precision.)
> -        times.select { |t| t % reported > 0 }.should be_empty
> -
> -        # We're assuming precision is a multiple of ten - it may or may not
> -        # be an incompatibility if it isn't but we'd like to notice this,
> -        # and the spec following these wouldn't work if it isn't.
> -        reported.should > 0
> -        (reported == 1 || reported % 10 == 0).should be_true
> -
> -        # The clock should not be less accurate than reported (times should
> -        # not all be a multiple of the next precision up, assuming precisions
> -        # are multiples of ten.)
> -        times.select { |t| t % (reported * 10) == 0 }.size.should_not == times.size
> -      end
> -    end
> -  end
> -
>    # These are documented
>  
>    it "with :GETTIMEOFDAY_BASED_CLOCK_REALTIME reports 1 microsecond" do
> @@ -47,15 +19,15 @@
>  
>    # These are observed
>  
> -  platform_is_not :solaris, :aix, :openbsd do
> -    it "with Process::CLOCK_REALTIME reports at least 1 microsecond" do
> -      Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond).should <= 1_000
> +  platform_is :linux, :darwin, :windows do
> +    it "with Process::CLOCK_REALTIME reports at least 10 millisecond" do
> +      Process.clock_getres(Process::CLOCK_REALTIME, :nanosecond).should <= 10_000_000
>      end
>    end
>  
> -  platform_is_not :aix, :openbsd do
> -    it "with Process::CLOCK_MONOTONIC reports at least 1 microsecond" do
> -      Process.clock_getres(Process::CLOCK_MONOTONIC, :nanosecond).should <= 1_000
> +  platform_is :linux, :darwin, :windows do
> +    it "with Process::CLOCK_MONOTONIC reports at least 10 millisecond" do
> +      Process.clock_getres(Process::CLOCK_MONOTONIC, :nanosecond).should <= 10_000_000
>      end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/spec/ruby/core/process/fixtures/clocks.rb ruby2.7-2.7.3/spec/ruby/core/process/fixtures/clocks.rb
> --- ruby2.7-2.7.2/spec/ruby/core/process/fixtures/clocks.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/spec/ruby/core/process/fixtures/clocks.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -15,46 +15,4 @@
>        [c, Process.const_get(c)]
>      }
>    end
> -
> -  def self.clock_constants_for_resolution_checks
> -    clocks = clock_constants
> -
> -    # These clocks in practice on Linux do not seem to match their reported resolution.
> -    platform_is :linux do
> -      clocks = clocks.reject { |clock, value|
> -        [:CLOCK_REALTIME_COARSE, :CLOCK_MONOTONIC_COARSE].include?(clock)
> -      }
> -    end
> -
> -    # These clocks in practice on macOS seem to be less precise than advertised by clock_getres
> -    platform_is :darwin do
> -      clocks = clocks.reject { |clock, value|
> -        [:CLOCK_UPTIME_RAW_APPROX, :CLOCK_MONOTONIC_RAW_APPROX].include?(clock)
> -      }
> -    end
> -
> -    # These clocks in practice on ARM on Linux do not seem to match their reported resolution.
> -    platform_is :armv7, :armv8, :aarch64 do
> -      clocks = clocks.reject { |clock, value|
> -        [:CLOCK_PROCESS_CPUTIME_ID, :CLOCK_THREAD_CPUTIME_ID, :CLOCK_MONOTONIC_RAW].include?(clock)
> -      }
> -    end
> -
> -    # These clocks in practice on AIX seem to be more precise than their reported resolution.
> -    platform_is :aix do
> -      clocks = clocks.reject { |clock, value|
> -        [:CLOCK_REALTIME, :CLOCK_MONOTONIC].include?(clock)
> -      }
> -    end
> -
> -    # On a Hyper-V Linux guest machine, these clocks in practice
> -    # seem to be less precise than advertised by clock_getres
> -    platform_is :linux do
> -      clocks = clocks.reject { |clock, value|
> -        clock == :CLOCK_MONOTONIC_RAW
> -      }
> -    end
> -
> -    clocks
> -  end
>  end
> diff -Nru ruby2.7-2.7.2/st.c ruby2.7-2.7.3/st.c
> --- ruby2.7-2.7.2/st.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/st.c	2021-04-05 18:09:38.000000000 +0530
> @@ -1815,7 +1815,7 @@
>  #ifndef UNALIGNED_WORD_ACCESS
>  # if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
>       defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
> -     defined(__powerpc64__) || \
> +     defined(__powerpc64__) || defined(__aarch64__) || \
>       defined(__mc68020__)
>  #   define UNALIGNED_WORD_ACCESS 1
>  # endif
> diff -Nru ruby2.7-2.7.2/test/irb/test_cmd.rb ruby2.7-2.7.3/test/irb/test_cmd.rb
> --- ruby2.7-2.7.2/test/irb/test_cmd.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/irb/test_cmd.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -17,12 +17,14 @@
>        Dir.chdir(@tmpdir)
>        @home_backup = ENV["HOME"]
>        ENV["HOME"] = @tmpdir
> +      @xdg_config_home_backup = ENV.delete("XDG_CONFIG_HOME")
>        @default_encoding = [Encoding.default_external, Encoding.default_internal]
>        @stdio_encodings = [STDIN, STDOUT, STDERR].map {|io| [io.external_encoding, io.internal_encoding] }
>        IRB.instance_variable_get(:@CONF).clear
>      end
>  
>      def teardown
> +      ENV["XDG_CONFIG_HOME"] = @xdg_config_home_backup
>        ENV["HOME"] = @home_backup
>        Dir.chdir(@pwd)
>        FileUtils.rm_rf(@tmpdir)
> diff -Nru ruby2.7-2.7.2/test/irb/test_history.rb ruby2.7-2.7.3/test/irb/test_history.rb
> --- ruby2.7-2.7.2/test/irb/test_history.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/irb/test_history.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1,6 +1,7 @@
>  # frozen_string_literal: false
>  require 'test/unit'
>  require 'irb'
> +require 'irb/ext/save-history'
>  require 'readline'
>  
>  module TestIRB
> @@ -13,133 +14,154 @@
>        IRB.conf[:RC_NAME_GENERATOR] = nil
>      end
>  
> +    class TestInputMethod < ::IRB::InputMethod
> +      HISTORY = Array.new
> +
> +      include IRB::HistorySavingAbility
> +
> +      attr_reader :list, :line_no
> +
> +      def initialize(list = [])
> +        super("test")
> +        @line_no = 0
> +        @list = list
> +      end
> +
> +      def gets
> +        @list[@line_no]&.tap {@line_no += 1}
> +      end
> +
> +      def eof?
> +        @line_no >= @list.size
> +      end
> +
> +      def encoding
> +        Encoding.default_external
> +      end
> +
> +      def reset
> +        @line_no = 0
> +      end
> +
> +      def winsize
> +        [10, 20]
> +      end
> +    end
> +
>      def test_history_save_1
>        omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> -      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> -        IRB.conf[:USE_READLINE] = true
> -        IRB.conf[:SAVE_HISTORY] = 1
> -        IRB.conf[:USE_READLINE] = true
> -      IRBRC
> +      IRB.conf[:SAVE_HISTORY] = 1
> +      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
> +        exit
> +      EXPECTED_HISTORY
>          1
>          2
>          3
>          4
> -      IRB_HISTORY
> -        stdin.write("5\nexit\n")
> -      end
> -
> -      assert_equal(<<~HISTORY_FILE, result_history_file)
> +      INITIAL_HISTORY
> +        5
>          exit
> -      HISTORY_FILE
> +      INPUT
>      end
>  
>      def test_history_save_100
>        omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> -      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> -        IRB.conf[:USE_READLINE] = true
> -        IRB.conf[:SAVE_HISTORY] = 100
> -        IRB.conf[:USE_READLINE] = true
> -      IRBRC
> +      IRB.conf[:SAVE_HISTORY] = 100
> +      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
>          1
>          2
>          3
>          4
> -      IRB_HISTORY
> -        stdin.write("5\nexit\n")
> -      end
> -
> -      assert_equal(<<~HISTORY_FILE, result_history_file)
> +        5
> +        exit
> +      EXPECTED_HISTORY
>          1
>          2
>          3
>          4
> +      INITIAL_HISTORY
>          5
>          exit
> -      HISTORY_FILE
> +      INPUT
>      end
>  
>      def test_history_save_bignum
>        omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> -      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> -        IRB.conf[:USE_READLINE] = true
> -        IRB.conf[:SAVE_HISTORY] = 10 ** 19
> -        IRB.conf[:USE_READLINE] = true
> -      IRBRC
> +      IRB.conf[:SAVE_HISTORY] = 10 ** 19
> +      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
>          1
>          2
>          3
>          4
> -      IRB_HISTORY
> -        stdin.write("5\nexit\n")
> -      end
> -
> -      assert_equal(<<~HISTORY_FILE, result_history_file)
> +        5
> +        exit
> +      EXPECTED_HISTORY
>          1
>          2
>          3
>          4
> +      INITIAL_HISTORY
>          5
>          exit
> -      HISTORY_FILE
> +      INPUT
>      end
>  
>      def test_history_save_minus_as_infinity
>        omit "Skip Editline" if /EditLine/n.match(Readline::VERSION)
> -      _result_output, result_history_file = launch_irb_with_irbrc_and_irb_history(<<~IRBRC, <<~IRB_HISTORY) do |stdin|
> -        IRB.conf[:USE_READLINE] = true
> -        IRB.conf[:SAVE_HISTORY] = -1 # infinity
> -        IRB.conf[:USE_READLINE] = true
> -      IRBRC
> +      IRB.conf[:SAVE_HISTORY] = -1 # infinity
> +      assert_history(<<~EXPECTED_HISTORY, <<~INITIAL_HISTORY, <<~INPUT)
>          1
>          2
>          3
>          4
> -      IRB_HISTORY
> -        stdin.write("5\nexit\n")
> -      end
> -
> -      assert_equal(<<~HISTORY_FILE, result_history_file)
> +        5
> +        exit
> +      EXPECTED_HISTORY
>          1
>          2
>          3
>          4
> +      INITIAL_HISTORY
>          5
>          exit
> -      HISTORY_FILE
> +      INPUT
>      end
>  
>      private
>  
> -    def launch_irb_with_irbrc_and_irb_history(irbrc, irb_history)
> -      result = nil
> -      result_history = nil
> -      backup_irbrc = ENV.delete("IRBRC")
> +    def assert_history(expected_history, initial_irb_history, input)
> +      backup_verbose, $VERBOSE = $VERBOSE, nil
>        backup_home = ENV["HOME"]
> +      backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME")
> +      IRB.conf[:LC_MESSAGES] = IRB::Locale.new
> +      actual_history = nil
>        Dir.mktmpdir("test_irb_history_#{$$}") do |tmpdir|
>          ENV["HOME"] = tmpdir
> -        open(IRB.rc_file, "w") do |f|
> -          f.write(irbrc)
> -        end
>          open(IRB.rc_file("_history"), "w") do |f|
> -          f.write(irb_history)
> +          f.write(initial_irb_history)
>          end
>  
> -        with_temp_stdio do |stdin, stdout|
> -          yield(stdin, stdout)
> -          stdin.close
> -          stdout.flush
> -          system('ruby', '-Ilib', '-Itest', '-W0', '-rirb', '-e', 'IRB.start(__FILE__)', in: stdin.path, out: stdout.path)
> -          result = stdout.read
> -          stdout.close
> -        end
> +        io = TestInputMethod.new
> +        io.class::HISTORY.clear
> +        io.load_history
> +        io.class::HISTORY.concat(input.split)
> +        io.save_history
> +
> +        io.load_history
>          open(IRB.rc_file("_history"), "r") do |f|
> -          result_history = f.read
> +          actual_history = f.read
>          end
>        end
> -      [result, result_history]
> +      assert_equal(expected_history, actual_history, <<~MESSAGE)
> +        expected:
> +        #{expected_history}
> +        but actual:
> +        #{actual_history}
> +      MESSAGE
>      ensure
> +      $VERBOSE = backup_verbose
>        ENV["HOME"] = backup_home
> -      ENV["IRBRC"] = backup_irbrc
> +      ENV["XDG_CONFIG_HOME"] = backup_xdg_config_home
>      end
>  
>      def with_temp_stdio
> diff -Nru ruby2.7-2.7.2/test/irb/test_init.rb ruby2.7-2.7.3/test/irb/test_init.rb
> --- ruby2.7-2.7.2/test/irb/test_init.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/irb/test_init.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -21,6 +21,7 @@
>  
>      def test_rc_file
>        backup_irbrc = ENV.delete("IRBRC") # This is for RVM...
> +      backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME")
>        backup_home = ENV["HOME"]
>        Dir.mktmpdir("test_irb_init_#{$$}") do |tmpdir|
>          ENV["HOME"] = tmpdir
> @@ -35,11 +36,13 @@
>        end
>      ensure
>        ENV["HOME"] = backup_home
> +      ENV["XDG_CONFIG_HOME"] = backup_xdg_config_home
>        ENV["IRBRC"] = backup_irbrc
>      end
>  
>      def test_rc_file_in_subdir
>        backup_irbrc = ENV.delete("IRBRC") # This is for RVM...
> +      backup_xdg_config_home = ENV.delete("XDG_CONFIG_HOME")
>        backup_home = ENV["HOME"]
>        Dir.mktmpdir("test_irb_init_#{$$}") do |tmpdir|
>          ENV["HOME"] = tmpdir
> @@ -57,6 +60,7 @@
>        end
>      ensure
>        ENV["HOME"] = backup_home
> +      ENV["XDG_CONFIG_HOME"] = backup_xdg_config_home
>        ENV["IRBRC"] = backup_irbrc
>      end
>  
> diff -Nru ruby2.7-2.7.2/test/pathname/test_pathname.rb ruby2.7-2.7.3/test/pathname/test_pathname.rb
> --- ruby2.7-2.7.2/test/pathname/test_pathname.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/pathname/test_pathname.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -690,6 +690,32 @@
>      }
>    end
>  
> +  def test_each_line_opts
> +    with_tmpchdir('rubytest-pathname') {|dir|
> +      open("a", "w") {|f| f.puts 1, 2 }
> +      a = []
> +      Pathname("a").each_line(chomp: true) {|line| a << line }
> +      assert_equal(["1", "2"], a)
> +
> +      a = []
> +      Pathname("a").each_line("2", chomp: true) {|line| a << line }
> +      assert_equal(["1\n", "\n"], a)
> +
> +      a = []
> +      Pathname("a").each_line(1, chomp: true) {|line| a << line }
> +      assert_equal(["1", "", "2", ""], a)
> +
> +      a = []
> +      Pathname("a").each_line("2", 1, chomp: true) {|line| a << line }
> +      assert_equal(["1", "\n", "", "\n"], a)
> +
> +      a = []
> +      enum = Pathname("a").each_line(chomp: true)
> +      enum.each {|line| a << line }
> +      assert_equal(["1", "2"], a)
> +    }
> +  end
> +
>    def test_readlines
>      with_tmpchdir('rubytest-pathname') {|dir|
>        open("a", "w") {|f| f.puts 1, 2 }
> diff -Nru ruby2.7-2.7.2/test/resolv/test_dns.rb ruby2.7-2.7.3/test/resolv/test_dns.rb
> --- ruby2.7-2.7.2/test/resolv/test_dns.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/resolv/test_dns.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -128,6 +128,119 @@
>      }
>    end
>  
> +  def test_query_ipv4_duplicate_responses
> +    begin
> +      OpenSSL
> +    rescue LoadError
> +      skip 'autoload problem. see [ruby-dev:45021][Bug #5786]'
> +    end if defined?(OpenSSL)
> +
> +    with_udp('127.0.0.1', 0) {|u|
> +      _, server_port, _, server_address = u.addr
> +      begin
> +        client_thread = Thread.new {
> +          Resolv::DNS.open(:nameserver_port => [[server_address, server_port]], :search => ['bad1.com', 'bad2.com', 'good.com'], ndots: 5) {|dns|
> +            dns.getaddress("example")
> +          }
> +        }
> +        server_thread = Thread.new {
> +          3.times do
> +            msg, (_, client_port, _, client_address) = Timeout.timeout(5) {u.recvfrom(4096)}
> +            id, flags, qdcount, ancount, nscount, arcount = msg.unpack("nnnnnn")
> +
> +            qr =     (flags & 0x8000) >> 15
> +            opcode = (flags & 0x7800) >> 11
> +            aa =     (flags & 0x0400) >> 10
> +            tc =     (flags & 0x0200) >> 9
> +            rd =     (flags & 0x0100) >> 8
> +            ra =     (flags & 0x0080) >> 7
> +            z =      (flags & 0x0070) >> 4
> +            rcode =   flags & 0x000f
> +            rest = msg[12..-1]
> +
> +            questions = msg.bytes[12..-1]
> +            labels = []
> +            idx = 0
> +            while idx < questions.length-5
> +              size = questions[idx]
> +              labels << questions[idx+1..idx+size].pack('c*')
> +              idx += size+1
> +            end
> +            hostname = labels.join('.')
> +
> +            if hostname == "example.good.com"
> +              id = id
> +              qr = 1
> +              opcode = opcode
> +              aa = 0
> +              tc = 0
> +              rd = rd
> +              ra = 1
> +              z = 0
> +              rcode = 0
> +              qdcount = 1
> +              ancount = 1
> +              nscount = 0
> +              arcount = 0
> +              word2 = (qr << 15) |
> +                      (opcode << 11) |
> +                      (aa << 10) |
> +                      (tc << 9) |
> +                      (rd << 8) |
> +                      (ra << 7) |
> +                      (z << 4) |
> +                      rcode
> +              msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
> +              msg << questions.pack('c*')
> +              type = 1
> +              klass = 1
> +              ttl = 3600
> +              rdlength = 4
> +              rdata = [52,0,2,1].pack("CCCC")
> +              rr = [0xc00c, type, klass, ttl, rdlength, rdata].pack("nnnNna*")
> +              msg << rr
> +              rdata = [52,0,2,2].pack("CCCC")
> +              rr = [0xc00c, type, klass, ttl, rdlength, rdata].pack("nnnNna*")
> +              msg << rr
> +
> +              u.send(msg, 0, client_address, client_port)
> +            else
> +              id = id
> +              qr = 1
> +              opcode = opcode
> +              aa = 0
> +              tc = 0
> +              rd = rd
> +              ra = 1
> +              z = 0
> +              rcode = 3
> +              qdcount = 1
> +              ancount = 0
> +              nscount = 0
> +              arcount = 0
> +              word2 = (qr << 15) |
> +                      (opcode << 11) |
> +                      (aa << 10) |
> +                      (tc << 9) |
> +                      (rd << 8) |
> +                      (ra << 7) |
> +                      (z << 4) |
> +                      rcode
> +              msg = [id, word2, qdcount, ancount, nscount, arcount].pack("nnnnnn")
> +              msg << questions.pack('c*')
> +
> +              u.send(msg, 0, client_address, client_port)
> +              u.send(msg, 0, client_address, client_port)
> +            end
> +          end
> +        }
> +        result, _ = assert_join_threads([client_thread, server_thread])
> +        assert_instance_of(Resolv::IPv4, result)
> +        assert_equal("52.0.2.1", result.to_s)
> +      end
> +    }
> +  end
> +
>    def test_query_ipv4_address_timeout
>      with_udp('127.0.0.1', 0) {|u|
>        _, port , _, host = u.addr
> diff -Nru ruby2.7-2.7.2/test/rexml/parse/test_document_type_declaration.rb ruby2.7-2.7.3/test/rexml/parse/test_document_type_declaration.rb
> --- ruby2.7-2.7.2/test/rexml/parse/test_document_type_declaration.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/parse/test_document_type_declaration.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -5,17 +5,187 @@
>  module REXMLTests
>    class TestParseDocumentTypeDeclaration < Test::Unit::TestCase
>      private
> -    def xml(internal_subset)
> -      <<-XML
> -<!DOCTYPE r SYSTEM "urn:x-rexml:test" [
> -#{internal_subset}
> -]>
> +    def parse(doctype)
> +      REXML::Document.new(<<-XML).doctype
> +#{doctype}
>  <r/>
>        XML
>      end
>  
> -    def parse(internal_subset)
> -      REXML::Document.new(xml(internal_subset)).doctype
> +    class TestName < self
> +      def test_valid
> +        doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r>
> +        DOCTYPE
> +        assert_equal("r", doctype.name)
> +      end
> +
> +      def test_garbage_plus_before_name_at_line_start
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-DOCTYPE)
> +<!DOCTYPE +
> +r SYSTEM "urn:x-rexml:test" [
> +]>
> +          DOCTYPE
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed DOCTYPE: invalid name
> +Line: 5
> +Position: 51
> +Last 80 unconsumed characters:
> ++ r SYSTEM "urn:x-rexml:test" [ ]>  <r/> 
> +        DETAIL
> +      end
> +    end
> +
> +    class TestExternalID < self
> +      class TestSystem < self
> +        def test_left_bracket_in_system_literal
> +          doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM "urn:x-rexml:[test" [
> +]>
> +          DOCTYPE
> +          assert_equal([
> +                         "r",
> +                         "SYSTEM",
> +                         nil,
> +                         "urn:x-rexml:[test",
> +                       ],
> +                       [
> +                         doctype.name,
> +                         doctype.external_id,
> +                         doctype.public,
> +                         doctype.system,
> +                       ])
> +        end
> +
> +        def test_greater_than_in_system_literal
> +          doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM "urn:x-rexml:>test" [
> +]>
> +          DOCTYPE
> +          assert_equal([
> +                         "r",
> +                         "SYSTEM",
> +                         nil,
> +                         "urn:x-rexml:>test",
> +                       ],
> +                       [
> +                         doctype.name,
> +                         doctype.external_id,
> +                         doctype.public,
> +                         doctype.system,
> +                       ])
> +        end
> +
> +        def test_no_literal
> +          exception = assert_raise(REXML::ParseException) do
> +            parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM>
> +            DOCTYPE
> +          end
> +          assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed DOCTYPE: system literal is missing
> +Line: 3
> +Position: 26
> +Last 80 unconsumed characters:
> + SYSTEM>  <r/> 
> +          DETAIL
> +        end
> +
> +        def test_garbage_after_literal
> +          exception = assert_raise(REXML::ParseException) do
> +            parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM 'r.dtd'x'>
> +            DOCTYPE
> +          end
> +          assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed DOCTYPE: garbage after external ID
> +Line: 3
> +Position: 36
> +Last 80 unconsumed characters:
> +x'>  <r/> 
> +          DETAIL
> +        end
> +
> +        def test_single_quote
> +          doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM 'r".dtd'>
> +          DOCTYPE
> +          assert_equal("r\".dtd", doctype.system)
> +        end
> +
> +        def test_double_quote
> +          doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM "r'.dtd">
> +          DOCTYPE
> +          assert_equal("r'.dtd", doctype.system)
> +        end
> +      end
> +
> +      class TestPublic < self
> +        class TestPublicIDLiteral < self
> +          def test_content_double_quote
> +            exception = assert_raise(REXML::ParseException) do
> +              parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC 'double quote " is invalid' "r.dtd">
> +              DOCTYPE
> +            end
> +            assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed DOCTYPE: invalid public ID literal
> +Line: 3
> +Position: 62
> +Last 80 unconsumed characters:
> + PUBLIC 'double quote " is invalid' "r.dtd">  <r/> 
> +            DETAIL
> +          end
> +
> +          def test_single_quote
> +            doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC 'public-id-literal' "r.dtd">
> +            DOCTYPE
> +            assert_equal("public-id-literal", doctype.public)
> +          end
> +
> +          def test_double_quote
> +            doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC "public'-id-literal" "r.dtd">
> +            DOCTYPE
> +            assert_equal("public'-id-literal", doctype.public)
> +          end
> +        end
> +
> +        class TestSystemLiteral < self
> +          def test_garbage_after_literal
> +            exception = assert_raise(REXML::ParseException) do
> +              parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC 'public-id-literal' 'system-literal'x'>
> +              DOCTYPE
> +            end
> +            assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed DOCTYPE: garbage after external ID
> +Line: 3
> +Position: 65
> +Last 80 unconsumed characters:
> +x'>  <r/> 
> +           DETAIL
> +          end
> +
> +          def test_single_quote
> +            doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC "public-id-literal" 'system"-literal'>
> +            DOCTYPE
> +            assert_equal("system\"-literal", doctype.system)
> +          end
> +
> +          def test_double_quote
> +            doctype = parse(<<-DOCTYPE)
> +<!DOCTYPE r PUBLIC "public-id-literal" "system'-literal">
> +            DOCTYPE
> +            assert_equal("system'-literal", doctype.system)
> +          end
> +        end
> +      end
>      end
>  
>      class TestMixed < self
> @@ -45,6 +215,15 @@
>          assert_equal([REXML::NotationDecl, REXML::AttlistDecl],
>                       doctype.children.collect(&:class))
>        end
> +
> +      private
> +      def parse(internal_subset)
> +        super(<<-DOCTYPE)
> +<!DOCTYPE r SYSTEM "urn:x-rexml:test" [
> +#{internal_subset}
> +]>
> +        DOCTYPE
> +      end
>      end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/test/rexml/parse/test_element.rb ruby2.7-2.7.3/test/rexml/parse/test_element.rb
> --- ruby2.7-2.7.2/test/rexml/parse/test_element.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/parse/test_element.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -46,6 +46,32 @@
>  
>          DETAIL
>        end
> +
> +      def test_garbage_less_than_before_root_element_at_line_start
> +        exception = assert_raise(REXML::ParseException) do
> +          parse("<\n<x/>")
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +malformed XML: missing tag start
> +Line: 2
> +Position: 6
> +Last 80 unconsumed characters:
> +< <x/>
> +        DETAIL
> +      end
> +
> +      def test_garbage_less_than_slash_before_end_tag_at_line_start
> +        exception = assert_raise(REXML::ParseException) do
> +          parse("<x></\n</x>")
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Missing end tag for 'x'
> +Line: 2
> +Position: 10
> +Last 80 unconsumed characters:
> +</ </x>
> +        DETAIL
> +      end
>      end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/test/rexml/parse/test_notation_declaration.rb ruby2.7-2.7.3/test/rexml/parse/test_notation_declaration.rb
> --- ruby2.7-2.7.2/test/rexml/parse/test_notation_declaration.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/parse/test_notation_declaration.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -23,10 +23,100 @@
>          doctype = parse("<!NOTATION name PUBLIC 'urn:public-id'>")
>          assert_equal("name", doctype.notation("name").name)
>        end
> +
> +      def test_no_name
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: name is missing
> +Line: 5
> +Position: 72
> +Last 80 unconsumed characters:
> + <!NOTATION>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_invalid_name
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION '>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: invalid name
> +Line: 5
> +Position: 74
> +Last 80 unconsumed characters:
> +'>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_no_id_type
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: invalid ID type
> +Line: 5
> +Position: 77
> +Last 80 unconsumed characters:
> +>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_invalid_id_type
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name INVALID>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: invalid ID type
> +Line: 5
> +Position: 85
> +Last 80 unconsumed characters:
> + INVALID>  ]> <r/> 
> +        DETAIL
> +      end
>      end
>  
>      class TestExternalID < self
>        class TestSystem < self
> +        def test_no_literal
> +          exception = assert_raise(REXML::ParseException) do
> +            parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name SYSTEM>
> +            INTERNAL_SUBSET
> +          end
> +          assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: system literal is missing
> +Line: 5
> +Position: 84
> +Last 80 unconsumed characters:
> + SYSTEM>  ]> <r/> 
> +          DETAIL
> +        end
> +
> +        def test_garbage_after_literal
> +          exception = assert_raise(REXML::ParseException) do
> +            parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name SYSTEM 'system-literal'x'>
> +            INTERNAL_SUBSET
> +          end
> +          assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: garbage before end >
> +Line: 5
> +Position: 103
> +Last 80 unconsumed characters:
> +x'>  ]> <r/> 
> +          DETAIL
> +        end
> +
>          def test_single_quote
>            doctype = parse(<<-INTERNAL_SUBSET)
>  <!NOTATION name SYSTEM 'system-literal'>
> @@ -44,6 +134,21 @@
>  
>        class TestPublic < self
>          class TestPublicIDLiteral < self
> +          def test_content_double_quote
> +            exception = assert_raise(REXML::ParseException) do
> +              parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC 'double quote " is invalid' "system-literal">
> +              INTERNAL_SUBSET
> +            end
> +            assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: invalid public ID literal
> +Line: 5
> +Position: 129
> +Last 80 unconsumed characters:
> + PUBLIC 'double quote " is invalid' "system-literal">  ]> <r/> 
> +            DETAIL
> +          end
> +
>            def test_single_quote
>              doctype = parse(<<-INTERNAL_SUBSET)
>  <!NOTATION name PUBLIC 'public-id-literal' "system-literal">
> @@ -60,6 +165,21 @@
>          end
>  
>          class TestSystemLiteral < self
> +          def test_garbage_after_literal
> +            exception = assert_raise(REXML::ParseException) do
> +              parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC 'public-id-literal' 'system-literal'x'>
> +              INTERNAL_SUBSET
> +            end
> +            assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: garbage before end >
> +Line: 5
> +Position: 123
> +Last 80 unconsumed characters:
> +x'>  ]> <r/> 
> +           DETAIL
> +          end
> +
>            def test_single_quote
>              doctype = parse(<<-INTERNAL_SUBSET)
>  <!NOTATION name PUBLIC "public-id-literal" 'system-literal'>
> @@ -96,5 +216,66 @@
>          end
>        end
>      end
> +
> +    class TestPublicID < self
> +      def test_no_literal
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: public ID literal is missing
> +Line: 5
> +Position: 84
> +Last 80 unconsumed characters:
> + PUBLIC>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_literal_content_double_quote
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC 'double quote " is invalid in PubidLiteral'>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: invalid public ID literal
> +Line: 5
> +Position: 128
> +Last 80 unconsumed characters:
> + PUBLIC 'double quote \" is invalid in PubidLiteral'>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_garbage_after_literal
> +        exception = assert_raise(REXML::ParseException) do
> +          parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC 'public-id-literal'x'>
> +          INTERNAL_SUBSET
> +        end
> +        assert_equal(<<-DETAIL.chomp, exception.to_s)
> +Malformed notation declaration: garbage before end >
> +Line: 5
> +Position: 106
> +Last 80 unconsumed characters:
> +x'>  ]> <r/> 
> +        DETAIL
> +      end
> +
> +      def test_literal_single_quote
> +        doctype = parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC 'public-id-literal'>
> +        INTERNAL_SUBSET
> +        assert_equal("public-id-literal", doctype.notation("name").public)
> +      end
> +
> +      def test_literal_double_quote
> +        doctype = parse(<<-INTERNAL_SUBSET)
> +<!NOTATION name PUBLIC "public-id-literal">
> +        INTERNAL_SUBSET
> +        assert_equal("public-id-literal", doctype.notation("name").public)
> +      end
> +    end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/test/rexml/parse/test_processing_instruction.rb ruby2.7-2.7.3/test/rexml/parse/test_processing_instruction.rb
> --- ruby2.7-2.7.2/test/rexml/parse/test_processing_instruction.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/parse/test_processing_instruction.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -20,6 +20,25 @@
>  <??>
>          DETAIL
>        end
> +
> +      def test_garbage_text
> +        # TODO: This should be parse error.
> +        # Create test/parse/test_document.rb or something and move this to it.
> +        doc = parse(<<-XML)
> +x<?x y
> +<!--?><?x -->?>
> +<r/>
> +        XML
> +        pi = doc.children[1]
> +        assert_equal([
> +                       "x",
> +                       "y\n<!--",
> +                     ],
> +                     [
> +                       pi.target,
> +                       pi.content,
> +                     ])
> +      end
>      end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/test/rexml/parser/test_ultra_light.rb ruby2.7-2.7.3/test/rexml/parser/test_ultra_light.rb
> --- ruby2.7-2.7.2/test/rexml/parser/test_ultra_light.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/parser/test_ultra_light.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -16,7 +16,6 @@
>                         nil,
>                         [:entitydecl, "name", "value"]
>                       ],
> -                     [:text, "\n"],
>                       [:start_element, :parent, "root", {}],
>                       [:text, "\n"],
>                     ],
> diff -Nru ruby2.7-2.7.2/test/rexml/test_core.rb ruby2.7-2.7.3/test/rexml/test_core.rb
> --- ruby2.7-2.7.2/test/rexml/test_core.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/test_core.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1043,7 +1043,7 @@
>        document.write(s)
>  
>        ## XML Doctype
> -      str = '<!DOCTYPE foo "bar">'
> +      str = '<!DOCTYPE foo SYSTEM "bar">'
>        source  = REXML::Source.new(str)
>        doctype = REXML::DocType.new(source)
>        document.add(doctype)
> diff -Nru ruby2.7-2.7.2/test/rexml/test_doctype.rb ruby2.7-2.7.3/test/rexml/test_doctype.rb
> --- ruby2.7-2.7.2/test/rexml/test_doctype.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rexml/test_doctype.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -18,12 +18,6 @@
>        @doc_type_system = REXML::Document.new(xml_system).doctype
>  
>        @pubid = "TEST_ID"
> -      xml_public = <<-XML
> -      <!DOCTYPE root PUBLIC "#{@pubid}">
> -      <root/>
> -      XML
> -      @doc_type_public = REXML::Document.new(xml_public).doctype
> -
>        xml_public_system = <<-XML
>        <!DOCTYPE root PUBLIC "#{@pubid}" "#{@sysid}">
>        <root/>
> @@ -35,11 +29,9 @@
>        assert_equal([
>                       nil,
>                       @pubid,
> -                     @pubid,
>                     ],
>                     [
>                       @doc_type_system.public,
> -                     @doc_type_public.public,
>                       @doc_type_public_system.public,
>                     ])
>      end
> @@ -58,12 +50,10 @@
>      def test_system
>        assert_equal([
>                       @sysid,
> -                     nil,
>                       @sysid,
>                     ],
>                     [
>                       @doc_type_system.system,
> -                     @doc_type_public.system,
>                       @doc_type_public_system.system,
>                     ])
>      end
> diff -Nru ruby2.7-2.7.2/test/ripper/test_parser_events.rb ruby2.7-2.7.3/test/ripper/test_parser_events.rb
> --- ruby2.7-2.7.2/test/ripper/test_parser_events.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ripper/test_parser_events.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -132,9 +132,17 @@
>    end
>  
>    def test_args_forward
> -    thru_args_forward = false
> -    parse('def m(...) n(...) end', :on_args_forward) {thru_args_forward = true}
> -    assert_equal true, thru_args_forward
> +    [
> +      'def m(...) n(...) end',
> +      'def m(...) end',
> +      'def m(a, ...) n(1, ...) end',
> +      'def m(...) n(1, ...) end',
> +      'def m(a, ...) n(...) end'
> +    ].each do |code|
> +      thru_args_forward = false
> +      parse(code, :on_args_forward) {thru_args_forward = true}
> +      assert_equal true, thru_args_forward, "no args_forward for: #{code}"
> +    end
>    end
>  
>    def test_arg_paren
> diff -Nru ruby2.7-2.7.2/test/ruby/test_arithmetic_sequence.rb ruby2.7-2.7.3/test/ruby/test_arithmetic_sequence.rb
> --- ruby2.7-2.7.2/test/ruby/test_arithmetic_sequence.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_arithmetic_sequence.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -284,6 +284,11 @@
>                            '[ruby-core:90648] [Bug #15444]')
>    end
>  
> +  def test_last_bug17218
> +    seq = (1.0997r .. 1.1r).step(0.0001r)
> +    assert_equal([1.0997r, 1.0998r, 1.0999r, 1.1r], seq.to_a, '[ruby-core:100312] [Bug #17218]')
> +  end
> +
>    def test_slice
>      seq = 1.step(10, 2)
>      assert_equal([[1, 3, 5], [7, 9]], seq.each_slice(3).to_a)
> diff -Nru ruby2.7-2.7.2/test/ruby/test_array.rb ruby2.7-2.7.3/test/ruby/test_array.rb
> --- ruby2.7-2.7.2/test/ruby/test_array.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_array.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -886,6 +886,17 @@
>      assert_raise(NoMethodError, bug12738) { a.flatten.m }
>    end
>  
> +  def test_flatten_recursive
> +    a = []
> +    a << a
> +    assert_raise(ArgumentError) { a.flatten }
> +    b = [1]; c = [2, b]; b << c
> +    assert_raise(ArgumentError) { b.flatten }
> +
> +    assert_equal([1, 2, b], b.flatten(1))
> +    assert_equal([1, 2, 1, 2, 1, c], b.flatten(4))
> +  end
> +
>    def test_flatten!
>      a1 = @cls[ 1, 2, 3]
>      a2 = @cls[ 5, 6 ]
> @@ -2624,9 +2635,6 @@
>  
>    def test_flatten_error
>      a = []
> -    a << a
> -    assert_raise(ArgumentError) { a.flatten }
> -
>      f = [].freeze
>      assert_raise(ArgumentError) { a.flatten!(1, 2) }
>      assert_raise(TypeError) { a.flatten!(:foo) }
> diff -Nru ruby2.7-2.7.2/test/ruby/test_class.rb ruby2.7-2.7.3/test/ruby/test_class.rb
> --- ruby2.7-2.7.2/test/ruby/test_class.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_class.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -483,6 +483,53 @@
>      assert_equal(:foo, d.foo)
>    end
>  
> +  def test_clone_singleton_class_exists
> +    klass = Class.new do
> +      def self.bar; :bar; end
> +    end
> +
> +    o = klass.new
> +    o.singleton_class
> +    clone = o.clone
> +
> +    assert_empty(o.singleton_class.instance_methods(false))
> +    assert_empty(clone.singleton_class.instance_methods(false))
> +    assert_empty(o.singleton_class.singleton_class.instance_methods(false))
> +    assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
> +  end
> +
> +  def test_clone_when_singleton_class_of_singleton_class_exists
> +    klass = Class.new do
> +      def self.bar; :bar; end
> +    end
> +
> +    o = klass.new
> +    o.singleton_class.singleton_class
> +    clone = o.clone
> +
> +    assert_empty(o.singleton_class.instance_methods(false))
> +    assert_empty(clone.singleton_class.instance_methods(false))
> +    assert_empty(o.singleton_class.singleton_class.instance_methods(false))
> +    assert_empty(clone.singleton_class.singleton_class.instance_methods(false))
> +  end
> +
> +  def test_clone_when_method_exists_on_singleton_class_of_singleton_class
> +    klass = Class.new do
> +      def self.bar; :bar; end
> +    end
> +
> +    o = klass.new
> +    o.singleton_class.singleton_class.define_method(:s2_method) { :s2 }
> +    clone = o.clone
> +
> +    assert_empty(o.singleton_class.instance_methods(false))
> +    assert_empty(clone.singleton_class.instance_methods(false))
> +    assert_equal(:s2, o.singleton_class.s2_method)
> +    assert_equal(:s2, clone.singleton_class.s2_method)
> +    assert_equal([:s2_method], o.singleton_class.singleton_class.instance_methods(false))
> +    assert_equal([:s2_method], clone.singleton_class.singleton_class.instance_methods(false))
> +  end
> +
>    def test_singleton_class_p
>      feature7609 = '[ruby-core:51087] [Feature #7609]'
>      assert_predicate(self.singleton_class, :singleton_class?, feature7609)
> diff -Nru ruby2.7-2.7.2/test/ruby/test_enum.rb ruby2.7-2.7.3/test/ruby/test_enum.rb
> --- ruby2.7-2.7.2/test/ruby/test_enum.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_enum.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -228,11 +228,13 @@
>      assert_equal(15, [3, 5, 7].inject(:+))
>      assert_float_equal(15.0, [3, 5, 7.0].inject(:+))
>      assert_equal(2*FIXNUM_MAX, Array.new(2, FIXNUM_MAX).inject(:+))
> +    assert_equal(3*FIXNUM_MAX, Array.new(3, FIXNUM_MAX).inject(:+))
>      assert_equal(2*(FIXNUM_MAX+1), Array.new(2, FIXNUM_MAX+1).inject(:+))
>      assert_equal(10*FIXNUM_MAX, Array.new(10, FIXNUM_MAX).inject(:+))
>      assert_equal(0, ([FIXNUM_MAX, 1, -FIXNUM_MAX, -1]*10).inject(:+))
>      assert_equal(FIXNUM_MAX*10, ([FIXNUM_MAX+1, -1]*10).inject(:+))
>      assert_equal(2*FIXNUM_MIN, Array.new(2, FIXNUM_MIN).inject(:+))
> +    assert_equal(3*FIXNUM_MIN, Array.new(3, FIXNUM_MIN).inject(:+))
>      assert_equal((FIXNUM_MAX+1).to_f, [FIXNUM_MAX, 1, 0.0].inject(:+))
>      assert_float_equal(10.0, [3.0, 5].inject(2.0, :+))
>      assert_float_equal((FIXNUM_MAX+1).to_f, [0.0, FIXNUM_MAX+1].inject(:+))
> diff -Nru ruby2.7-2.7.2/test/ruby/test_keyword.rb ruby2.7-2.7.3/test/ruby/test_keyword.rb
> --- ruby2.7-2.7.2/test/ruby/test_keyword.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_keyword.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -2741,6 +2741,11 @@
>          baz(*args)
>        end
>  
> +      define_method(:block_splat) {|*args| }
> +      ruby2_keywords :block_splat, def foo_bar_after_bmethod(*args)
> +        bar(*args)
> +      end
> +
>        ruby2_keywords def foo_baz2(*args)
>          baz(*args)
>          baz(*args)
> @@ -2876,6 +2881,7 @@
>      assert_equal([1, h1], o.foo(:foo_baz, 1, :a=>1))
>      assert_equal([[1], h1], o.foo_foo_bar(1, :a=>1))
>      assert_equal([1, h1], o.foo_foo_baz(1, :a=>1))
> +    assert_equal([[1], h1], o.foo_bar_after_bmethod(1, :a=>1))
>  
>      assert_equal([[1], h1], o.foo(:bar, 1, **h1))
>      assert_equal([1, h1], o.foo(:baz, 1, **h1))
> @@ -2891,6 +2897,7 @@
>      assert_equal([1, h1], o.foo(:foo_baz, 1, **h1))
>      assert_equal([[1], h1], o.foo_foo_bar(1, **h1))
>      assert_equal([1, h1], o.foo_foo_baz(1, **h1))
> +    assert_equal([[1], h1], o.foo_bar_after_bmethod(1, **h1))
>  
>      assert_equal([[h1], {}], o.foo(:bar, h1, **{}))
>      assert_equal([h1], o.foo(:baz, h1, **{}))
> @@ -2906,6 +2913,7 @@
>      assert_equal([h1], o.foo(:foo_baz, h1, **{}))
>      assert_equal([[h1], {}], o.foo_foo_bar(h1, **{}))
>      assert_equal([h1], o.foo_foo_baz(h1, **{}))
> +    assert_equal([[h1], {}], o.foo_bar_after_bmethod(h1, **{}))
>  
>      assert_warn(/Using the last argument as keyword parameters is deprecated.*The called method `bar'/m) do
>        assert_equal([[1], h1], o.foo(:bar, 1, h1))
> @@ -2923,6 +2931,7 @@
>        assert_equal([[1], h1], o.foo_bar(1, h1))
>      end
>      assert_equal([1, h1], o.foo_baz(1, h1))
> +    assert_equal([[1], h1], o.foo_bar_after_bmethod(1, h1))
>  
>      assert_equal([[1, h1, 1], {}], o.foo_mod(:bar, 1, :a=>1))
>      assert_equal([1, h1, 1], o.foo_mod(:baz, 1, :a=>1))
> diff -Nru ruby2.7-2.7.2/test/ruby/test_method.rb ruby2.7-2.7.3/test/ruby/test_method.rb
> --- ruby2.7-2.7.2/test/ruby/test_method.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_method.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1064,6 +1064,86 @@
>        '[ruby-core:85231] [Bug #14421]'
>    end
>  
> +  def test_super_method_alias
> +    c0 = Class.new do
> +      def m1
> +        [:C0_m1]
> +      end
> +      def m2
> +        [:C0_m2]
> +      end
> +    end
> +
> +    c1 = Class.new(c0) do
> +      def m1
> +        [:C1_m1] + super
> +      end
> +      alias m2 m1
> +    end
> +
> +    c2 = Class.new(c1) do
> +      def m2
> +        [:C2_m2] + super
> +      end
> +    end
> +    o1 = c2.new
> +    assert_equal([:C2_m2, :C1_m1, :C0_m1], o1.m2)
> +
> +    m = o1.method(:m2)
> +    assert_equal([:C2_m2, :C1_m1, :C0_m1], m.call)
> +
> +    m = m.super_method
> +    assert_equal([:C1_m1, :C0_m1], m.call)
> +
> +    m = m.super_method
> +    assert_equal([:C0_m1], m.call)
> +
> +    assert_nil(m.super_method)
> +  end
> +
> +  def test_super_method_alias_to_prepended_module
> +    m = Module.new do
> +      def m1
> +        [:P_m1] + super
> +      end
> +
> +      def m2
> +        [:P_m2] + super
> +      end
> +    end
> +
> +    c0 = Class.new do
> +      def m1
> +        [:C0_m1]
> +      end
> +    end
> +
> +    c1 = Class.new(c0) do
> +      def m1
> +        [:C1_m1] + super
> +      end
> +      prepend m
> +      alias m2 m1
> +    end
> +
> +    o1 = c1.new
> +    assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], o1.m2)
> +
> +    m = o1.method(:m2)
> +    assert_equal([:P_m2, :P_m1, :C1_m1, :C0_m1], m.call)
> +
> +    m = m.super_method
> +    assert_equal([:P_m1, :C1_m1, :C0_m1], m.call)
> +
> +    m = m.super_method
> +    assert_equal([:C1_m1, :C0_m1], m.call)
> +
> +    m = m.super_method
> +    assert_equal([:C0_m1], m.call)
> +
> +    assert_nil(m.super_method)
> +  end
> +
>    def rest_parameter(*rest)
>      rest
>    end
> diff -Nru ruby2.7-2.7.2/test/ruby/test_module.rb ruby2.7-2.7.3/test/ruby/test_module.rb
> --- ruby2.7-2.7.2/test/ruby/test_module.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_module.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1924,6 +1924,29 @@
>      assert_equal(0, 1 / 2)
>    end
>  
> +  def test_visibility_after_refine_and_visibility_change
> +    m = Module.new
> +    c = Class.new do
> +      def x; :x end
> +    end
> +    c.prepend(m)
> +    Module.new do
> +      refine c do
> +        def x; :y end
> +      end
> +    end
> +
> +    o1 = c.new
> +    o2 = c.new
> +    assert_equal(:x, o1.public_send(:x))
> +    assert_equal(:x, o2.public_send(:x))
> +    o1.singleton_class.send(:private, :x)
> +    o2.singleton_class.send(:public, :x)
> +
> +    assert_raise(NoMethodError) { o1.public_send(:x) }
> +    assert_equal(:x, o2.public_send(:x))
> +  end
> +
>    def test_prepend_visibility
>      bug8005 = '[ruby-core:53106] [Bug #8005]'
>      c = Class.new do
> diff -Nru ruby2.7-2.7.2/test/ruby/test_rational.rb ruby2.7-2.7.3/test/ruby/test_rational.rb
> --- ruby2.7-2.7.2/test/ruby/test_rational.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_rational.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -598,6 +598,13 @@
>      assert_nothing_raised(TypeError, '[Bug #5020] [ruby-dev:44088]') do
>        Rational(1,2).coerce(Complex(1,1))
>      end
> +
> +    assert_raise(ZeroDivisionError) do
> +      1 / 0r.coerce(0+0i)[0]
> +    end
> +    assert_raise(ZeroDivisionError) do
> +      1 / 0r.coerce(0.0+0i)[0]
> +    end
>    end
>  
>    class ObjectX
> diff -Nru ruby2.7-2.7.2/test/ruby/test_regexp.rb ruby2.7-2.7.3/test/ruby/test_regexp.rb
> --- ruby2.7-2.7.2/test/ruby/test_regexp.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_regexp.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -218,6 +218,17 @@
>    def test_assign_named_capture_to_reserved_word
>      /(?<nil>.)/ =~ "a"
>      assert_not_include(local_variables, :nil, "[ruby-dev:32675]")
> +
> +    def (obj = Object.new).test(s, nil: :ng)
> +      /(?<nil>.)/ =~ s
> +      binding.local_variable_get(:nil)
> +    end
> +    assert_equal("b", obj.test("b"))
> +
> +    tap do |nil: :ng|
> +      /(?<nil>.)/ =~ "c"
> +      assert_equal("c", binding.local_variable_get(:nil))
> +    end
>    end
>  
>    def test_assign_named_capture_to_const
> diff -Nru ruby2.7-2.7.2/test/ruby/test_require.rb ruby2.7-2.7.3/test/ruby/test_require.rb
> --- ruby2.7-2.7.2/test/ruby/test_require.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_require.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -368,15 +368,15 @@
>      bug = '[ruby-list:49994] path in ospath'
>      base = "test_load\u{3042 3044 3046 3048 304a}".encode(Encoding::Windows_31J)
>      path = nil
> -    Tempfile.create([base, ".rb"]) do |t|
> -      path = t.path
> -
> +    Dir.mktmpdir do |dir|
> +      path = File.join(dir, base+".rb")
>        assert_raise_with_message(LoadError, /#{base}/) {
> -        load(File.join(File.dirname(path), base))
> +        load(File.join(dir, base))
>        }
>  
> -      t.puts "warn 'ok'"
> -      t.close
> +      File.open(path, "w+b") do |t|
> +        t.puts "warn 'ok'"
> +      end
>        assert_include(path, base)
>        assert_warn("ok\n", bug) {
>          assert_nothing_raised(LoadError, bug) {
> diff -Nru ruby2.7-2.7.2/test/ruby/test_rubyoptions.rb ruby2.7-2.7.3/test/ruby/test_rubyoptions.rb
> --- ruby2.7-2.7.2/test/ruby/test_rubyoptions.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_rubyoptions.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -83,6 +83,15 @@
>      assert_in_out_err(%w(-w -e) + ['p Warning[:deprecated]'], "", %w(true), [])
>      assert_in_out_err(%w(-W -e) + ['p Warning[:deprecated]'], "", %w(true), [])
>      assert_in_out_err(%w(-e) + ['p Warning[:deprecated]'], "", %w(false), [])
> +    code = 'puts "#{$VERBOSE}:#{Warning[:deprecated]}:#{Warning[:experimental]}"'
> +    Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) do |t|
> +      t.puts code
> +      t.close
> +      assert_in_out_err(["-r#{t.path}", '-e', code], "", %w(false:false:true false:false:true), [])
> +      assert_in_out_err(["-r#{t.path}", '-w', '-e', code], "", %w(true:true:true true:true:true), [])
> +      assert_in_out_err(["-r#{t.path}", '-W:deprecated', '-e', code], "", %w(false:true:true false:true:true), [])
> +      assert_in_out_err(["-r#{t.path}", '-W:no-experimental', '-e', code], "", %w(false:false:false false:false:false), [])
> +    end
>    ensure
>      ENV['RUBYOPT'] = save_rubyopt
>    end
> @@ -1060,6 +1069,11 @@
>      end
>    end
>  
> +  def test_rubylib_invalid_encoding
> +    env = {"RUBYLIB"=>"\xFF", "LOCALE"=>"en_US.UTF-8", "LC_ALL"=>"en_US.UTF-8"}
> +    assert_ruby_status([env, "-e;"])
> +  end
> +
>    def test_null_script
>      skip "#{IO::NULL} is not a character device" unless File.chardev?(IO::NULL)
>      assert_in_out_err([IO::NULL], success: true)
> diff -Nru ruby2.7-2.7.2/test/ruby/test_syntax.rb ruby2.7-2.7.3/test/ruby/test_syntax.rb
> --- ruby2.7-2.7.2/test/ruby/test_syntax.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_syntax.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1374,6 +1374,15 @@
>      assert_nil obj.test
>    end
>  
> +  def test_assignment_return_in_loop
> +    obj = Object.new
> +    def obj.test
> +      x = nil
> +      _y = (return until x unless x)
> +    end
> +    assert_nil obj.test, "[Bug #16695]"
> +  end
> +
>    def test_method_call_location
>      line = __LINE__+5
>      e = assert_raise(NoMethodError) do
> @@ -1544,6 +1553,119 @@
>      end
>    end
>  
> +  def test_argument_forwarding_with_leading_arguments
> +    obj = Object.new
> +    def obj.bar(*args, **kws, &block)
> +      if block
> +        block.call(args, kws)
> +      else
> +        [args, kws]
> +      end
> +    end
> +    obj.instance_eval('def foo(_a, ...) bar(...) end', __FILE__, __LINE__)
> +    assert_equal [[], {}], obj.foo(1)
> +    assert_equal [[2], {}], obj.foo(1, 2)
> +    assert_equal [[2, 3], {}], obj.foo(1, 2, 3)
> +    assert_equal [[], {a: 1}], obj.foo(1, a: 1)
> +    assert_equal [[2], {a: 1}], obj.foo(1, 2, a: 1)
> +    assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
> +    assert_equal [[2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(...) bar(1, ...) end', __FILE__, __LINE__)
> +    assert_equal [[1], {}], obj.foo
> +    assert_equal [[1, 1], {}], obj.foo(1)
> +    assert_equal [[1, 1, 2], {}], obj.foo(1, 2)
> +    assert_equal [[1, 1, 2, 3], {}], obj.foo(1, 2, 3)
> +    assert_equal [[1], {a: 1}], obj.foo(a: 1)
> +    assert_equal [[1, 1], {a: 1}], obj.foo(1, a: 1)
> +    assert_equal [[1, 1, 2], {a: 1}], obj.foo(1, 2, a: 1)
> +    assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1)
> +    assert_equal [[1, 1, 2, 3], {a: 1}], obj.foo(1, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(a, ...) bar(a, ...) end', __FILE__, __LINE__)
> +    assert_equal [[4], {}], obj.foo(4)
> +    assert_equal [[4, 2], {}], obj.foo(4, 2)
> +    assert_equal [[4, 2, 3], {}], obj.foo(4, 2, 3)
> +    assert_equal [[4], {a: 1}], obj.foo(4, a: 1)
> +    assert_equal [[4, 2], {a: 1}], obj.foo(4, 2, a: 1)
> +    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
> +    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(_a, ...) bar(1, ...) end', __FILE__, __LINE__)
> +    assert_equal [[1], {}], obj.foo(4)
> +    assert_equal [[1, 2], {}], obj.foo(4, 2)
> +    assert_equal [[1, 2, 3], {}], obj.foo(4, 2, 3)
> +    assert_equal [[1], {a: 1}], obj.foo(4, a: 1)
> +    assert_equal [[1, 2], {a: 1}], obj.foo(4, 2, a: 1)
> +    assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1)
> +    assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(_a, _b, ...) bar(...) end', __FILE__, __LINE__)
> +    assert_equal [[], {}], obj.foo(4, 5)
> +    assert_equal [[2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(_a, _b, ...) bar(1, ...) end', __FILE__, __LINE__)
> +    assert_equal [[1], {}], obj.foo(4, 5)
> +    assert_equal [[1, 2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[1, 2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[1], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[1, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[1, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(_a, ...) bar(1, 2, ...) end', __FILE__, __LINE__)
> +    assert_equal [[1, 2], {}], obj.foo(5)
> +    assert_equal [[1, 2, 5], {}], obj.foo(4, 5)
> +    assert_equal [[1, 2, 5, 2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[1, 2, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[1, 2, 5], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[1, 2, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[1, 2, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[1, 2, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(a, b, ...) bar(b, a, ...) end', __FILE__, __LINE__)
> +    assert_equal [[5, 4], {}], obj.foo(4, 5)
> +    assert_equal [[5, 4, 2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[5, 4, 2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[5, 4], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[5, 4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[5, 4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[5, 4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(a, _b, ...) bar(a, ...) end', __FILE__, __LINE__)
> +    assert_equal [[4], {}], obj.foo(4, 5)
> +    assert_equal [[4, 2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[4, 2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[4], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[4, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[4, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +
> +    obj.singleton_class.send(:remove_method, :foo)
> +    obj.instance_eval('def foo(a, ...) bar(a, 1, ...) end', __FILE__, __LINE__)
> +    assert_equal [[4, 1], {}], obj.foo(4)
> +    assert_equal [[4, 1, 5], {}], obj.foo(4, 5)
> +    assert_equal [[4, 1, 5, 2], {}], obj.foo(4, 5, 2)
> +    assert_equal [[4, 1, 5, 2, 3], {}], obj.foo(4, 5, 2, 3)
> +    assert_equal [[4, 1, 5], {a: 1}], obj.foo(4, 5, a: 1)
> +    assert_equal [[4, 1, 5, 2], {a: 1}], obj.foo(4, 5, 2, a: 1)
> +    assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1)
> +    assert_equal [[4, 1, 5, 2, 3], {a: 1}], obj.foo(4, 5, 2, 3, a: 1){|args, kws| [args, kws]}
> +  end
> +
>    private
>  
>    def not_label(x) @result = x; @not_label ||= nil end
> diff -Nru ruby2.7-2.7.2/test/ruby/test_time.rb ruby2.7-2.7.3/test/ruby/test_time.rb
> --- ruby2.7-2.7.2/test/ruby/test_time.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_time.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -1194,6 +1194,20 @@
>      }
>    end
>  
> +  def test_getlocal_utc_offset
> +    t = Time.gm(2000)
> +    assert_equal [00, 30, 21, 31, 12, 1999], t.getlocal("-02:30").to_a[0, 6]
> +    assert_equal [00, 00,  9,  1,  1, 2000], t.getlocal("+09:00").to_a[0, 6]
> +    assert_equal [20, 29, 21, 31, 12, 1999], t.getlocal("-02:30:40").to_a[0, 6]
> +    assert_equal [35, 10,  9,  1,  1, 2000], t.getlocal("+09:10:35").to_a[0, 6]
> +    assert_equal [00, 30, 21, 31, 12, 1999], t.getlocal("-0230").to_a[0, 6]
> +    assert_equal [00, 00,  9,  1,  1, 2000], t.getlocal("+0900").to_a[0, 6]
> +    assert_equal [20, 29, 21, 31, 12, 1999], t.getlocal("-023040").to_a[0, 6]
> +    assert_equal [35, 10,  9,  1,  1, 2000], t.getlocal("+091035").to_a[0, 6]
> +    assert_raise(ArgumentError) {t.getlocal("-02:3040")}
> +    assert_raise(ArgumentError) {t.getlocal("+0910:35")}
> +  end
> +
>    def test_getlocal_nil
>      now = Time.now
>      now2 = nil
> diff -Nru ruby2.7-2.7.2/test/ruby/test_time_tz.rb ruby2.7-2.7.3/test/ruby/test_time_tz.rb
> --- ruby2.7-2.7.2/test/ruby/test_time_tz.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/ruby/test_time_tz.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -749,6 +749,16 @@
>    def self.make_timezone(tzname, abbr, utc_offset, abbr2 = nil, utc_offset2 = nil)
>      TestTimeTZ::TZ.new(tzname, abbr, utc_offset, abbr2, utc_offset2)
>    end
> +
> +  def test_fractional_second
> +    x = Object.new
> +    def x.local_to_utc(t); t + 8*3600; end
> +    def x.utc_to_local(t); t - 8*3600; end
> +
> +    t1 = Time.new(2020,11,11,12,13,14.124r, '-08:00')
> +    t2 = Time.new(2020,11,11,12,13,14.124r, x)
> +    assert_equal(t1, t2)
> +  end
>  end
>  
>  begin
> diff -Nru ruby2.7-2.7.2/test/rubygems/test_bundled_ca.rb ruby2.7-2.7.3/test/rubygems/test_bundled_ca.rb
> --- ruby2.7-2.7.2/test/rubygems/test_bundled_ca.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rubygems/test_bundled_ca.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -51,12 +51,16 @@
>        assert_https('rubygems.org')
>      end
>  
> -    def test_accessing_fastly
> -      assert_https('rubygems.global.ssl.fastly.net')
> +    def test_accessing_www_rubygems
> +      assert_https('www.rubygems.org')
> +    end
> +
> +    def test_accessing_staging
> +      assert_https('staging.rubygems.org')
>      end
>  
>      def test_accessing_new_index
> -      assert_https('fastly.rubygems.org')
> +      assert_https('index.rubygems.org')
>      end
>  
>    end
> diff -Nru ruby2.7-2.7.2/test/rubygems/test_kernel.rb ruby2.7-2.7.3/test/rubygems/test_kernel.rb
> --- ruby2.7-2.7.2/test/rubygems/test_kernel.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rubygems/test_kernel.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -91,6 +91,25 @@
>      refute $:.any? { |p| %r{a-1/bin} =~ p }
>    end
>  
> +  def test_gem_failing_inside_require_doesnt_cause_double_exceptions
> +    File.write("activate.rb", "gem('a', '= 999')\n")
> +
> +    require "open3"
> +
> +    output, _ = Open3.capture2e(
> +      { "GEM_HOME" => Gem.paths.home },
> +      Gem.ruby,
> +      "-I",
> +      File.expand_path("../../lib", __dir__),
> +      "-r",
> +      "./activate.rb"
> +    )
> +
> +    load_errors = output.split("\n").select { |line| line.include?("Could not find")}
> +
> +    assert_equal 1, load_errors.size
> +  end
> +
>    def test_gem_bundler
>      quick_gem 'bundler', '1'
>      quick_gem 'bundler', '2.a'
> diff -Nru ruby2.7-2.7.2/test/rubygems/test_require.rb ruby2.7-2.7.3/test/rubygems/test_require.rb
> --- ruby2.7-2.7.2/test/rubygems/test_require.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/rubygems/test_require.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -45,6 +45,35 @@
>      refute require(path), "'#{path}' was not yet required"
>    end
>  
> +  def test_respect_loaded_features_caching_like_standard_require
> +    dir = Dir.mktmpdir("test_require", @tempdir)
> +
> +    lp1 = File.join dir, 'foo1'
> +    foo1 = File.join lp1, 'foo.rb'
> +
> +    FileUtils.mkdir_p lp1
> +    File.open(foo1, 'w') { |f| f.write "class Object; HELLO = 'foo1' end" }
> +
> +    lp = $LOAD_PATH.dup
> +
> +    $LOAD_PATH.unshift lp1
> +    assert_require 'foo'
> +    assert_equal "foo1", ::Object::HELLO
> +
> +    lp2 = File.join dir, 'foo2'
> +    foo2 = File.join lp2, 'foo.rb'
> +
> +    FileUtils.mkdir_p lp2
> +    File.open(foo2, 'w') { |f| f.write "class Object; HELLO = 'foo2' end" }
> +
> +    $LOAD_PATH.unshift lp2
> +    refute_require 'foo'
> +    assert_equal "foo1", ::Object::HELLO
> +  ensure
> +    $LOAD_PATH.replace lp
> +    Object.send :remove_const, :HELLO if Object.const_defined? :HELLO
> +  end
> +
>    # Providing -I on the commandline should always beat gems
>    def test_dash_i_beats_gems
>      a1 = util_spec "a", "1", {"b" => "= 1"}, "lib/test_gem_require_a.rb"
> @@ -120,6 +149,24 @@
>      Object.send :remove_const, :HELLO if Object.const_defined? :HELLO
>    end
>  
> +  def test_dash_i_respects_default_library_extension_priority
> +    skip "extensions don't quite work on jruby" if Gem.java_platform?
> +
> +    dash_i_ext_arg = util_install_extension_file('a')
> +    dash_i_lib_arg = util_install_ruby_file('a')
> +
> +    lp = $LOAD_PATH.dup
> +
> +    begin
> +      $LOAD_PATH.unshift dash_i_lib_arg
> +      $LOAD_PATH.unshift dash_i_ext_arg
> +      assert_require 'a'
> +      assert_match(/a\.rb$/, $LOADED_FEATURES.last)
> +    ensure
> +      $LOAD_PATH.replace lp
> +    end
> +  end
> +
>    def test_concurrent_require
>      Object.const_set :FILE_ENTERED_LATCH, Latch.new(2)
>      Object.const_set :FILE_EXIT_LATCH, Latch.new(1)
> @@ -364,6 +411,17 @@
>      assert_equal 0, times_called
>    end
>  
> +  def test_second_gem_require_does_not_resolve_path_manually_before_going_through_standard_require
> +    a1 = util_spec "a", "1", nil, "lib/test_gem_require_a.rb"
> +    install_gem a1
> +
> +    assert_require "test_gem_require_a"
> +
> +    stub(:gem_original_require, ->(path) { assert_equal "test_gem_require_a", path }) do
> +      require "test_gem_require_a"
> +    end
> +  end
> +
>    def test_realworld_default_gem
>      testing_ruby_repo = !ENV["GEM_COMMAND"].nil?
>      skip "this test can't work under ruby-core setup" if testing_ruby_repo || java_platform?
> @@ -539,4 +597,50 @@
>      $VERBOSE = old_verbose
>    end
>  
> +  def util_install_extension_file(name)
> +    spec = quick_gem name
> +    util_build_gem spec
> +
> +    spec.extensions << "extconf.rb"
> +    write_file File.join(@tempdir, "extconf.rb") do |io|
> +      io.write <<-RUBY
> +        require "mkmf"
> +        CONFIG['LDSHARED'] = '$(TOUCH) $@ ||'
> +        create_makefile("#{name}")
> +      RUBY
> +    end
> +
> +    write_file File.join(@tempdir, "#{name}.c") do |io|
> +      io.write <<-C
> +        void Init_#{name}() { }
> +      C
> +    end
> +
> +    write_file File.join(@tempdir, "depend")
> +
> +    spec.files += ["extconf.rb", "depend", "#{name}.c"]
> +
> +    so = File.join(spec.gem_dir, "#{name}.#{RbConfig::CONFIG["DLEXT"]}")
> +    refute_path_exists so
> +
> +    path = Gem::Package.build spec
> +    installer = Gem::Installer.at path
> +    installer.install
> +    assert_path_exists so
> +
> +    spec.gem_dir
> +  end
> +
> +  def util_install_ruby_file(name)
> +    dir_lib = Dir.mktmpdir("test_require_lib", @tempdir)
> +    dash_i_lib_arg = File.join dir_lib
> +
> +    a_rb = File.join dash_i_lib_arg, "#{name}.rb"
> +
> +    FileUtils.mkdir_p File.dirname a_rb
> +    File.open(a_rb, 'w') { |f| f.write "# #{name}.rb" }
> +
> +    dash_i_lib_arg
> +  end
> +
>  end
> diff -Nru ruby2.7-2.7.2/test/test_tmpdir.rb ruby2.7-2.7.3/test/test_tmpdir.rb
> --- ruby2.7-2.7.2/test/test_tmpdir.rb	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/test/test_tmpdir.rb	2021-04-05 18:09:38.000000000 +0530
> @@ -86,6 +86,10 @@
>        traversal_path = Array.new(target.count('/')-2, '..').join('/') + traversal_path
>        actual = yield traversal_path
>        assert_not_send([File.absolute_path(actual), :start_with?, target])
> +      [File::SEPARATOR, File::ALT_SEPARATOR].compact.each do |separator|
> +        actual = yield traversal_path.tr('/', separator)
> +        assert_not_send([File.absolute_path(actual), :start_with?, target])
> +      end
>      end
>    end
>  end
> diff -Nru ruby2.7-2.7.2/thread.c ruby2.7-2.7.3/thread.c
> --- ruby2.7-2.7.2/thread.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/thread.c	2021-04-05 18:09:38.000000000 +0530
> @@ -422,11 +422,6 @@
>  {
>      gvl_release(vm);
>      gvl_destroy(vm);
> -    if (0) {
> -        /* may be held by running threads */
> -        rb_native_mutex_destroy(&vm->waitpid_lock);
> -        rb_native_mutex_destroy(&vm->workqueue_lock);
> -    }
>  }
>  
>  void
> diff -Nru ruby2.7-2.7.2/thread_pthread.h ruby2.7-2.7.3/thread_pthread.h
> --- ruby2.7-2.7.2/thread_pthread.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/thread_pthread.h	2021-04-05 18:09:38.000000000 +0530
> @@ -40,6 +40,8 @@
>      } cond;
>  } native_thread_data_t;
>  
> +void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
> +
>  #undef except
>  #undef try
>  #undef leave
> diff -Nru ruby2.7-2.7.2/thread_sync.c ruby2.7-2.7.3/thread_sync.c
> --- ruby2.7-2.7.2/thread_sync.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/thread_sync.c	2021-04-05 18:09:38.000000000 +0530
> @@ -484,7 +484,7 @@
>      }
>      RUBY_VM_CHECK_INTS_BLOCKING(GET_EC());
>      end = time(0) - beg;
> -    return INT2FIX(end);
> +    return TIMET2NUM(end);
>  }
>  
>  /*
> diff -Nru ruby2.7-2.7.2/thread_win32.h ruby2.7-2.7.3/thread_win32.h
> --- ruby2.7-2.7.2/thread_win32.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/thread_win32.h	2021-04-05 18:09:38.000000000 +0530
> @@ -32,5 +32,7 @@
>      HANDLE lock;
>  } rb_global_vm_lock_t;
>  
> +void rb_native_mutex_destroy(rb_nativethread_lock_t *lock);
> +
>  #endif /* RUBY_THREAD_WIN32_H */
>  
> diff -Nru ruby2.7-2.7.2/time.c ruby2.7-2.7.3/time.c
> --- ruby2.7-2.7.2/time.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/time.c	2021-04-05 18:09:38.000000000 +0530
> @@ -2071,7 +2071,7 @@
>      VALUE tmp;
>      if (!NIL_P(tmp = rb_check_string_type(arg))) {
>          int n = 0;
> -        char *s = RSTRING_PTR(tmp);
> +        const char *s = RSTRING_PTR(tmp), *min = NULL, *sec = NULL;
>          if (!rb_enc_str_asciicompat_p(tmp)) {
>  	  invalid_utc_offset:
>              return Qnil;
> @@ -2100,24 +2100,38 @@
>              if (STRNCASECMP("UTC", s, 3) == 0) {
>                  return UTC_ZONE;
>              }
> -            goto invalid_utc_offset;
> -	  case 9:
> -	    if (s[6] != ':') goto invalid_utc_offset;
> -	    if (!ISDIGIT(s[7]) || !ISDIGIT(s[8])) goto invalid_utc_offset;
> -	    n += (s[7] * 10 + s[8] - '0' * 11);
> -            /* fall through */
> -	  case 6:
> -	    if (s[0] != '+' && s[0] != '-') goto invalid_utc_offset;
> -	    if (!ISDIGIT(s[1]) || !ISDIGIT(s[2])) goto invalid_utc_offset;
> -	    if (s[3] != ':') goto invalid_utc_offset;
> -	    if (!ISDIGIT(s[4]) || !ISDIGIT(s[5])) goto invalid_utc_offset;
> -	    if (s[4] > '5') goto invalid_utc_offset;
> -	    break;
> +            break; /* +HH */
> +          case 5: /* +HHMM */
> +            min = s+3;
> +            break;
> +          case 6: /* +HH:MM */
> +            min = s+4;
> +            break;
> +          case 7: /* +HHMMSS */
> +            sec = s+5;
> +            min = s+3;
> +            break;
> +          case 9: /* +HH:MM:SS */
> +            sec = s+7;
> +            min = s+4;
> +            break;
>  	  default:
>  	    goto invalid_utc_offset;
>  	}
> +        if (sec) {
> +            if (sec == s+7 && *(sec-1) != ':') goto invalid_utc_offset;
> +            if (!ISDIGIT(sec[0]) || !ISDIGIT(sec[1])) goto invalid_utc_offset;
> +            n += (sec[0] * 10 + sec[1] - '0' * 11);
> +        }
> +        if (min) {
> +            if (min == s+4 && *(min-1) != ':') goto invalid_utc_offset;
> +            if (!ISDIGIT(min[0]) || !ISDIGIT(min[1])) goto invalid_utc_offset;
> +            if (min[0] > '5') goto invalid_utc_offset;
> +            n += (min[0] * 10 + min[1] - '0' * 11) * 60;
> +        }
> +        if (s[0] != '+' && s[0] != '-') goto invalid_utc_offset;
> +        if (!ISDIGIT(s[1]) || !ISDIGIT(s[2])) goto invalid_utc_offset;
>          n += (s[1] * 10 + s[2] - '0' * 11) * 3600;
> -        n += (s[4] * 10 + s[5] - '0' * 11) * 60;
>          if (s[0] == '-')
>              n = -n;
>          return INT2FIX(n);
> @@ -5456,6 +5470,7 @@
>      ttm = DATA_PTR(tm);
>      v = &vtm;
>      GMTIMEW(ttm->timew = tobj->timew, v);
> +    ttm->timew = wsub(ttm->timew, v->subsecx);
>      v->subsecx = INT2FIX(0);
>      v->zone = Qnil;
>      ttm->vtm = *v;
> diff -Nru ruby2.7-2.7.2/version.h ruby2.7-2.7.3/version.h
> --- ruby2.7-2.7.2/version.h	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/version.h	2021-04-05 18:09:38.000000000 +0530
> @@ -1,12 +1,12 @@
>  # define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR
>  # define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
> -#define RUBY_VERSION_TEENY 2
> +#define RUBY_VERSION_TEENY 3
>  #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR
> -#define RUBY_PATCHLEVEL 137
> +#define RUBY_PATCHLEVEL 183
>  
> -#define RUBY_RELEASE_YEAR 2020
> -#define RUBY_RELEASE_MONTH 10
> -#define RUBY_RELEASE_DAY 1
> +#define RUBY_RELEASE_YEAR 2021
> +#define RUBY_RELEASE_MONTH 4
> +#define RUBY_RELEASE_DAY 5
>  
>  #include "ruby/version.h"
>  
> diff -Nru ruby2.7-2.7.2/vm.c ruby2.7-2.7.3/vm.c
> --- ruby2.7-2.7.2/vm.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/vm.c	2021-04-05 18:09:38.000000000 +0530
> @@ -2354,6 +2354,8 @@
>  	if (objspace) {
>  	    rb_objspace_free(objspace);
>  	}
> +        rb_native_mutex_destroy(&vm->waitpid_lock);
> +        rb_native_mutex_destroy(&vm->workqueue_lock);
>  	/* after freeing objspace, you *can't* use ruby_xfree() */
>  	ruby_mimfree(vm);
>  	ruby_current_vm_ptr = NULL;
> diff -Nru ruby2.7-2.7.2/vm_exec.c ruby2.7-2.7.3/vm_exec.c
> --- ruby2.7-2.7.2/vm_exec.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/vm_exec.c	2021-04-05 18:09:38.000000000 +0530
> @@ -27,6 +27,9 @@
>  #elif defined(__GNUC__) && defined(__powerpc64__)
>  #define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("r" reg)
>  
> +#elif defined(__GNUC__) && defined(__aarch64__)
> +#define DECL_SC_REG(type, r, reg) register type reg_##r __asm__("x" reg)
> +
>  #else
>  #define DECL_SC_REG(type, r, reg) register type reg_##r
>  #endif
> @@ -74,6 +77,11 @@
>      DECL_SC_REG(rb_control_frame_t *, cfp, "15");
>  #define USE_MACHINE_REGS 1
>  
> +#elif defined(__GNUC__) && defined(__aarch64__)
> +    DECL_SC_REG(const VALUE *, pc, "19");
> +    DECL_SC_REG(rb_control_frame_t *, cfp, "20");
> +#define USE_MACHINE_REGS 1
> +
>  #else
>      register rb_control_frame_t *reg_cfp;
>      const VALUE *reg_pc;
> diff -Nru ruby2.7-2.7.2/vm_insnhelper.c ruby2.7-2.7.3/vm_insnhelper.c
> --- ruby2.7-2.7.2/vm_insnhelper.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/vm_insnhelper.c	2021-04-05 18:09:38.000000000 +0530
> @@ -2794,8 +2794,8 @@
>      return cfp;
>  }
>  
> -static VALUE
> -find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
> +MJIT_FUNC_EXPORTED VALUE
> +rb_find_defined_class_by_owner(VALUE current_class, VALUE target_owner)
>  {
>      VALUE klass = current_class;
>  
> @@ -2820,7 +2820,7 @@
>      const rb_callable_method_entry_t *cme;
>  
>      if (orig_me->defined_class == 0) {
> -	VALUE defined_class = find_defined_class_by_owner(me->defined_class, orig_me->owner);
> +        VALUE defined_class = rb_find_defined_class_by_owner(me->defined_class, orig_me->owner);
>  	VM_ASSERT(RB_TYPE_P(orig_me->owner, T_MODULE));
>  	cme = rb_method_entry_complement_defined_class(orig_me, me->called_id, defined_class);
>  
> diff -Nru ruby2.7-2.7.2/vm_method.c ruby2.7-2.7.3/vm_method.c
> --- ruby2.7-2.7.2/vm_method.c	2020-10-01 17:45:38.000000000 +0530
> +++ ruby2.7-2.7.3/vm_method.c	2021-04-05 18:09:38.000000000 +0530
> @@ -738,13 +738,17 @@
>  }
>  
>  static inline rb_method_entry_t*
> -search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
> +search_method0(VALUE klass, ID id, VALUE *defined_class_ptr, bool skip_refined)
>  {
>      rb_method_entry_t *me;
>  
>      for (; klass; klass = RCLASS_SUPER(klass)) {
>  	RB_DEBUG_COUNTER_INC(mc_search_super);
> -	if ((me = lookup_method_table(klass, id)) != 0) break;
> +	if ((me = lookup_method_table(klass, id)) != 0) {
> +	    if (!skip_refined || me->def->type != VM_METHOD_TYPE_REFINED) {
> +		break;
> +	    }
> +	}
>      }
>  
>      if (defined_class_ptr)
> @@ -813,6 +817,12 @@
>      }
>  }
>  
> +static inline rb_method_entry_t*
> +search_method(VALUE klass, ID id, VALUE *defined_class_ptr)
> +{
> +    return search_method0(klass, id, defined_class_ptr, false);
> +}
> +
>  static rb_method_entry_t *
>  method_entry_get(VALUE klass, ID id, VALUE *defined_class_ptr)
>  {
> @@ -1068,7 +1078,7 @@
>      VALUE defined_class;
>      VALUE origin_class = RCLASS_ORIGIN(klass);
>  
> -    me = search_method(origin_class, name, &defined_class);
> +    me = search_method0(origin_class, name, &defined_class, true);
>      if (!me && RB_TYPE_P(klass, T_MODULE)) {
>  	me = search_method(rb_cObject, name, &defined_class);
>      }
> @@ -1774,7 +1784,7 @@
>  
>  /*
>   *  call-seq:
> - *     ruby2_keywords(method_name, ...)    -> self
> + *     ruby2_keywords(method_name, ...)    -> nil
>   *
>   *  For the given method names, marks the method as passing keywords through
>   *  a normal argument splat.  This should only be called on methods that
> @@ -1864,7 +1874,7 @@
>                      else {
>                          rb_warn("Skipping set of ruby2_keywords flag for %s (method accepts keywords or method does not accept argument splat)", rb_id2name(name));
>                      }
> -                    return Qnil;
> +                    break;
>                  }
>                }
>                /* fallthrough */




-- 
Sebastian Ramacher


Reply to: