Freeze, frozen? in extensions

I’m poking around in the 1.8.1 ext/ sources and I notice that there are
very, very few uses of rb_check_frozen. I expected to see the C extensions
calling rb_check_frozen before modifying them. What am I overlooking? Is
it just not necessary?

Tim Hunter wrote:

I’m poking around in the 1.8.1 ext/ sources and I notice that there are
very, very few uses of rb_check_frozen. I expected to see the C extensions
calling rb_check_frozen before modifying them. What am I overlooking? Is
it just not necessary?

Calling a C extension which uses rb_str_modify() and /not/ rb_check_frozen_p()
on a string that’s frozen before the call gives:

D:/ruby/DfB/rb6062.TMP:3:in `call’: can’t modify frozen string (TypeError)

No reason why that should be expected, though.
You could have two exts that do the same job – one causing a TypeError,
but not the other.

As a Ruby String points to a C string, it would easily be possible for
an ext just to overwrite part of the C string even if it had been frozen
but (you made me think) Ruby objects always are/should be modified via
the API rather than directly which allows Ruby to check things such as
/frozen/ status.

That may be a rule which just feels right to my narrow experience.
If I learned it, it was only a few moments ago.
I’d retract it if someone offered the glaring exception(s) :slight_smile:

daz

Hi,

···

In message “freeze, frozen? in extensions” on 04/03/07, Tim Hunter cyclists@nc.rr.com writes:

I’m poking around in the 1.8.1 ext/ sources and I notice that there are
very, very few uses of rb_check_frozen. I expected to see the C extensions
calling rb_check_frozen before modifying them. What am I overlooking? Is
it just not necessary?

I encourage extension writers to add frozen/security check to their
extensions.

						matz.

As a Ruby String points to a C string, it would easily be possible for
an ext just to overwrite part of the C string even if it had been frozen
but (you made me think) Ruby objects *always* are/should be modified via
the API rather than directly which allows Ruby to check things such as
/frozen/ status.

well, I can give you an exception. In plruby you have

        vid = INT2NUM(typoid);
        klass = rb_hash_aref(plruby_classes, vid);
        if (NIL_P(klass)) {
            klass = rb_hash_aref(plruby_conversions, vid);
            if (NIL_P(klass)) {
                st_insert(RHASH(plruby_classes)->tbl, vid, Qfalse);
            }
            else {
                klass = rb_const_get(rb_cObject, NUM2INT(klass));
                st_insert(RHASH(plruby_classes)->tbl, vid, klass);
            }
        }

It's trying to search if it exist a class associated with a postgres type,
to call a conversion method.

Now there is rb_hash_aref() but it use st_insert() rather than
rb_hash_aset(). The reason is simple, plruby can run with $SAFE >= 4 and
in this case ruby will give an error

svg% ruby -e 'a = {}; $SAFE = 4; a[12] = 24'
-e:1:in `=': Insecure: can't modify hash (SecurityError)
        from -e:1
svg%

because I'm *sure* that it don't exist a security problem in this case it
use st_insert() rather than the standard API function to bypass the
security mechanism

Guy Decoux

Thanks, matz! I spent most of yesterday afternoon adding calls to
rb_check_frozen to my extension. Now I’m trying to add meaningful
implementations of dup and clone.

···

On Mon, 8 Mar 2004 13:04:12 +0900, matz@ruby-lang.org (Yukihiro Matsumoto) wrote:

I encourage extension writers to add frozen/security check to their
extensions.

  					matz.

Today I see that I my original post was terse to the point of being
incomprehensible. What I was trying to ask was “How do I support the
freeze method in my C extension? That is, suppose a script calls the
freeze method on one of my objects, and then uses a method that modifies
that object. What should I do?”

I examined the Ruby sources and discovered the “rb_check_frozen” function.
This function tests the frozen state of the object and if the object is
frozen, raises a TypeError exception. So I suppose that every method in my
classes that modifies the object should call rb_check_frozen to make sure
the object isn’t frozen before proceeding. I poked around a bit in the
code that implements the built-in classes (for example, array.c) and see
that this seems to be the case.

To confirm my plan I started looking at the code for the standard
libraries that are written in C, but I saw very few calls to
rb_check_frozen. This makes me wonder, have I misunderstood how to support
frozen objects in C?

···

On Sun, 07 Mar 2004 23:49:09 +0900, ts wrote:

Now there is rb_hash_aref() but it use st_insert() rather than
rb_hash_aset(). The reason is simple, plruby can run with $SAFE >= 4
and in this case ruby will give an error

