-
-
Save burke/fde10664779077ba495e4c7be92d44e1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit bdbb00871f63edd931b6d8bb6a2ea0061e9b1daa | |
Author: Burke Libbey <burke@libbey.me> | |
Date: Tue Mar 28 12:39:53 2017 -0400 | |
defer load check | |
diff --git a/file.c b/file.c | |
index c57447a..2598574 100644 | |
--- a/file.c | |
+++ b/file.c | |
@@ -5796,11 +5796,11 @@ rb_find_file_ext_safe(VALUE *filep, const char *const *ext, int safe_level) | |
VALUE | |
rb_find_file(VALUE path) | |
{ | |
- return rb_find_file_safe(path, rb_safe_level()); | |
+ return rb_find_file_safe(path, rb_safe_level(), 0); | |
} | |
VALUE | |
-rb_find_file_safe(VALUE path, int safe_level) | |
+rb_find_file_safe(VALUE path, int safe_level, int defer_load_check) | |
{ | |
VALUE tmp, load_path; | |
const char *f = StringValueCStr(path); | |
@@ -5820,7 +5820,9 @@ rb_find_file_safe(VALUE path, int safe_level) | |
if (safe_level >= 1 && !fpath_check(path)) { | |
rb_raise(rb_eSecurityError, "loading from unsafe path %s", f); | |
} | |
- if (!rb_file_load_ok(f)) return 0; | |
+ if (!defer_load_check && !rb_file_load_ok(f)) { | |
+ return 0; | |
+ } | |
if (!expanded) | |
path = copy_path_class(file_expand_path_1(path), path); | |
return path; | |
diff --git a/include/ruby/intern.h b/include/ruby/intern.h | |
index aec2d52..c7a952e 100644 | |
--- a/include/ruby/intern.h | |
+++ b/include/ruby/intern.h | |
@@ -478,7 +478,7 @@ VALUE rb_file_s_absolute_path(int, const VALUE *); | |
VALUE rb_file_absolute_path(VALUE, VALUE); | |
VALUE rb_file_dirname(VALUE fname); | |
int rb_find_file_ext_safe(VALUE*, const char* const*, int); | |
-VALUE rb_find_file_safe(VALUE, int); | |
+VALUE rb_find_file_safe(VALUE, int, int); | |
int rb_find_file_ext(VALUE*, const char* const*); | |
VALUE rb_find_file(VALUE); | |
VALUE rb_file_directory_p(VALUE,VALUE); | |
diff --git a/load.c b/load.c | |
index 70c7345..a65446a 100644 | |
--- a/load.c | |
+++ b/load.c | |
@@ -859,7 +859,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
if (loading) *path = rb_filesystem_str_new_cstr(loading); | |
return 'r'; | |
} | |
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(fname, safe_level, 1)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading) | |
*path = tmp; | |
@@ -884,7 +884,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
#else | |
rb_str_cat2(tmp, DLEXT); | |
OBJ_FREEZE(tmp); | |
- if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(tmp, safe_level, 0)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) | |
*path = tmp; | |
@@ -897,7 +897,7 @@ search_required(VALUE fname, volatile VALUE *path, int safe_level) | |
if (loading) *path = rb_filesystem_str_new_cstr(loading); | |
return 's'; | |
} | |
- if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { | |
+ if ((tmp = rb_find_file_safe(fname, safe_level, 0)) != 0) { | |
ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); | |
if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) | |
*path = tmp; | |
diff --git a/ruby.c b/ruby.c | |
index c780937..317797b 100644 | |
--- a/ruby.c | |
+++ b/ruby.c | |
@@ -1762,17 +1762,17 @@ load_file_internal(VALUE argp_v) | |
} | |
static VALUE | |
-open_load_file(VALUE fname_v, int *xflag) | |
+open_load_file(VALUE fname_v, int *xflag, int script) | |
{ | |
const char *fname = StringValueCStr(fname_v); | |
VALUE f; | |
- int e; | |
+ int e = 0; | |
+ int fd = 0; | |
if (RSTRING_LEN(fname_v) == 1 && fname[0] == '-') { | |
f = rb_stdin; | |
} | |
else { | |
- int fd; | |
/* open(2) may block if fname is point to FIFO and it's empty. Let's | |
use O_NONBLOCK. */ | |
#if defined O_NONBLOCK && HAVE_FCNTL && !(O_NONBLOCK & O_ACCMODE) | |
@@ -1795,7 +1795,8 @@ open_load_file(VALUE fname_v, int *xflag) | |
#endif | |
if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) { | |
- rb_load_fail(fname_v, strerror(errno)); | |
+ e = errno; | |
+ goto fail; | |
} | |
rb_update_max_fd(fd); | |
@@ -1803,8 +1804,7 @@ open_load_file(VALUE fname_v, int *xflag) | |
/* disabling O_NONBLOCK */ | |
if (fcntl(fd, F_SETFL, 0) < 0) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
#endif | |
@@ -1813,8 +1813,7 @@ open_load_file(VALUE fname_v, int *xflag) | |
struct stat st; | |
if (fstat(fd, &st) != 0) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
if (S_ISFIFO(st.st_mode)) { | |
/* | |
@@ -1822,18 +1821,36 @@ open_load_file(VALUE fname_v, int *xflag) | |
rb_thread_wait_fd() release GVL. So, it's safe. | |
*/ | |
rb_thread_wait_fd(fd); | |
+ } else if (S_ISDIR(st.st_mode)) { | |
+ e = EISDIR; | |
+ goto fail; | |
+ } else if (!S_ISREG(st.st_mode)) { | |
+ e = ENXIO; | |
+ goto fail; | |
} | |
} | |
-#endif | |
+#else | |
+ /* Note that we've replicated ruby_is_fd_loadable in S_ISFIFO without | |
+ * calling fstat64 twice. */ | |
if (!ruby_is_fd_loadable(fd)) { | |
e = errno; | |
- (void)close(fd); | |
- rb_load_fail(fname_v, strerror(e)); | |
+ goto fail; | |
} | |
+#endif | |
f = rb_io_fdopen(fd, mode, fname); | |
} | |
return f; | |
+fail: | |
+ if (fd > 0) (void)close(fd); | |
+ if (script) { | |
+ /* when we reach this from `$ ruby bad.rb`, show the reason */ | |
+ rb_load_fail(fname_v, strerror(e)); | |
+ } else { | |
+ /* when called from require/load/etc., just show: | |
+ * "cannot load such file", same as `load_failed`. */ | |
+ rb_load_fail(fname_v, "cannot load such file"); | |
+ } | |
} | |
static VALUE | |
@@ -1874,7 +1891,7 @@ load_file(VALUE parser, VALUE fname, int script, struct cmdline_options *opt) | |
arg.opt = opt; | |
arg.xflag = 0; | |
arg.lineno = rb_gv_get("$."); | |
- arg.f = open_load_file(rb_str_encode_ospath(fname), &arg.xflag); | |
+ arg.f = open_load_file(rb_str_encode_ospath(fname), &arg.xflag, script); | |
return (NODE *)rb_ensure(load_file_internal, (VALUE)&arg, | |
restore_load_file, (VALUE)&arg); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment