freeze, frozen? in extensions

T

Tim Hunter

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?
 
D

daz

Tim said:
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) :)


daz
 
T

ts

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

Tim Hunter

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

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?
 
T

ts

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

raise an error.

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

No, but like said previously by "daz" <[email protected]>, 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
 
D

daz

ts said:
d> As a Ruby String points to a C string, it would easily be possible for
d> an ext just to overwrite part of the C string even if it had been frozen
d> but (you made me think) Ruby objects *always* are/should be modified via
d> the API rather than directly which allows Ruby to check things such as
d> /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
 
D

daz

Tim said:
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
 
R

Robert Klemme

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

raise an error.

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

No, but like said previously by "daz" <[email protected]>, 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
 
T

ts

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

It depend what you call ruby :)


Guy Decoux
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,143
Messages
2,570,822
Members
47,368
Latest member
michaelsmithh

Latest Threads

Top