diff --git a/file.c b/file.c index 77facacfcf202a..e9e2dd134030bf 100644 --- a/file.c +++ b/file.c @@ -3397,6 +3397,16 @@ rb_file_expand_path_internal(VALUE fname, VALUE dname, int abs_mode, int long_na #define EXPAND_PATH_BUFFER() rb_usascii_str_new(0, MAXPATHLEN + 2) +static VALUE +str_shrink(VALUE str) +{ + rb_str_resize(str, RSTRING_LEN(str)); + return str; +} + +#define expand_path(fname, dname, abs_mode, long_name, result) \ + str_shrink(rb_file_expand_path_internal(fname, dname, abs_mode, long_name, result)) + #define check_expand_path_args(fname, dname) \ (((fname) = rb_get_path(fname)), \ (void)(NIL_P(dname) ? (dname) : ((dname) = rb_get_path(dname)))) @@ -3411,13 +3421,13 @@ VALUE rb_file_expand_path(VALUE fname, VALUE dname) { check_expand_path_args(fname, dname); - return rb_file_expand_path_internal(fname, dname, 0, 1, EXPAND_PATH_BUFFER()); + return expand_path(fname, dname, 0, 1, EXPAND_PATH_BUFFER()); } VALUE rb_file_expand_path_fast(VALUE fname, VALUE dname) { - return rb_file_expand_path_internal(fname, dname, 0, 0, EXPAND_PATH_BUFFER()); + return expand_path(fname, dname, 0, 0, EXPAND_PATH_BUFFER()); } /* @@ -3465,7 +3475,7 @@ VALUE rb_file_absolute_path(VALUE fname, VALUE dname) { check_expand_path_args(fname, dname); - return rb_file_expand_path_internal(fname, dname, 1, 1, EXPAND_PATH_BUFFER()); + return expand_path(fname, dname, 1, 1, EXPAND_PATH_BUFFER()); } /* @@ -5408,6 +5418,7 @@ is_explicit_relative(const char *path) static VALUE copy_path_class(VALUE path, VALUE orig) { + str_shrink(path); RBASIC_SET_CLASS(path, rb_obj_class(orig)); OBJ_FREEZE(path); return path; diff --git a/string.c b/string.c index 99b7e37f58797e..bd1e3bcfdd5cec 100644 --- a/string.c +++ b/string.c @@ -2034,9 +2034,11 @@ rb_str_resize(VALUE str, long len) independent = str_independent(str); ENC_CODERANGE_CLEAR(str); slen = RSTRING_LEN(str); - if (len != slen) { + + { const int termlen = TERM_LEN(str); if (STR_EMBED_P(str)) { + if (len == slen) return str; if (len + termlen <= RSTRING_EMBED_LEN_MAX + 1) { STR_SET_EMBED_LEN(str, len); TERM_FILL(RSTRING(str)->as.ary + len, termlen); @@ -2056,11 +2058,13 @@ rb_str_resize(VALUE str, long len) return str; } else if (!independent) { + if (len == slen) return str; str_make_independent_expand(str, len - slen); } - else if (slen < len || slen - len > 1024) { + else if (slen < len || (RSTRING(str)->as.heap.aux.capa - len) > (len < 1024 ? len : 1024)) { REALLOC_N(RSTRING(str)->as.heap.ptr, char, len + termlen); } + else if (len == slen) return str; if (!STR_NOCAPA_P(str)) { RSTRING(str)->as.heap.aux.capa = len; } diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb index 2c945eac626f19..a64a956afd73d8 100644 --- a/test/ruby/test_file_exhaustive.rb +++ b/test/ruby/test_file_exhaustive.rb @@ -458,6 +458,15 @@ def test_expand_path end end + def test_expand_path_memsize + bug9934 = '[ruby-core:63114] [Bug #9934]' + require "objspace" + path = File.expand_path("/foo") + assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize, bug9934) + path = File.expand_path("/a"*25) + assert_equal(51, ObjectSpace.memsize_of(path), bug9934) + end + def test_expand_path_encoding drive = (DRIVE ? 'C:' : '') if Encoding.find("filesystem") == Encoding::CP1251