[前][次][番号順一覧][スレッド一覧]

ruby-changes:49252

From: nagachika <ko1@a...>
Date: Thu, 21 Dec 2017 00:20:20 +0900 (JST)
Subject: [ruby-changes:49252] nagachika:r61367 (ruby_2_4): merge revision(s) 58146, 58150, 58156: [Backport #13276]

nagachika	2017-12-21 00:20:15 +0900 (Thu, 21 Dec 2017)

  New Revision: 61367

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=61367

  Log:
    merge revision(s) 58146,58150,58156: [Backport #13276]
    
    error.c: refactor warning messages
    
    * error.c (with_warning_string): extract building warning message
      string from variadic arguments.
    
    * error.c (syserr_warning): write warning message with the system
      error message.
    
    error.c: warning functions
    
    * error.c: define warning functions in all combinations of
      * no errno, system errno, argument
      * without/with encoding
      * enabled/disabled by default
    
    dir.c: err at glob failure
    
    * dir.c (glob_helper): raise a SystemCallError exception when
      opendir() failed, except for ENOENT, ENOTDIR, and EACCES.  this
      behavior predates 1.0; the comments in glob.c claimed that
      glob() returned -1 on error but actualy the pointer to a global
      variable, then dir_glob() did check only -1 as the comments, and
      ignored actual errors.  [ruby-core:80226] [Bug #13276]
    
    dir.c: ruby_glob_funcs_t

  Modified directories:
    branches/ruby_2_4/
  Modified files:
    branches/ruby_2_4/dir.c
    branches/ruby_2_4/error.c
    branches/ruby_2_4/internal.h
    branches/ruby_2_4/test/ruby/test_dir.rb
    branches/ruby_2_4/version.h
Index: ruby_2_4/dir.c
===================================================================
--- ruby_2_4/dir.c	(revision 61366)
+++ ruby_2_4/dir.c	(revision 61367)
@@ -1248,6 +1248,12 @@ to_be_ignored(int e) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1248
 #define STAT(p, s)	stat((p), (s))
 #endif
 
+typedef int ruby_glob_errfunc(const char*, VALUE, const void*, int);
+typedef struct {
+    ruby_glob_func *match;
+    ruby_glob_errfunc *error;
+} ruby_glob_funcs_t;
+
 /* System call with warning */
 static int
 do_stat(const char *path, struct stat *pst, int flags, rb_encoding *enc)
@@ -1274,7 +1280,8 @@ do_lstat(const char *path, struct stat * https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1280
 #endif
 
 static DIR *
-do_opendir(const char *path, int flags, rb_encoding *enc)
+do_opendir(const char *path, int flags, rb_encoding *enc,
+	   ruby_glob_errfunc *errfunc, VALUE arg, int *status)
 {
     DIR *dirp;
 #ifdef _WIN32
@@ -1295,7 +1302,12 @@ do_opendir(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1302
 	    e = errno;
 	    /* fallback */
 	  case 0:
+	    *status = 0;
 	    if (to_be_ignored(e)) break;
+	    if (errfunc) {
+		*status = (*errfunc)(path, arg, enc, e);
+		break;
+	    }
 	    sys_warning(path, enc);
 	}
     }
@@ -1705,6 +1717,61 @@ glob_func_caller(VALUE val) https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1717
     return Qnil;
 }
 
+struct glob_error_args {
+    const char *path;
+    rb_encoding *enc;
+    int error;
+};
+
+static VALUE
+glob_func_warning(VALUE val)
+{
+    struct glob_error_args *arg = (struct glob_error_args *)val;
+    rb_syserr_enc_warning(arg->error, arg->enc, "%s", arg->path);
+    return Qnil;
+}
+
+#if 0
+static int
+rb_glob_warning(const char *path, VALUE a, const void *enc, int error)
+{
+    int status;
+    struct glob_error_args args;
+
+    args.path = path;
+    args.enc = enc;
+    args.error = error;
+    rb_protect(glob_func_warning, (VALUE)&args, &status);
+    return status;
+}
+#endif
+
+static VALUE
+glob_func_error(VALUE val)
+{
+    struct glob_error_args *arg = (struct glob_error_args *)val;
+    VALUE path = rb_enc_str_new_cstr(arg->path, arg->enc);
+    rb_syserr_fail_str(arg->error, path);
+    return Qnil;
+}
+
+static int
+rb_glob_error(const char *path, VALUE a, const void *enc, int error)
+{
+    int status;
+    struct glob_error_args args;
+    VALUE (*errfunc)(VALUE) = glob_func_error;
+
+    if (error == EACCES) {
+	errfunc = glob_func_warning;
+    }
+    args.path = path;
+    args.enc = enc;
+    args.error = error;
+    rb_protect(errfunc, (VALUE)&args, &status);
+    return status;
+}
+
 static inline int
 dirent_match(const char *pat, rb_encoding *enc, const char *name, const struct dirent *dp, int flags)
 {
@@ -1726,7 +1793,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1793
     struct glob_pattern **beg,
     struct glob_pattern **end,
     int flags,
-    ruby_glob_func *func,
+    const ruby_glob_funcs_t *funcs,
     VALUE arg,
     rb_encoding *enc)
 {
@@ -1785,13 +1852,13 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1852
 	    }
 	}
 	if (match_all && pathtype > path_noent) {
-	    status = glob_call_func(func, path, arg, enc);
+	    status = glob_call_func(funcs->match, path, arg, enc);
 	    if (status) return status;
 	}
 	if (match_dir && pathtype == path_directory) {
 	    char *tmp = join_path(path, pathlen, dirsep, "", 0);
 	    if (!tmp) return -1;
-	    status = glob_call_func(func, tmp, arg, enc);
+	    status = glob_call_func(funcs->match, tmp, arg, enc);
 	    GLOB_FREE(tmp);
 	    if (status) return status;
 	}
@@ -1810,12 +1877,14 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1877
 	if (cur + 1 == end && (*cur)->type <= ALPHA) {
 	    plainname = join_path(path, pathlen, dirsep, (*cur)->str, strlen((*cur)->str));
 	    if (!plainname) return -1;
-	    dirp = do_opendir(plainname, flags, enc);
+	    dirp = do_opendir(plainname, flags, enc, funcs->error, arg, &status);
 	    GLOB_FREE(plainname);
 	}
 	else
+# else
+	    ;
 # endif
-	dirp = do_opendir(*path ? path : ".", flags, enc);
+	dirp = do_opendir(*path ? path : ".", flags, enc, funcs->error, arg, &status);
 	if (dirp == NULL) {
 # if FNM_SYSCASE || NORMALIZE_UTF8PATH
 	    if ((magical < 2) && !recursive && (errno == EACCES)) {
@@ -1823,7 +1892,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1892
 		goto literally;
 	    }
 # endif
-	    return 0;
+	    return status;
 	}
 	IF_NORMALIZE_UTF8PATH(norm_p = need_normalization(dirp, *path ? path : "."));
 
@@ -1923,7 +1992,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L1992
 
 	    status = glob_helper(buf, name - buf + namlen, 1,
 				 new_pathtype, new_beg, new_end,
-				 flags, func, arg, enc);
+				 flags, funcs, arg, enc);
 	    GLOB_FREE(buf);
 	    GLOB_FREE(new_beg);
 	    if (status) break;
@@ -1983,11 +2052,12 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2052
 		    long base = pathlen + (dirsep != 0);
 		    buf = replace_real_basename(buf, base, enc, IF_NORMALIZE_UTF8PATH(1)+0,
 						flags, &new_pathtype);
+		    if (!buf) break;
 		}
 #endif
 		status = glob_helper(buf, pathlen + strlen(buf + pathlen), 1,
 				     new_pathtype, new_beg, new_end,
-				     flags, func, arg, enc);
+				     flags, funcs, arg, enc);
 		GLOB_FREE(buf);
 		GLOB_FREE(new_beg);
 		if (status) break;
