[#35789] [Ruby 1.9 - Bug #407] (Open) String#<< — Shyouhei Urabe <redmine@...>

チケット #407 が報告されました。 (by Shyouhei Urabe)

13 messages 2008/08/06

[#35845] [Bug #437] test_strftime(TestTime) fails on Solaris — Shugo Maeda <redmine@...>

Bug #437: test_strftime(TestTime) fails on Solaris

24 messages 2008/08/13
[#35855] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — "Shugo Maeda" <shugo@...> 2008/08/15

前田です。

[#35856] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — SATOH Fumiyasu <fumiyas@...> 2008/08/15

さとうふみやす @ OSS テクノロジです。

[#35857] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — Yukihiro Matsumoto <matz@...> 2008/08/15

まつもと ゆきひろです

[#35870] Re: [Bug #437] test_strftime(TestTime) fails on Solaris — "Shugo Maeda" <shugo@...> 2008/08/18

前田です。

[#35863] Refactoring of enumerating prime numbers — "Yugui (Yuki Sonoda)" <yugui@...>

Yuguiです。

20 messages 2008/08/16
[#35865] Re: Refactoring of enumerating prime numbers — keiju@... (keiju ISHITSUKA) 2008/08/17

けいじゅ@いしつかです.

[#35867] Re: Refactoring of enumerating prime numbers — "Yugui (Yuki Sonoda)" <yugui@...> 2008/08/17

Yuguiです。

[#35875] Re: Refactoring of enumerating prime numbers — keiju@... (keiju ISHITSUKA) 2008/08/19

けいじゅ@いしつかです.

[#35877] Re: Refactoring of enumerating prime numbers — Nobuyoshi Nakada <nobu@...> 2008/08/19

なかだです。

[#35882] Re: Refactoring of enumerating prime numbers — keiju@... (石塚圭樹) 2008/08/20

けいじゅ@いしつかです.

[#35904] [Feature:1.9] pack format 'm' based on RFC 4648 — "Yusuke ENDOH" <mame@...>

遠藤です。

14 messages 2008/08/21
[#36442] [Feature #471] pack format 'm' based on RFC 4648 — Yuki Sonoda <redmine@...> 2008/09/22

チケット #471 が更新されました。 (by Yuki Sonoda)

[#35906] %N for Time#strftime — "Shugo Maeda" <shugo@...>

前田です。

13 messages 2008/08/21

[#35986] 1.9と1.8で、delegateのインスタンスのクラス名の違う — Fujioka <fuj@...>

xibbarこと藤岡です。

17 messages 2008/08/26
[#35987] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — Yukihiro Matsumoto <matz@...> 2008/08/26

まつもと ゆきひろです

[#35991] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — keiju@... (石塚圭樹) 2008/08/26

けいじゅ@いしつかです.

[#35994] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — Fujioka <fuj@...> 2008/08/27

藤岡です。

[#35998] Re: 1.9と1.8で、delegateのインスタンスのクラス名の違う — keiju@... (石塚圭樹) 2008/08/27

けいじゅ@いしつかです.

[#36066] Numeric#scalar? — Tadayoshi Funaba <tadf@...>

1.9 の Numeric#scalar? について、適当でないのでは (real? などのほうがい

24 messages 2008/08/31
[#36069] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/08/31

原です。

[#36104] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/02

> やはり、scalar? はずれているんじゃないかな。real? の方がいい

[#36122] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/09/03

原です。

[#36133] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/03

> ここで、scalar? を疑問視する理由を復習すると、たとえば、「複

[#36173] Re: Numeric#scalar? — Tadayoshi Funaba <tadf@...> 2008/09/05

1.9.1 までに時間がないので scalar? だけ何とかしたいと思っていましたが、

[#36183] Re: Numeric#scalar? — "Shugo Maeda" <shugo@...> 2008/09/06

前田です。

[#36186] Re: Numeric#scalar? — Shin-ichiro HARA <sinara@...> 2008/09/06

原です。

[ruby-dev:35833] Re: $SAFEの今後

From: "Shugo Maeda" <shugo@...>
Date: 2008-08-12 16:14:21 UTC
List: ruby-dev #35833
前田です。

2008/07/02 18:17 Shugo Maeda <shugo@ruby-lang.org>:
>> taint(汚染)が二種類になるので名前を考えないといけません。ま
>> た、それぞれのレベルの汚染を操作するメソッドについても考えな
>> いといけません。まあ、いずれも技術的な問題ではありませんが。
>
> untrusted?はどうでしょう。
> # untrust/trustがtaint/untaint相当。

とりあえず、上記の名前で実装してみました。
パッチを添付します。

-- 
Shugo Maeda

Attachments (1)

untrusted.diff (20 KB, text/x-diff)
Index: array.c
===================================================================
--- array.c	(revision 18544)
+++ array.c	(working copy)
@@ -54,7 +54,7 @@
 rb_ary_modify_check(VALUE ary)
 {
     if (OBJ_FROZEN(ary)) rb_error_frozen("array");
-    if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify array");
 }
 
Index: debug.c
===================================================================
--- debug.c	(revision 18544)
+++ debug.c	(working copy)
@@ -67,8 +67,6 @@
     } various;
 } dummy_gdb_enums;
 
-const VALUE RUBY_FL_USER20    = FL_USER20;
-
 int
 ruby_debug_print_indent(int level, int debug_level, int indent_level)
 {
Index: time.c
===================================================================
--- time.c	(revision 18544)
+++ time.c	(working copy)
@@ -60,7 +60,7 @@
 time_modify(VALUE time)
 {
     rb_check_frozen(time);
-    if (!OBJ_TAINTED(time) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(time) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify Time");
 }
 
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 18544)
+++ include/ruby/ruby.h	(working copy)
@@ -432,7 +432,7 @@
 #define OBJSETUP(obj,c,t) do {\
     RBASIC(obj)->flags = (t);\
     RBASIC(obj)->klass = (c);\
-    if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\
+    if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT | FL_UNTRUSTED);\
 } while (0)
 #define CLONESETUP(clone,obj) do {\
     OBJSETUP(clone,rb_singleton_class_clone((VALUE)obj),RBASIC(obj)->flags);\
@@ -440,7 +440,7 @@
     if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\
 } while (0)
 #define DUPSETUP(dup,obj) do {\
-    OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\
+    OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED));\
     if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\
 } while (0)
 
@@ -693,10 +693,11 @@
 #define FL_RESERVED  (((VALUE)1)<<6) /* will be used in the future GC */
 #define FL_FINALIZE  (((VALUE)1)<<7)
 #define FL_TAINT     (((VALUE)1)<<8)
-#define FL_EXIVAR    (((VALUE)1)<<9)
-#define FL_FREEZE    (((VALUE)1)<<10)
+#define FL_UNTRUSTED (((VALUE)1)<<9)
+#define FL_EXIVAR    (((VALUE)1)<<10)
+#define FL_FREEZE    (((VALUE)1)<<11)
 
-#define FL_USHIFT    11
+#define FL_USHIFT    12
 
 #define FL_USER0     (((VALUE)1)<<(FL_USHIFT+0))
 #define FL_USER1     (((VALUE)1)<<(FL_USHIFT+1))
@@ -718,7 +719,6 @@
 #define FL_USER17    (((VALUE)1)<<(FL_USHIFT+17))
 #define FL_USER18    (((VALUE)1)<<(FL_USHIFT+18))
 #define FL_USER19    (((VALUE)1)<<(FL_USHIFT+19))
-#define FL_USER20    (((VALUE)1)<<(FL_USHIFT+20))
 
 #define SPECIAL_CONST_P(x) (IMMEDIATE_P(x) || !RTEST(x))
 
@@ -732,7 +732,9 @@
 
 #define OBJ_TAINTED(x) FL_TEST((x), FL_TAINT)
 #define OBJ_TAINT(x) FL_SET((x), FL_TAINT)
-#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & FL_TAINT;} while (0)
+#define OBJ_UNTRUSTED(x) FL_TEST((x), FL_UNTRUSTED)
+#define OBJ_UNTRUST(x) FL_SET((x), FL_UNTRUSTED)
+#define OBJ_INFECT(x,s) do {if (FL_ABLE(x) && FL_ABLE(s)) RBASIC(x)->flags |= RBASIC(s)->flags & (FL_TAINT | FL_UNTRUSTED);} while (0)
 
 #define OBJ_FROZEN(x) FL_TEST((x), FL_FREEZE)
 #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE)
Index: re.c
===================================================================
--- re.c	(revision 18544)
+++ re.c	(working copy)
@@ -2299,7 +2299,7 @@
     rb_encoding *fixed_enc = 0;
     rb_encoding *a_enc = rb_ascii8bit_encoding();
 
-    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify regexp");
     rb_check_frozen(obj);
     if (FL_TEST(obj, REG_LITERAL))
Index: variable.c
===================================================================
--- variable.c	(revision 18544)
+++ variable.c	(working copy)
@@ -995,7 +995,7 @@
     long i, len;
     int ivar_extended;
 
-    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
     if (OBJ_FROZEN(obj)) rb_error_frozen("object");
     switch (TYPE(obj)) {
@@ -1216,7 +1216,7 @@
     struct st_table *iv_index_tbl;
     st_data_t index;
 
-    if (!OBJ_TAINTED(obj) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable");
     if (OBJ_FROZEN(obj)) rb_error_frozen("object");
     if (!rb_is_instance_id(id)) {
@@ -1505,7 +1505,7 @@
     if (!rb_is_const_id(id)) {
 	rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id));
     }
-    if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't remove constant");
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
@@ -1667,7 +1667,7 @@
 {
     const char *dest = isconst ? "constant" : "class variable";
 
-    if (!OBJ_TAINTED(klass) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4)
       rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest);
     if (OBJ_FROZEN(klass)) {
 	if (BUILTIN_TYPE(klass) == T_MODULE) {
@@ -1922,7 +1922,7 @@
     if (!rb_is_class_id(id)) {
 	rb_name_error(id, "wrong class variable name %s", rb_id2name(id));
     }
-    if (!OBJ_TAINTED(mod) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't remove class variable");
     if (OBJ_FROZEN(mod)) rb_error_frozen("class/module");
 
Index: object.c
===================================================================
--- object.c	(revision 18544)
+++ object.c	(working copy)
@@ -161,7 +161,7 @@
         rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest));
     }
     RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
-    RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT);
+    RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR|FL_TAINT|FL_UNTRUSTED);
     rb_copy_generic_ivar(dest, obj);
     rb_gc_copy_finalizer(dest, obj);
     switch (TYPE(obj)) {
@@ -692,6 +692,62 @@
     return obj;
 }
 
+/*
+ *  call-seq:
+ *     obj.untrusted?    => true or false
+ *  
+ *  Returns <code>true</code> if the object is untainted.
+ */
+
+VALUE
+rb_obj_untrusted(VALUE obj)
+{
+    if (OBJ_UNTRUSTED(obj))
+	return Qtrue;
+    return Qfalse;
+}
+
+/*
+ *  call-seq:
+ *     obj.untrust -> obj
+ *  
+ *  Marks <i>obj</i> as untrusted.
+ */
+
+VALUE
+rb_obj_untrust(VALUE obj)
+{
+    rb_secure(4);
+    if (!OBJ_UNTRUSTED(obj)) {
+	if (OBJ_FROZEN(obj)) {
+	    rb_error_frozen("object");
+	}
+	OBJ_UNTRUST(obj);
+    }
+    return obj;
+}
+
+
+/*
+ *  call-seq:
+ *     obj.trust    => obj
+ *  
+ *  Removes the untrusted mark from <i>obj</i>.
+ */
+
+VALUE
+rb_obj_trust(VALUE obj)
+{
+    rb_secure(3);
+    if (OBJ_UNTRUSTED(obj)) {
+	if (OBJ_FROZEN(obj)) {
+	    rb_error_frozen("object");
+	}
+	FL_UNSET(obj, FL_UNTRUSTED);
+    }
+    return obj;
+}
+
 void
 rb_obj_infect(VALUE obj1, VALUE obj2)
 {
@@ -723,7 +779,7 @@
 rb_obj_freeze(VALUE obj)
 {
     if (!OBJ_FROZEN(obj)) {
-	if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) {
+	if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(obj)) {
 	    rb_raise(rb_eSecurityError, "Insecure: can't freeze object");
 	}
 	OBJ_FREEZE(obj);
@@ -2419,6 +2475,9 @@
     rb_define_method(rb_mKernel, "taint", rb_obj_taint, 0);
     rb_define_method(rb_mKernel, "tainted?", rb_obj_tainted, 0);
     rb_define_method(rb_mKernel, "untaint", rb_obj_untaint, 0);
+    rb_define_method(rb_mKernel, "untrust", rb_obj_untrust, 0);
+    rb_define_method(rb_mKernel, "untrusted?", rb_obj_untrusted, 0);
+    rb_define_method(rb_mKernel, "trust", rb_obj_trust, 0);
     rb_define_method(rb_mKernel, "freeze", rb_obj_freeze, 0);
     rb_define_method(rb_mKernel, "frozen?", rb_obj_frozen_p, 0);
 
Index: string.c
===================================================================
--- string.c	(revision 18544)
+++ string.c	(working copy)
@@ -1027,7 +1027,7 @@
 	rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked");
     }
     if (OBJ_FROZEN(str)) rb_error_frozen("string");
-    if (!OBJ_TAINTED(str) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(str) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify string");
 }
 
@@ -3170,6 +3170,7 @@
     VALUE pat, repl, hash = Qnil;
     int iter = 0;
     int tainted = 0;
+    int untrusted = 0;
     long plen;
 
     if (argc == 1 && rb_block_given_p()) {
@@ -3182,6 +3183,7 @@
 	    StringValue(repl);
 	}
 	if (OBJ_TAINTED(repl)) tainted = 1;
+	if (OBJ_UNTRUSTED(repl)) untrusted = 1;
     }
     else {
 	rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
@@ -3227,6 +3229,7 @@
 	rb_str_modify(str);
 	rb_enc_associate(str, enc);
 	if (OBJ_TAINTED(repl)) tainted = 1;
+	if (OBJ_UNTRUSTED(repl)) untrusted = 1;
 	if (ENC_CODERANGE_UNKNOWN < cr && cr < ENC_CODERANGE_BROKEN) {
 	    int cr2 = ENC_CODERANGE(repl);
 	    if (cr2 == ENC_CODERANGE_UNKNOWN || cr2 > cr) cr = cr2;
@@ -3246,6 +3249,7 @@
 	RSTRING_PTR(str)[RSTRING_LEN(str)] = '\0';
 	ENC_CODERANGE_SET(str, cr);
 	if (tainted) OBJ_TAINT(str);
+	if (untrusted) OBJ_UNTRUST(str);
 
 	return str;
     }
Index: io.c
===================================================================
--- io.c	(revision 18544)
+++ io.c	(working copy)
@@ -227,8 +227,8 @@
 VALUE
 rb_io_taint_check(VALUE io)
 {
-    if (!OBJ_TAINTED(io) && rb_safe_level() >= 4)
-	rb_raise(rb_eSecurityError, "Insecure: operation on untainted IO");
+    if (!OBJ_UNTRUSTED(io) && rb_safe_level() >= 4)
+	rb_raise(rb_eSecurityError, "Insecure: operation on trusted IO");
     rb_check_frozen(io);
     return io;
 }
@@ -2819,7 +2819,7 @@
 static VALUE
 rb_io_close_m(VALUE io)
 {
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't close");
     }
     rb_io_check_closed(RFILE(io)->fptr);
@@ -2902,7 +2902,7 @@
     rb_io_t *fptr;
     VALUE write_io;
 
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't close");
     }
     GetOpenFile(io, fptr);
@@ -2962,7 +2962,7 @@
     rb_io_t *fptr;
     VALUE write_io;
 
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(io)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(io)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't close");
     }
     write_io = GetWriteIO(io);
@@ -4430,7 +4430,8 @@
     off_t pos = 0;
 
     nfile = rb_io_get_io(nfile);
-    if (rb_safe_level() >= 4 && (!OBJ_TAINTED(io) || !OBJ_TAINTED(nfile))) {
+    if (rb_safe_level() >= 4 &&
+       	(!OBJ_UNTRUSTED(io) || !OBJ_UNTRUSTED(nfile))) {
 	rb_raise(rb_eSecurityError, "Insecure: can't reopen");
     }
     GetOpenFile(io, fptr);
Index: dir.c
===================================================================
--- dir.c	(revision 18544)
+++ dir.c	(working copy)
@@ -414,8 +414,8 @@
 static void
 dir_check(VALUE dir)
 {
-    if (!OBJ_TAINTED(dir) && rb_safe_level() >= 4)
-	rb_raise(rb_eSecurityError, "Insecure: operation on untainted Dir");
+    if (!OBJ_UNTRUSTED(dir) && rb_safe_level() >= 4)
+	rb_raise(rb_eSecurityError, "Insecure: operation on trusted Dir");
     rb_check_frozen(dir);
 }
 
@@ -630,7 +630,7 @@
 {
     struct dir_data *dirp;
 
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(dir)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(dir)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't close");
     }
     GetDIR(dir, dirp);
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 18544)
+++ vm_method.c	(working copy)
@@ -108,7 +108,8 @@
     if (NIL_P(klass)) {
 	klass = rb_cObject;
     }
-    if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
+    if (rb_safe_level() >= 4 &&
+       	(klass == rb_cObject || !OBJ_UNTRUSTED(klass))) {
 	rb_raise(rb_eSecurityError, "Insecure: can't define method");
     }
     if (!FL_TEST(klass, FL_SINGLETON) &&
@@ -307,7 +308,7 @@
     if (klass == rb_cObject) {
 	rb_secure(4);
     }
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't remove method");
     }
     if (OBJ_FROZEN(klass))
@@ -474,7 +475,7 @@
     if (rb_vm_cbase() == rb_cObject && klass == rb_cObject) {
 	rb_secure(4);
     }
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) {
 	rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
 		 rb_id2name(id));
     }
@@ -810,7 +811,7 @@
 static void
 secure_visibility(VALUE self)
 {
-    if (rb_safe_level() >= 4 && !OBJ_TAINTED(self)) {
+    if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(self)) {
 	rb_raise(rb_eSecurityError,
 		 "Insecure: can't change method visibility");
     }
Index: struct.c
===================================================================
--- struct.c	(revision 18544)
+++ struct.c	(working copy)
@@ -144,7 +144,7 @@
 rb_struct_modify(VALUE s)
 {
     if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
-    if (!OBJ_TAINTED(s) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4)
        rb_raise(rb_eSecurityError, "Insecure: can't modify Struct");
 }
 
Index: class.c
===================================================================
--- class.c	(revision 18544)
+++ class.c	(working copy)
@@ -833,6 +833,12 @@
     else {
 	FL_UNSET(klass, FL_TAINT);
     }
+    if (OBJ_UNTRUSTED(obj)) {
+	OBJ_UNTRUST(klass);
+    }
+    else {
+	FL_UNSET(klass, FL_UNTRUSTED);
+    }
     if (OBJ_FROZEN(obj)) OBJ_FREEZE(klass);
     ALLOW_INTS;
 
Index: hash.c
===================================================================
--- hash.c	(revision 18544)
+++ hash.c	(working copy)
@@ -247,7 +247,7 @@
 rb_hash_modify_check(VALUE hash)
 {
     if (OBJ_FROZEN(hash)) rb_error_frozen("hash");
-    if (!OBJ_TAINTED(hash) && rb_safe_level() >= 4)
+    if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4)
 	rb_raise(rb_eSecurityError, "Insecure: can't modify hash");
 }
 
Index: ruby.c
===================================================================
--- ruby.c	(revision 18544)
+++ ruby.c	(working copy)
@@ -1069,12 +1069,12 @@
 #endif
     opt->script_name = rb_str_new4(rb_progname);
     opt->script = RSTRING_PTR(opt->script_name);
+    safe = rb_safe_level();
+    rb_set_safe_level_force(0);
     ruby_set_argv(argc, argv);
     process_sflag(opt);
 
     ruby_init_loadpath();
-    safe = rb_safe_level();
-    rb_set_safe_level_force(0);
     ruby_init_gems(!(opt->disable & DISABLE_BIT(gems)));
     lenc = rb_locale_encoding();
     for (i = 0; i < RARRAY_LEN(rb_argv); i++) {
Index: test/ruby/test_array.rb
===================================================================
--- test/ruby/test_array.rb	(revision 18544)
+++ test/ruby/test_array.rb	(working copy)
@@ -451,16 +451,20 @@
 
   def test_clone
     for taint in [ false, true ]
-      for frozen in [ false, true ]
-        a = @cls[*(0..99).to_a]
-        a.taint  if taint
-        a.freeze if frozen
-        b = a.clone
+      for untrust in [ false, true ]
+        for frozen in [ false, true ]
+          a = @cls[*(0..99).to_a]
+          a.taint  if taint
+          a.untrust  if untrust
+          a.freeze if frozen
+          b = a.clone
 
-        assert_equal(a, b)
-        assert(a.__id__ != b.__id__)
-        assert_equal(a.frozen?, b.frozen?)
-        assert_equal(a.tainted?, b.tainted?)
+          assert_equal(a, b)
+          assert(a.__id__ != b.__id__)
+          assert_equal(a.frozen?, b.frozen?)
+          assert_equal(a.untrusted?, b.untrusted?)
+          assert_equal(a.tainted?, b.tainted?)
+        end
       end
     end
   end
Index: test/ruby/test_string.rb
===================================================================
--- test/ruby/test_string.rb	(revision 18544)
+++ test/ruby/test_string.rb	(working copy)
@@ -427,16 +427,20 @@
 
   def test_clone
     for taint in [ false, true ]
-      for frozen in [ false, true ]
-        a = S("Cool")
-        a.taint  if taint
-        a.freeze if frozen
-        b = a.clone
+      for untrust in [ false, true ]
+        for frozen in [ false, true ]
+          a = S("Cool")
+          a.taint  if taint
+          a.untrust  if untrust
+          a.freeze if frozen
+          b = a.clone
 
-        assert_equal(a, b)
-        assert(a.__id__ != b.__id__)
-        assert_equal(a.frozen?, b.frozen?)
-        assert_equal(a.tainted?, b.tainted?)
+          assert_equal(a, b)
+          assert(a.__id__ != b.__id__)
+          assert_equal(a.frozen?, b.frozen?)
+          assert_equal(a.untrusted?, b.untrusted?)
+          assert_equal(a.tainted?, b.tainted?)
+        end
       end
     end
 
@@ -532,16 +536,20 @@
 
   def test_dup
     for taint in [ false, true ]
-      for frozen in [ false, true ]
-        a = S("hello")
-        a.taint  if taint
-        a.freeze if frozen
-        b = a.dup 
+      for untrust in [ false, true ]
+        for frozen in [ false, true ]
+          a = S("hello")
+          a.taint  if taint
+          a.untrust  if untrust
+          a.freeze if frozen
+          b = a.dup 
 
-        assert_equal(a, b)
-        assert(a.__id__ != b.__id__)
-        assert(!b.frozen?)
-        assert_equal(a.tainted?, b.tainted?)
+          assert_equal(a, b)
+          assert(a.__id__ != b.__id__)
+          assert(!b.frozen?)
+          assert_equal(a.tainted?, b.tainted?)
+          assert_equal(a.untrusted?, b.untrusted?)
+        end
       end
     end     
   end
@@ -623,7 +631,9 @@
 
     a = S("hello")
     a.taint
+    a.untrust
     assert(a.gsub(/./, S('X')).tainted?)
+    assert(a.gsub(/./, S('X')).untrusted?)
 
     assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug")
 
@@ -651,8 +661,10 @@
 
     r = S('X')
     r.taint
+    r.untrust
     a.gsub!(/./, r)
     assert(a.tainted?) 
+    assert(a.untrusted?) 
 
     a = S("hello")
     assert_nil(a.sub!(S('X'), S('Y')))
@@ -823,9 +835,11 @@
 
     a = S("foo")
     a.taint
+    a.untrust
     b = a.replace(S("xyz"))
     assert_equal(S("xyz"), b)
     assert(b.tainted?)
+    assert(b.untrusted?)
 
     s = "foo" * 100
     s2 = ("bar" * 100).dup
@@ -1170,7 +1184,10 @@
 
     a = S("hello")
     a.taint
-    assert(a.sub(/./, S('X')).tainted?)
+    a.untrust
+    x = a.sub(/./, S('X'))
+    assert(x.tainted?)
+    assert(x.untrusted?)
 
     o = Object.new
     def o.to_str; "bar"; end
@@ -1211,8 +1228,10 @@
 
     r = S('X')
     r.taint
+    r.untrust
     a.sub!(/./, r)
     assert(a.tainted?) 
+    assert(a.untrusted?) 
   end
 
   def test_succ
Index: test/ruby/test_object.rb
===================================================================
--- test/ruby/test_object.rb	(revision 18544)
+++ test/ruby/test_object.rb	(working copy)
@@ -320,4 +320,59 @@
       1.extend
     end
   end
+
+  def test_untrusted
+    obj = lambda {
+      $SAFE = 4
+      x = Object.new
+      x.instance_eval { @foo = 1 }
+      x
+    }.call
+    assert_equal(true, obj.untrusted?)
+    assert_equal(true, obj.tainted?)
+
+    x = Object.new
+    assert_equal(false, x.untrusted?)
+    assert_raise(SecurityError) do
+      lambda {
+        $SAFE = 4
+        x.instance_eval { @foo = 1 }
+      }.call
+    end
+
+    x = Object.new
+    x.taint
+    assert_raise(SecurityError) do
+      lambda {
+        $SAFE = 4
+        x.instance_eval { @foo = 1 }
+      }.call
+    end
+
+    x.untrust
+    assert_equal(true, x.untrusted?)
+    assert_nothing_raised do
+      lambda {
+        $SAFE = 4
+        x.instance_eval { @foo = 1 }
+      }.call
+    end
+
+    x.trust
+    assert_equal(false, x.untrusted?)
+    assert_raise(SecurityError) do
+      lambda {
+        $SAFE = 4
+        x.instance_eval { @foo = 1 }
+      }.call
+    end
+
+    a = Object.new
+    a.untrust
+    assert_equal(true, a.untrusted?)
+    b = a.dup
+    assert_equal(true, b.untrusted?)
+    c = a.clone
+    assert_equal(true, c.untrusted?)
+  end
 end

In This Thread