From e9b5878c4168ec6b5ed5129d897ee9be7636ca71 Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 26 Mar 2003 07:01:14 +0000 Subject: [PATCH] * eval.c (avalue_splat): new function to do unary * (splat) operator. * eval.c (avalue_to_svalue,svalue_to_avalue,svalue_to_mrhs): do not use implicit "to_ary" conversion. * ext/curses/curses.c (GetWINDOW,GetMOUSE): add taint check. * ext/curses/curses.c (curses_init_screen): ditto. * ext/curses/curses.c (window_initialize): ditto. * gc.c (os_each_obj): prohibit ObjectSpace#each_object in safe mode ($SAFE >= 4). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@3616 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 17 ++++++++++++ README.EXT | 17 ++++++++++-- README.EXT.ja | 15 ++++++++-- eval.c | 67 +++++++++++++++++++-------------------------- ext/curses/curses.c | 6 ++++ gc.c | 3 ++ node.h | 4 +-- parse.y | 4 +-- sample/test.rb | 34 +++++++++++++++++++---- 9 files changed, 112 insertions(+), 55 deletions(-) diff --git a/ChangeLog b/ChangeLog index 668bee3d3a..2f775e974b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +Wed Mar 26 13:19:32 2003 Yukihiro Matsumoto + + * eval.c (avalue_splat): new function to do unary * (splat) + operator. + + * eval.c (avalue_to_svalue,svalue_to_avalue,svalue_to_mrhs): do + not use implicit "to_ary" conversion. + + * ext/curses/curses.c (GetWINDOW,GetMOUSE): add taint check. + + * ext/curses/curses.c (curses_init_screen): ditto. + + * ext/curses/curses.c (window_initialize): ditto. + + * gc.c (os_each_obj): prohibit ObjectSpace#each_object in safe + mode ($SAFE >= 4). + Tue Mar 25 23:26:02 2003 Yukihiro Matsumoto * signal.c (trap): return "DEFAULT" and "IGNORE" respectively for diff --git a/README.EXT b/README.EXT index 4bbe1202e6..97e57934be 100644 --- a/README.EXT +++ b/README.EXT @@ -94,9 +94,20 @@ The T_FIXNUM data is a 31bit length fixed integer (63bit length on some machines), which can be convert to a C integer by using the FIX2INT() macro. There is also NUM2INT() which converts any Ruby numbers into C integers. The NUM2INT() macro includes a type check, so -an exception will be raised if the conversion failed. There are also -a macro NUM2DBL() to retrieve the double float value and STR2CSTR() is -useful to get the string as char*. +an exception will be raised if the conversion failed. NUM2DBL() can +be used to retrieve the double float value in same way. + +To get char* from a VALUE, version 1.7 recommend to use new macros +StringValue() and StringValuePtr(). StringValue(var) replaces var's +value to the result of "var.to_str()". StringValuePtr(var) does same +replacement and returns char* representation of var. These macros +will skip the replacement if var is a String. Notice that the macros +requires to take only lvalue as their argument, to change the value +of var in the replacement. + +In version 1.6 or earlier, STR2CSTR() was used to do same thing +but now it is obsoleted in version 1.7 because of STR2CSTR() has +a risk of dangling pointer problem in to_str() impliclit conversion. Other data types have corresponding C structures, e.g. struct RArray for T_ARRAY etc. The VALUE of the type which has corresponding structure diff --git a/README.EXT.ja b/README.EXT.ja index 0ef67497ce..f4681880b4 100644 --- a/README.EXT.ja +++ b/README.EXT.ja @@ -104,10 +104,19 @@ FIXNUM います.それから,FIXNUMに限らずRubyのデータを整数に変換する 「NUM2INT()」というマクロがあります.このマクロはデータタイ プのチェック無しで使えます(整数に変換できない場合には例外が -発生する). +発生する).同様にチェック無しで使える変換マクロはdoubleを +取り出す「NUM2DBL()」があります。 -同様にチェック無しで使える変換マクロはdoubleを取り出す -「NUM2DBL()」とchar*を取り出す「STR2CSTR()」があります. +char* を取り出す場合、version 1.6 以前では「STR2CSTR()」と +いうマクロを使っていましたが、これは to_str() による暗黙の +型変換結果が GC される可能性があるため、version 1.7 以降では +obsolete となり、代わりに StringValue() と StringValuePtr() +を使う事を推奨しています。StringValue(var) は var が String + であれば何もせず、そうでなければ var を var.to_str() の結果に +置き換えるマクロ、StringValuePtr(var) は同様に var を置き換え +てから var の文字列表現に対する char* を返すマクロです。var の +内容を直接置き換える処理が入るので、var は lvalue である必要が +あります。 それ以外のデータタイプは対応するCの構造体があります.対応す る構造体のあるVALUEはそのままキャスト(型変換)すれば構造体の diff --git a/eval.c b/eval.c index e59ad61e78..e166712ed0 100644 --- a/eval.c +++ b/eval.c @@ -2201,28 +2201,23 @@ static VALUE avalue_to_svalue(v) VALUE v; { - VALUE tmp; - - if (v == Qundef) return v; - tmp = rb_check_array_type(v); - if (NIL_P(tmp)) { + if (TYPE(v) != T_ARRAY) { return v; } - v = tmp; if (RARRAY(v)->len == 0) { return Qundef; } if (RARRAY(v)->len == 1) { - tmp = rb_check_array_type(RARRAY(v)->ptr[0]); - if (NIL_P(tmp)) { - return RARRAY(v)->ptr[0]; + VALUE tmp = RARRAY(v)->ptr[0]; + if (TYPE(tmp) != T_ARRAY) { + return tmp; } if (RARRAY(tmp)->len > 1) { return v; } return tmp; } - return tmp; + return v; } static VALUE @@ -2232,40 +2227,29 @@ svalue_to_avalue(v) VALUE tmp; if (v == Qundef) return rb_ary_new2(0); - tmp = rb_check_array_type(v); - - if (NIL_P(tmp)) { + if (TYPE(v) != T_ARRAY) { return rb_ary_new3(1, v); } - v = tmp; if (RARRAY(v)->len == 1) { - tmp = rb_check_array_type(RARRAY(v)->ptr[0]); - if (NIL_P(tmp)) return rb_ary_new3(1, v); - if (RARRAY(tmp)->len > 1) return v; - return tmp; + tmp = RARRAY(v)->ptr[0]; + if (TYPE(tmp) == T_ARRAY && RARRAY(tmp)->len > 1) + return v; + return rb_ary_new3(1, v); } return v; } static VALUE -avalue_to_mrhs(v) +avalue_splat(v) VALUE v; { - VALUE tmp; - - if (v == Qundef) return v; - tmp = rb_check_array_type(v); - if (NIL_P(tmp)) { - return v; - } - v = tmp; if (RARRAY(v)->len == 0) { return Qundef; } if (RARRAY(v)->len == 1) { return RARRAY(v)->ptr[0]; } - return tmp; + return v; } static VALUE @@ -2273,18 +2257,15 @@ svalue_to_mrhs(v, lhs) VALUE v; NODE *lhs; { - VALUE tmp; - if (v == Qundef) return rb_ary_new2(0); - tmp = rb_check_array_type(v); - - if (NIL_P(tmp)) { + if (TYPE(v) != T_ARRAY) { return rb_ary_new3(1, v); } - if (!lhs && RARRAY(tmp)->len <= 1) { - return rb_ary_new3(1, tmp); + /* no lhs means splat lhs only */ + if (!lhs && RARRAY(v)->len <= 1) { + return rb_ary_new3(1, v); } - return tmp; + return v; } static VALUE @@ -2670,8 +2651,16 @@ rb_eval(self, n) result = rb_ary_to_ary(rb_eval(self, node->nd_head)); break; - case NODE_REXPAND: - result = avalue_to_mrhs(rb_eval(self, node->nd_head)); + case NODE_SPLAT: + { + VALUE tmp; + + result = rb_eval(self, node->nd_head); + tmp = rb_check_array_type(result); + if (!NIL_P(tmp)) { + result = avalue_splat(tmp); + } + } break; case NODE_SVALUE: @@ -3982,7 +3971,7 @@ rb_yield_0(val, self, klass, pcall, avalue) massign(self, block->var, val, pcall); } else { - if (avalue) val = avalue_to_mrhs(val); + if (avalue) val = avalue_splat(val); if (val == Qundef) val = Qnil; assign(self, block->var, val, pcall); } diff --git a/ext/curses/curses.c b/ext/curses/curses.c index fa29263bcd..a666cce897 100644 --- a/ext/curses/curses.c +++ b/ext/curses/curses.c @@ -75,6 +75,8 @@ no_window() } #define GetWINDOW(obj, winp) do {\ + if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ + rb_raise(rb_eSecurityError, "Insecure: operation on untainted window");\ Data_Get_Struct(obj, struct windata, winp);\ if (winp->window == 0) no_window();\ } while (0) @@ -113,6 +115,7 @@ prep_window(class, window) static VALUE curses_init_screen() { + rb_secure(4); if (rb_stdscr) return rb_stdscr; initscr(); if (stdscr == 0) { @@ -593,6 +596,8 @@ no_mevent() } #define GetMOUSE(obj, data) do {\ + if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)\ + rb_raise(rb_eSecurityError, "Insecure: operation on untainted mouse");\ Data_Get_Struct(obj, struct mousedata, data);\ if (data->mevent == 0) no_mevent();\ } while (0) @@ -677,6 +682,7 @@ window_initialize(obj, h, w, top, left) struct windata *winp; WINDOW *window; + rb_secure(4); curses_init_screen(); Data_Get_Struct(obj, struct windata, winp); if (winp->window) delwin(winp->window); diff --git a/gc.c b/gc.c index 6789c0d180..6c8e9f650e 100644 --- a/gc.c +++ b/gc.c @@ -705,6 +705,8 @@ rb_gc_mark(ptr) case NODE_YIELD: case NODE_COLON2: case NODE_ARGS: + case NODE_SPLAT: + case NODE_SVALUE: ptr = (VALUE)obj->as.node.u1.node; goto again; @@ -1377,6 +1379,7 @@ os_each_obj(argc, argv) { VALUE of; + rb_secure(4); if (rb_scan_args(argc, argv, "01", &of) == 0) { return os_live_obj(); } diff --git a/node.h b/node.h index da2f2f4f52..516618a7a5 100644 --- a/node.h +++ b/node.h @@ -89,7 +89,7 @@ enum node_type { NODE_ARGSPUSH, NODE_RESTARY, NODE_RESTARY2, - NODE_REXPAND, + NODE_SPLAT, NODE_SVALUE, NODE_BLOCK_ARG, NODE_BLOCK_PASS, @@ -309,7 +309,7 @@ typedef struct RNode { #define NEW_ARGSPUSH(a,b) rb_node_newnode(NODE_ARGSPUSH,a,b,0) #define NEW_RESTARY(a) rb_node_newnode(NODE_RESTARY,a,0,0) #define NEW_RESTARY2(a) rb_node_newnode(NODE_RESTARY2,a,0,0) -#define NEW_REXPAND(a) rb_node_newnode(NODE_REXPAND,a,0,0) +#define NEW_SPLAT(a) rb_node_newnode(NODE_SPLAT,a,0,0) #define NEW_SVALUE(a) rb_node_newnode(NODE_SVALUE,a,0,0) #define NEW_BLOCK_ARG(v) rb_node_newnode(NODE_BLOCK_ARG,v,0,local_cnt(v)) #define NEW_BLOCK_PASS(b) rb_node_newnode(NODE_BLOCK_PASS,0,b,0) diff --git a/parse.y b/parse.y index 8096d5d576..faea6c4639 100644 --- a/parse.y +++ b/parse.y @@ -1385,7 +1385,7 @@ mrhs : args ',' arg_value } | tSTAR arg_value { - $$ = NEW_REXPAND($2); + $$ = NEW_SPLAT($2); } ; @@ -5314,7 +5314,7 @@ ret_args(node) } } if (node && nd_type(node) == NODE_RESTARY) { - nd_set_type(node, NODE_REXPAND); + nd_set_type(node, NODE_SPLAT); } return node; } diff --git a/sample/test.rb b/sample/test.rb index fb7c0f6757..5c263090d0 100644 --- a/sample/test.rb +++ b/sample/test.rb @@ -248,13 +248,33 @@ f = lambda {|r,*l| test_ok([] == r); test_ok([1] == l)} f.call([], *[1]) f.yield([], *[1]) -a = [42,55] -lambda{|x| test_ok([42,55] == x)}.call(a) -lambda{|x,| test_ok([42,55] == x)}.call(a) -lambda{|*x| test_ok([[42,55]] == x)}.call(a) + +f = lambda{|x| x} +test_ok(f.call(42) == 42) +test_ok(f.call([42]) == [42]) +test_ok(f.call([[42]]) == [[42]]) +test_ok(f.call([42,55]) == [42,55]) +test_ok(f.call(42,55) == [42,55]) + +f = lambda{|x,| x} +test_ok(f.call(42) == 42) +test_ok(f.call([42]) == [42]) +test_ok(f.call([[42]]) == [[42]]) +test_ok(f.call([42,55]) == [42,55]) + +f = lambda{|*x| x} +test_ok(f.call(42) == [42]) +test_ok(f.call([42]) == [[42]]) +test_ok(f.call([[42]]) == [[[42]]]) +test_ok(f.call([42,55]) == [[42,55]]) +test_ok(f.call(42,55) == [42,55]) a,=*[1] test_ok(a == 1) +a,=*[[1]] +test_ok(a == 1) +a,=*[[[1]]] +test_ok(a == [1]) a = loop do break; end; test_ok(a == nil) a = loop do break nil; end; test_ok(a == nil) @@ -905,10 +925,12 @@ class IterTest def each8; @body.each {|x| yield(x) } end def f(a) - test_ok(a == [1]) + a end end -IterTest.new(nil).method(:f).to_proc.call([1]) +test_ok(IterTest.new(nil).method(:f).to_proc.call([1]) == [1]) +m = /\w+/.match("abc") +test_ok(IterTest.new(nil).method(:f).to_proc.call([m]) == [m]) IterTest.new([0]).each0 {|x| test_ok(x == 0)} IterTest.new([1]).each1 {|x| test_ok(x == 1)}