@@ -2001,7 +2071,9 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2071
 }
 
 static int
-ruby_glob0(const char *path, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc)
+ruby_glob0(const char *path, int flags,
+	   const ruby_glob_funcs_t *funcs, VALUE arg,
+	   rb_encoding *enc)
 {
     struct glob_pattern *list;
     const char *root, *start;
@@ -2029,7 +2101,7 @@ ruby_glob0(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2101
 	return -1;
     }
     status = glob_helper(buf, n, 0, path_unknown, &list, &list + 1,
-			 flags, func, arg, enc);
+			 flags, funcs, arg, enc);
     glob_free_pattern(list);
     GLOB_FREE(buf);
 
@@ -2039,8 +2111,11 @@ ruby_glob0(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2111
 int
 ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
 {
-    return ruby_glob0(path, flags & ~GLOB_VERBOSE, func, arg,
-		      rb_ascii8bit_encoding());
+    ruby_glob_funcs_t funcs;
+    funcs.match = func;
+    funcs.error = NULL;
+    return ruby_glob0(path, flags & ~GLOB_VERBOSE,
+		      &funcs, arg, rb_ascii8bit_encoding());
 }
 
 static int
@@ -2054,6 +2129,10 @@ rb_glob_caller(const char *path, VALUE a https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2129
     return status;
 }
 
+static const ruby_glob_funcs_t rb_glob_funcs = {
+    rb_glob_caller, rb_glob_error,
+};
+
 void
 rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
 {
@@ -2064,8 +2143,8 @@ rb_glob(const char *path, void (*func)(c https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2143
     args.value = arg;
     args.enc = rb_ascii8bit_encoding();
 
-    status = ruby_glob0(path, GLOB_VERBOSE, rb_glob_caller, (VALUE)&args,
-			args.enc);
+    status = ruby_glob0(path, GLOB_VERBOSE, &rb_glob_funcs,
+			(VALUE)&args, args.enc);
     if (status) GLOB_JUMP_TAG(status);
 }
 
@@ -2143,7 +2222,7 @@ ruby_brace_expand(const char *str, int f https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2222
 }
 
 struct brace_args {
-    ruby_glob_func *func;
+    ruby_glob_funcs_t funcs;
     VALUE value;
     int flags;
 };
@@ -2153,7 +2232,7 @@ glob_brace(const char *path, VALUE val, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2232
 {
     struct brace_args *arg = (struct brace_args *)val;
 
-    return ruby_glob0(path, arg->flags, arg->func, arg->value, enc);
+    return ruby_glob0(path, arg->flags, &arg->funcs, arg->value, enc);
 }
 
 int
@@ -2162,7 +2241,8 @@ ruby_brace_glob_with_enc(const char *str https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2241
     struct brace_args args;
 
     flags &= ~GLOB_VERBOSE;
-    args.func = func;
+    args.funcs.match = func;
+    args.funcs.error = NULL;
     args.value = arg;
     args.flags = flags;
     return ruby_brace_expand(str, flags, glob_brace, (VALUE)&args, enc);
@@ -2184,7 +2264,8 @@ push_caller(const char *path, VALUE val, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/dir.c#L2264
 {
     struct push_glob_args *arg = (struct push_glob_args *)val;
 
-    return ruby_glob0(path, arg->flags, rb_glob_caller, (VALUE)&arg->glob, enc);
+    return ruby_glob0(path, arg->flags, &rb_glob_funcs,
+		      (VALUE)&arg->glob, enc);
 }
 
 static int
Index: ruby_2_4/test/ruby/test_dir.rb
===================================================================
--- ruby_2_4/test/ruby/test_dir.rb	(revision 61366)
+++ ruby_2_4/test/ruby/test_dir.rb	(revision 61367)
@@ -184,6 +184,24 @@ class TestDir < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/ruby_2_4/test/ruby/test_dir.rb#L184
     end
   end
 
+  if Process.const_defined?(:RLIMIT_NOFILE)
+    def test_glob_too_may_open_files
+      assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}", chdir: @root)
+      begin;
+        n = 16
+        Process.setrlimit(Process::RLIMIT_NOFILE, n)
+        files = []
+        begin
+          n.times {files << File.open('b')}
+        rescue Errno::EMFILE, Errno::ENFILE => e
+        end
+        assert_raise(e.class) {
+          Dir.glob('*')
+        }
+      end;
+    end
+  end
+
   def assert_entries(entries)
     entries.sort!
     assert_equal(%w(. ..) + ("a".."z").to_a, entries)
Index: ruby_2_4/internal.h
===================================================================
--- ruby_2_4/internal.h	(revision 61366)
+++ ruby_2_4/internal.h	(revision 61367)
@@ -1015,9 +1015,17 @@ VALUE rb_check_backtrace(VALUE); https://github.com/ruby/ruby/blob/trunk/ruby_2_4/internal.h#L1015
 NORETURN(void rb_async_bug_errno(const char *,int));
 const char *rb_builtin_type_name(int t);
 const char *rb_builtin_class_name(VALUE x);
+PRINTF_ARGS(void rb_sys_warn(const char *fmt, ...), 1, 2);
+PRINTF_ARGS(void rb_syserr_warn(int err, const char *fmt, ...), 2, 3);
 PRINTF_ARGS(void rb_enc_warn(rb_encoding *enc, const char *fmt, ...), 2, 3);
+PRINTF_ARGS(void rb_sys_enc_warn(rb_encoding *enc, const char *fmt, ...), 2, 3);
+PRINTF_ARGS(void rb_syserr_enc_warn(int err, rb_encoding *enc, const char *fmt, ...), 3, 4);
+PRINTF_ARGS(void rb_sys_warning(const char *fmt, ...), 1, 2);
+PRINTF_ARGS(void rb_syserr_warning(int err, const char *fmt, ...), 2, 3);
 PRINTF_ARGS(void rb_enc_warning(rb_encoding *enc, const char *fmt, ...), 2, 3);
 PRINTF_ARGS(void rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...), 2, 3);
+PRINTF_ARGS(void rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...), 3, 4);
+
 VALUE rb_name_err_new(VALUE mesg, VALUE recv, VALUE method);
 #define rb_name_err_raise_str(mesg, recv, name) \
     rb_exc_raise(rb_name_err_new(mesg, recv, name))
Index: ruby_2_4/version.h
===================================================================
--- ruby_2_4/version.h	(revision 61366)
+++ ruby_2_4/version.h	(revision 61367)
@@ -1,10 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_4/version.h#L1
 #define RUBY_VERSION "2.4.4"
-#define RUBY_RELEASE_DATE "2017-12-20"
-#define RUBY_PATCHLEVEL 214
+#define RUBY_RELEASE_DATE "2017-12-21"
+#define RUBY_PATCHLEVEL 215
 
 #define RUBY_RELEASE_YEAR 2017
 #define RUBY_RELEASE_MONTH 12
-#define RUBY_RELEASE_DAY 20
+#define RUBY_RELEASE_DAY 21
 
 #include "ruby/version.h"
 
Index: ruby_2_4/error.c
===================================================================
--- ruby_2_4/error.c	(revision 61366)
+++ ruby_2_4/error.c	(revision 61367)
@@ -217,62 +217,52 @@ warning_string(rb_encoding *enc, const c https://github.com/ruby/ruby/blob/trunk/ruby_2_4/error.c#L217
 			 fmt, args);
 }
 
+#define with_warning_string(mesg, enc, fmt) \
+    VALUE mesg; \
+    va_list args; va_start(args, fmt); \
+    mesg = warning_string(enc, fmt, args); \
+    va_end(args);
+
 void
 rb_warn(const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-
-    if (NIL_P(ruby_verbose)) return;
-
-    va_start(args, fmt);
-    mesg = warning_string(0, fmt, args);
-    va_end(args);
-    rb_write_warning_str(mesg);
+    if (!NIL_P(ruby_verbose)) {
+	with_warning_string(mesg, 0, fmt) {
+	    rb_write_warning_str(mesg);
+	}
+    }
 }
 
 void
 rb_enc_warn(rb_encoding *enc, const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-
-    if (NIL_P(ruby_verbose)) return;
-
-    va_start(args, fmt);
-    mesg = warning_string(enc, fmt, args);
-    va_end(args);
-    rb_write_warning_str(mesg);
+    if (!NIL_P(ruby_verbose)) {
+	with_warning_string(mesg, enc, fmt) {
+	    rb_write_warning_str(mesg);
+	}
+    }
 }
 
 /* rb_warning() reports only in verbose mode */
 void
 rb_warning(const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-
-    if (!RTEST(ruby_verbose)) return;
-
-    va_start(args, fmt);
-    mesg = warning_string(0, fmt, args);
-    va_end(args);
-    rb_write_warning_str(mesg);
+    if (RTEST(ruby_verbose)) {
+	with_warning_string(mesg, 0, fmt) {
+	    rb_write_warning_str(mesg);
+	}
+    }
 }
 
 #if 0
 void
 rb_enc_warning(rb_encoding *enc, const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-
-    if (!RTEST(ruby_verbose)) return;
-
-    va_start(args, fmt);
-    mesg = warning_string(enc, fmt, args);
-    va_end(args);
-    rb_write_warning_str(mesg);
+    if (RTEST(ruby_verbose)) {
+	with_warning_string(mesg, enc, fmt) {
+	    rb_write_warning_str(mesg);
+	}
+    }
 }
 #endif
 
@@ -2394,44 +2384,104 @@ rb_mod_syserr_fail_str(VALUE mod, int e, https://github.com/ruby/ruby/blob/trunk/ruby_2_4/error.c#L2384
     rb_exc_raise(exc);
 }
 
+static void
+syserr_warning(VALUE mesg, int err)
+{
+    rb_str_set_len(mesg, RSTRING_LEN(mesg)-1);
+    rb_str_catf(mesg, ": %s\n", strerror(err));
+    rb_write_warning_str(mesg);
+}
+
+#if 0
 void
-rb_sys_warning(const char *fmt, ...)
+rb_sys_warn(const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-    int errno_save;
+    if (!NIL_P(ruby_verbose)) {
+	int errno_save = errno;
+	with_warning_string(mesg, 0, fmt) {
+	    syserr_warning(mesg, errno_save);
+	}
+	errno = errno_save;
+    }
+}
 
-    errno_save = errno;
+void
+rb_syserr_warn(int err, const char *fmt, ...)
+{
+    if (!NIL_P(ruby_verbose)) {
+	with_warning_string(mesg, 0, fmt) {
+	    syserr_warning(mesg, err);
+	}
+    }
+}
 
-    if (!RTEST(ruby_verbose)) return;
+void
+rb_sys_enc_warn(rb_encoding *enc, const char *fmt, ...)
+{
+    if (!NIL_P(ruby_verbose)) {
+	int errno_save = errno;
+	with_warning_string(mesg, enc, fmt) {
+	    syserr_warning(mesg, errno_save);
+	}
+	errno = errno_save;
+    }
+}
 
-    va_start(args, fmt);
-    mesg = warning_string(0, fmt, args);
-    va_end(args);
-    rb_str_set_len(mesg, RSTRING_LEN(mesg)-1);
-    rb_str_catf(mesg, ": %s\n", strerror(errno_save));
-    rb_write_warning_str(mesg);
-    errno = errno_save;
+void
+rb_syserr_enc_warn(int err, rb_encoding *enc, const char *fmt, ...)
+{
+    if (!NIL_P(ruby_verbose)) {
+	with_warning_string(mesg, enc, fmt) {
+	    syserr_warning(mesg, err);
+	}
+    }
 }
+#endif
 
 void
-rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...)
+rb_sys_warning(const char *fmt, ...)
 {
-    VALUE mesg;
-    va_list args;
-    int errno_save;
+    if (RTEST(ruby_verbose)) {
+	int errno_save = errno;
+	with_warning_string(mesg, 0, fmt) {
+	    syserr_warning(mesg, errno_save);
+	}
+	errno = errno_save;
+    }
+}
 
-    errno_save = errno;
+#if 0
+void
+rb_syserr_warning(int err, const char *fmt, ...)
+{
+    if (RTEST(ruby_verbose)) {
+	with_warning_string(mesg, 0, fmt) {
+	    syserr_warning(mesg, err);
+	}
+    }
+}
+#endif
 
-    if (!RTEST(ruby_verbose)) return;
+void
+rb_sys_enc_warning(rb_encoding *enc, const char *fmt, ...)
+{
+    if (RTEST(ruby_verbose)) {
+	int errno_save = errno;
+	with_warning_string(mesg, enc, fmt) {
+	    syserr_warning(mesg, errno_save);
+	}
+	errno = errno_save;
+    }
+}
 
-    va_start(args, fmt);
-    mesg = warning_string(enc, fmt, args);
-    va_end(args);
-    rb_str_set_len(mesg, RSTRING_LEN(mesg)-1);
-    rb_str_catf(mesg, ": %s\n", strerror(errno_save));
-    rb_write_warning_str(mesg);
-    errno = errno_save;
+void
+rb_syserr_enc_warning(int err, rb_encoding *enc, const char *fmt, ...)
+{
+    if (RTEST(ruby_verbose)) {
+	with_warning_string(mesg, enc, fmt) {
+	    syserr_warning(mesg, err);
+	}
+    }
 }
 
 void
Index: ruby_2_4
===================================================================
--- ruby_2_4	(revision 61366)
+++ ruby_2_4	(revision 61367)

Property changes on: ruby_2_4
___________________________________________________________________
Modified: svn:mergeinfo
## -0,0 +0,1 ##
   Merged /trunk:r58146,58150,58156

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]