mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
vm_core.h: fix symbols leak
* vm_core.h (rb_call_info_kw_arg_struct): make keywords a symbols list to get rid of inadvertent creation by variable keyword arguments. [ruby-core:68031] [Bug #10831] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@49517 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e27a538eab
commit
b4f61ad610
5 changed files with 48 additions and 18 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
Fri Feb 6 10:31:50 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* vm_core.h (rb_call_info_kw_arg_struct): make keywords a symbols
|
||||||
|
list to get rid of inadvertent creation by variable keyword
|
||||||
|
arguments. [ruby-core:68031] [Bug #10831]
|
||||||
|
|
||||||
Thu Feb 5 22:42:34 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
Thu Feb 5 22:42:34 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
|
||||||
|
|
||||||
* lib/rubygems: Update to RubyGems HEAD(5c3b6f3).
|
* lib/rubygems: Update to RubyGems HEAD(5c3b6f3).
|
||||||
|
|
10
compile.c
10
compile.c
|
@ -2409,7 +2409,7 @@ compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const
|
||||||
{
|
{
|
||||||
int len = (int)node->nd_alen / 2;
|
int len = (int)node->nd_alen / 2;
|
||||||
rb_call_info_kw_arg_t *kw_arg = (rb_call_info_kw_arg_t *)ruby_xmalloc(sizeof(rb_call_info_kw_arg_t) + sizeof(VALUE) * (len - 1));
|
rb_call_info_kw_arg_t *kw_arg = (rb_call_info_kw_arg_t *)ruby_xmalloc(sizeof(rb_call_info_kw_arg_t) + sizeof(VALUE) * (len - 1));
|
||||||
ID *keywords = kw_arg->keywords;
|
VALUE *keywords = kw_arg->keywords;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
kw_arg->keyword_len = len;
|
kw_arg->keyword_len = len;
|
||||||
|
|
||||||
|
@ -2418,7 +2418,7 @@ compile_array_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE * const
|
||||||
for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
|
for (i=0; node != NULL; i++, node = node->nd_next->nd_next) {
|
||||||
NODE *key_node = node->nd_head;
|
NODE *key_node = node->nd_head;
|
||||||
NODE *val_node = node->nd_next->nd_head;
|
NODE *val_node = node->nd_next->nd_head;
|
||||||
keywords[i] = SYM2ID(key_node->nd_lit);
|
keywords[i] = key_node->nd_lit;
|
||||||
COMPILE(ret, "keyword values", val_node);
|
COMPILE(ret, "keyword values", val_node);
|
||||||
}
|
}
|
||||||
assert(i == len);
|
assert(i == len);
|
||||||
|
@ -5844,12 +5844,14 @@ iseq_build_callinfo_from_hash(rb_iseq_t *iseq, VALUE op)
|
||||||
if (!NIL_P(vkw_arg)) {
|
if (!NIL_P(vkw_arg)) {
|
||||||
int i;
|
int i;
|
||||||
int len = RARRAY_LENINT(vkw_arg);
|
int len = RARRAY_LENINT(vkw_arg);
|
||||||
size_t n = sizeof(rb_call_info_kw_arg_t) + sizeof(ID) * (len - 1);
|
size_t n = sizeof(rb_call_info_kw_arg_t) + sizeof(VALUE) * (len - 1);
|
||||||
|
|
||||||
kw_arg = xmalloc(n);
|
kw_arg = xmalloc(n);
|
||||||
kw_arg->keyword_len = len;
|
kw_arg->keyword_len = len;
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
kw_arg->keywords[i] = SYM2ID(RARRAY_AREF(vkw_arg, i));
|
VALUE kw = RARRAY_AREF(vkw_arg, i);
|
||||||
|
SYM2ID(kw); /* make immortal */
|
||||||
|
kw_arg->keywords[i] = kw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -426,5 +426,26 @@ module Test_Symbol
|
||||||
x.method(:send).call(name.to_sym)
|
x.method(:send).call(name.to_sym)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_kwarg_symbol_leak_no_rest
|
||||||
|
foo = -> (arg: 42) {}
|
||||||
|
assert_no_immortal_symbol_created("kwarg no rest") do |name|
|
||||||
|
assert_raise(ArgumentError) { foo.call(name.to_sym => 42) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_kwarg_symbol_leak_with_rest
|
||||||
|
foo = -> (arg: 2, **options) {}
|
||||||
|
assert_no_immortal_symbol_created("kwarg with rest") do |name|
|
||||||
|
foo.call(name.to_sym => 42)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_kwarg_symbol_leak_just_rest
|
||||||
|
foo = -> (**options) {}
|
||||||
|
assert_no_immortal_symbol_created("kwarg just rest") do |name|
|
||||||
|
foo.call(name.to_sym => 42)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
27
vm_args.c
27
vm_args.c
|
@ -238,7 +238,7 @@ args_pop_keyword_hash(struct args_info *args, VALUE *kw_hash_ptr, rb_thread_t *t
|
||||||
static int
|
static int
|
||||||
args_kw_argv_to_hash(struct args_info *args)
|
args_kw_argv_to_hash(struct args_info *args)
|
||||||
{
|
{
|
||||||
const ID * const passed_keywords = args->ci->kw_arg->keywords;
|
const VALUE *const passed_keywords = args->ci->kw_arg->keywords;
|
||||||
const int kw_len = args->ci->kw_arg->keyword_len;
|
const int kw_len = args->ci->kw_arg->keyword_len;
|
||||||
VALUE h = rb_hash_new();
|
VALUE h = rb_hash_new();
|
||||||
const int kw_start = args->argc - kw_len;
|
const int kw_start = args->argc - kw_len;
|
||||||
|
@ -247,7 +247,7 @@ args_kw_argv_to_hash(struct args_info *args)
|
||||||
|
|
||||||
args->argc = kw_start + 1;
|
args->argc = kw_start + 1;
|
||||||
for (i=0; i<kw_len; i++) {
|
for (i=0; i<kw_len; i++) {
|
||||||
rb_hash_aset(h, ID2SYM(passed_keywords[i]), kw_argv[i]);
|
rb_hash_aset(h, passed_keywords[i], kw_argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
args->argv[args->argc - 1] = h;
|
args->argv[args->argc - 1] = h;
|
||||||
|
@ -260,11 +260,11 @@ args_stored_kw_argv_to_hash(struct args_info *args)
|
||||||
{
|
{
|
||||||
VALUE h = rb_hash_new();
|
VALUE h = rb_hash_new();
|
||||||
int i;
|
int i;
|
||||||
const ID * const passed_keywords = args->ci->kw_arg->keywords;
|
const VALUE *const passed_keywords = args->ci->kw_arg->keywords;
|
||||||
const int passed_keyword_len = args->ci->kw_arg->keyword_len;
|
const int passed_keyword_len = args->ci->kw_arg->keyword_len;
|
||||||
|
|
||||||
for (i=0; i<passed_keyword_len; i++) {
|
for (i=0; i<passed_keyword_len; i++) {
|
||||||
rb_hash_aset(h, ID2SYM(passed_keywords[i]), args->kw_argv[i]);
|
rb_hash_aset(h, passed_keywords[i], args->kw_argv[i]);
|
||||||
}
|
}
|
||||||
args->kw_argv = NULL;
|
args->kw_argv = NULL;
|
||||||
|
|
||||||
|
@ -348,7 +348,7 @@ args_setup_rest_parameter(struct args_info *args, VALUE *locals)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
make_unused_kw_hash(const ID *passed_keywords, int passed_keyword_len, const VALUE *kw_argv, const int key_only)
|
make_unused_kw_hash(const VALUE *passed_keywords, int passed_keyword_len, const VALUE *kw_argv, const int key_only)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
VALUE obj = key_only ? rb_ary_tmp_new(1) : rb_hash_new();
|
VALUE obj = key_only ? rb_ary_tmp_new(1) : rb_hash_new();
|
||||||
|
@ -356,10 +356,10 @@ make_unused_kw_hash(const ID *passed_keywords, int passed_keyword_len, const VAL
|
||||||
for (i=0; i<passed_keyword_len; i++) {
|
for (i=0; i<passed_keyword_len; i++) {
|
||||||
if (kw_argv[i] != Qundef) {
|
if (kw_argv[i] != Qundef) {
|
||||||
if (key_only) {
|
if (key_only) {
|
||||||
rb_ary_push(obj, ID2SYM(passed_keywords[i]));
|
rb_ary_push(obj, passed_keywords[i]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
rb_hash_aset(obj, ID2SYM(passed_keywords[i]), kw_argv[i]);
|
rb_hash_aset(obj, passed_keywords[i], kw_argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,12 +367,13 @@ make_unused_kw_hash(const ID *passed_keywords, int passed_keyword_len, const VAL
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const ID * const passed_keywords, VALUE *passed_values, const int passed_keyword_len)
|
args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const VALUE *const passed_keywords, VALUE *passed_values, const int passed_keyword_len)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
const VALUE keyname = ID2SYM(key);
|
||||||
|
|
||||||
for (i=0; i<passed_keyword_len; i++) {
|
for (i=0; i<passed_keyword_len; i++) {
|
||||||
if (key == passed_keywords[i]) {
|
if (keyname == passed_keywords[i]) {
|
||||||
*ptr = passed_values[i];
|
*ptr = passed_values[i];
|
||||||
passed_values[i] = Qundef;
|
passed_values[i] = Qundef;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -383,7 +384,7 @@ args_setup_kw_parameters_lookup(const ID key, VALUE *ptr, const ID * const passe
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_len, const ID * const passed_keywords,
|
args_setup_kw_parameters(VALUE* const passed_values, const int passed_keyword_len, const VALUE *const passed_keywords,
|
||||||
const rb_iseq_t * const iseq, VALUE * const locals)
|
const rb_iseq_t * const iseq, VALUE * const locals)
|
||||||
{
|
{
|
||||||
const ID *acceptable_keywords = iseq->param.keyword->table;
|
const ID *acceptable_keywords = iseq->param.keyword->table;
|
||||||
|
@ -495,7 +496,7 @@ fill_keys_values(st_data_t key, st_data_t val, st_data_t ptr)
|
||||||
{
|
{
|
||||||
struct fill_values_arg *arg = (struct fill_values_arg *)ptr;
|
struct fill_values_arg *arg = (struct fill_values_arg *)ptr;
|
||||||
int i = arg->argc++;
|
int i = arg->argc++;
|
||||||
arg->keys[i] = SYM2ID((VALUE)key);
|
arg->keys[i] = (VALUE)key;
|
||||||
arg->vals[i] = (VALUE)val;
|
arg->vals[i] = (VALUE)val;
|
||||||
return ST_CONTINUE;
|
return ST_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -722,14 +723,14 @@ vm_caller_setup_arg_splat(rb_control_frame_t *cfp, rb_call_info_t *ci)
|
||||||
static inline void
|
static inline void
|
||||||
vm_caller_setup_arg_kw(rb_control_frame_t *cfp, rb_call_info_t *ci)
|
vm_caller_setup_arg_kw(rb_control_frame_t *cfp, rb_call_info_t *ci)
|
||||||
{
|
{
|
||||||
const ID * const passed_keywords = ci->kw_arg->keywords;
|
const VALUE *const passed_keywords = ci->kw_arg->keywords;
|
||||||
const int kw_len = ci->kw_arg->keyword_len;
|
const int kw_len = ci->kw_arg->keyword_len;
|
||||||
const VALUE h = rb_hash_new();
|
const VALUE h = rb_hash_new();
|
||||||
VALUE *sp = cfp->sp;
|
VALUE *sp = cfp->sp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i=0; i<kw_len; i++) {
|
for (i=0; i<kw_len; i++) {
|
||||||
rb_hash_aset(h, ID2SYM(passed_keywords[i]), (sp - kw_len)[i]);
|
rb_hash_aset(h, passed_keywords[i], (sp - kw_len)[i]);
|
||||||
}
|
}
|
||||||
(sp-kw_len)[0] = h;
|
(sp-kw_len)[0] = h;
|
||||||
|
|
||||||
|
|
|
@ -137,7 +137,7 @@ struct rb_control_frame_struct;
|
||||||
|
|
||||||
typedef struct rb_call_info_kw_arg_struct {
|
typedef struct rb_call_info_kw_arg_struct {
|
||||||
int keyword_len;
|
int keyword_len;
|
||||||
ID keywords[1];
|
VALUE keywords[1];
|
||||||
} rb_call_info_kw_arg_t;
|
} rb_call_info_kw_arg_t;
|
||||||
|
|
||||||
/* rb_call_info_t contains calling information including inline cache */
|
/* rb_call_info_t contains calling information including inline cache */
|
||||||
|
|
Loading…
Reference in a new issue