This is normal ?

pigeon% cat b.rb
#!/usr/bin/ruby
cat = Struct.new("Cat", :name, :age, :life)
a = cat.new("cat", 12, 7)
Thread.new do
   abort_on_exception = true
   $SAFE = 4
   a.life -= 1
end.join
p a.life
pigeon% 

pigeon% b.rb
6
pigeon%

 It's possible to modify a struct with $SAFE >= 4 (this is very dangerous
for cats :-))
 
pigeon% diff -u struct.c.old struct.c
--- struct.c.old        Sun Aug  5 15:17:44 2001
+++ struct.c    Sun Aug  5 15:35:03 2001
@@ -124,6 +124,15 @@
     rb_struct_ref9,
 };
 
+static void
+rb_struct_modify(s)
+    VALUE s;
+{
+    if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
+    if (!OBJ_TAINTED(s) && rb_safe_level() >= 4)
+       rb_raise(rb_eSecurityError, "Insecure: can't modify Struct");
+}
+
 static VALUE
 rb_struct_set(obj, val)
     VALUE obj, val;
@@ -135,6 +144,7 @@
     if (NIL_P(member)) {
        rb_bug("non-initialized struct");
     }
+    rb_struct_modify(obj);
     for (i=0; i<RARRAY(member)->len; i++) {
        slot = RARRAY(member)->ptr[i];
        if (rb_id_attrset(SYM2ID(slot)) == rb_frame_last_func()) {
@@ -253,6 +263,7 @@
     VALUE size;
     long n;
 
+    rb_struct_modify(self);
     size = iv_get(klass, "__size__");
     n = FIX2LONG(size);
     if (n < RARRAY(values)->len) {
@@ -473,7 +484,7 @@
        rb_bug("non-initialized struct");
     }
 
-    if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
+    rb_struct_modify(s);
     len = RARRAY(member)->len;
     for (i=0; i<len; i++) {
        if (SYM2ID(RARRAY(member)->ptr[i]) == id) {
@@ -504,7 +515,7 @@
         rb_raise(rb_eIndexError, "offset %d too large for struct(size:%d)",
                 i, RSTRUCT(s)->len);
     }
-    if (OBJ_FROZEN(s)) rb_error_frozen("Struct");
+    rb_struct_modify(s);
     return RSTRUCT(s)->ptr[i] = val;
 }
 
pigeon% 

pigeon% ruby b.rb
b.rb:7:in `life=': Insecure: can't modify Struct (SecurityError)
        from b.rb:4:in `join'
        from b.rb:4
pigeon% 


Guy Decoux