svg% ruby -e ‘a = {}; $SAFE = 4; a[12] = 24’ -e:1:in `=': Insecure:
can’t modify hash (SecurityError)
from -e:1
svg%

because I’m sure that it don’t exist a security problem in this case
it use st_insert() rather than the standard API function to bypass the
security mechanism

ts wrote:

As a Ruby String points to a C string, it would easily be possible for
an ext just to overwrite part of the C string even if it had been frozen
but (you made me think) Ruby objects always are/should be modified via
the API rather than directly which allows Ruby to check things such as
/frozen/ status.

well, I can give you an exception. In plruby you have

    vid = INT2NUM(typoid);
    klass = rb_hash_aref(plruby_classes, vid);
    if (NIL_P(klass)) {
        klass = rb_hash_aref(plruby_conversions, vid);
        if (NIL_P(klass)) {
            st_insert(RHASH(plruby_classes)->tbl, vid, Qfalse);
        }
        else {
            klass = rb_const_get(rb_cObject, NUM2INT(klass));
            st_insert(RHASH(plruby_classes)->tbl, vid, klass);
        }
    }

It’s trying to search if it exist a class associated with a postgres type,
to call a conversion method.

Now there is rb_hash_aref() but it use st_insert() rather than
rb_hash_aset(). The reason is simple, plruby can run with $SAFE >= 4 and
in this case ruby will give an error

svg% ruby -e ‘a = {}; $SAFE = 4; a[12] = 24’
-e:1:in `=': Insecure: can’t modify hash (SecurityError)
from -e:1
svg%

because I’m sure that it don’t exist a security problem in this case it
use st_insert() rather than the standard API function to bypass the
security mechanism

Guy Decoux

I’m checking for holes in my life-boat.

3-)

daz

Today I see that I my original post was terse to the point of being
incomprehensible. What I was trying to ask was "How do I support the
freeze method in my C extension? That is, suppose a script calls the
freeze method on one of my objects, and then uses a method that modifies
that object. What should I do?"

raise an error.

To confirm my plan I started looking at the code for the standard
libraries that are written in C, but I saw very few calls to
rb_check_frozen. This makes me wonder, have I misunderstood how to support
frozen objects in C?

No, but like said previously by "daz" <dooby@d10.karoo.co.uk>, in many
case a C extension will use the standard API function and ruby will make
the test. Uf this is not the case add the test. For example, mmap has

svg% grep frozen mmap-0.2.4/*.c
        rb_error_frozen("mmap"); \
        if (t_mm->flag & MM_FROZEN) rb_error_frozen("mmap");
    if (t_mm->flag & MM_FROZEN) rb_error_frozen("mmap");
        rb_error_frozen("mmap");
    if (str->flag & MM_FROZEN) rb_error_frozen("mmap");
svg%

Guy Decoux

Tim Hunter wrote:

To confirm my plan I started looking at the code for the standard
libraries that are written in C, but I saw very few calls to
rb_check_frozen. This makes me wonder, have I misunderstood how to support
frozen objects in C?

Did you look for use of the OBJ_FROZEN(obj) macro, also ?

daz

Good suggestion! I see it used in openssl and stringio.

···

On Sun, 07 Mar 2004 16:04:46 +0000, daz wrote:

Did you look for use of the OBJ_FROZEN(obj) macro, also ?

“ts” decoux@moulon.inra.fr schrieb im Newsbeitrag
news:200403071546.i27FkgK20961@moulon.inra.fr

Today I see that I my original post was terse to the point of being
incomprehensible. What I was trying to ask was “How do I support the
freeze method in my C extension? That is, suppose a script calls the
freeze method on one of my objects, and then uses a method that
modifies
that object. What should I do?”

raise an error.

To confirm my plan I started looking at the code for the standard
libraries that are written in C, but I saw very few calls to
rb_check_frozen. This makes me wonder, have I misunderstood how to
support
frozen objects in C?

No, but like said previously by “daz” dooby@d10.karoo.co.uk, in many
case a C extension will use the standard API function and ruby will make
the test.

Wouldn’t it be more precise to say that those standard API methods will make
the test? I mean, the interpreter won’t know which methods are “const” and
which aren’t, but those methods will know.

Just my 0.02 EUR…

robert

"ts" <decoux@moulon.inra.fr> schrieb im Newsbeitrag
news:200403071546.i27FkgK20961@moulon.inra.fr...

case a C extension will use the standard API function and ruby will make
the test.

Wouldn't it be more precise to say that those standard API methods will make
the test? I mean, the interpreter won't know which methods are "const" and
which aren't, but those methods will know.

It depend what you call ruby :slight_smile:

Guy Decoux