Is it considered Harmful?

B

Bill Kelly

From: "Sean O'Dell said:
You're wrong on that. It wouldn't crash Ruby to change the class of an
object. Objects already change their class when you turn them into
singletons. Changing it to any class of your choosing would be even simpler,
since creating a singleton involves inheriting all the old class methods;
changing a class wouldn't require all that work.

Supposed an object's class were changed to a different class
which was itself (or whose ancestor(s) were) implemented in 'C'
code. Something that expects that once it's initialized it
can go ahead and rely on its class invariants pointing to real
operating system file handles, window handles, etc.

Like, hypothetically,

"hello".class = OpenGLCanvas
"hello".class = IO

...or whatever. For example:

x = "hello"
x.class = OpenGLCanvas
x.PushMatrix()

kind of thing.

Should we expect a hard crash here? If so, is that OK because
it's "programmer error" and not really Ruby's fault?

I haven't done enough Smalltalk to know what #become would do
in such situations...


Regards,

Bill
 
T

ts

B> Should we expect a hard crash here? If so, is that OK because
B> it's "programmer error" and not really Ruby's fault?

It's always ruby fault when it crash with a .rb file


Guy Decoux
 
E

Eric Hodel

--eDyw1yV8HuEtd7LH
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
x =3D "hello"
x.class =3D OpenGLCanvas
x.PushMatrix()
=20
kind of thing.
=20
Should we expect a hard crash here? If so, is that OK because
it's "programmer error" and not really Ruby's fault?
=20
I haven't done enough Smalltalk to know what #become would do
in such situations...=20

Smalltalk's classes are better factored to handle such occurances.
Ruby's are not.

--=20
Eric Hodel - (e-mail address removed) - http://segment7.net
All messages signed with fingerprint:
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04


--eDyw1yV8HuEtd7LH
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (FreeBSD)

iD8DBQFA3FJiMypVHHlsnwQRAr7IAKCnjCyDVTjrad4fcI+P0AAWTA1KbwCgzPqB
0NfCePQRqGDLLc3qI9QlFmM=
=urHA
-----END PGP SIGNATURE-----

--eDyw1yV8HuEtd7LH--
 
P

Phil Tomson

It's a brave man that calls Guy 'wrong,' so I'm looking forward to
seeing your implementation of this.

I have to admit that I too had to do a double-take when I saw someone
saying the Guy was 'wrong'.

....we'll have to see how this plays out, but I have my suspicions ;-)


Phil
 
J

Jim Weirich

gabriele renzi said:
in evil.rb (you can find it at rubyforge) you even have Object#become
if you need it ;)

Are there limitations on evil.rb's implementation of become? How do you
get around Guy's concerns about crashing?
 
L

Lennon Day-Reynolds

It's usually Ruby's fault, except for the fact that you can, in "pure
Ruby" code, use modules like DL (which is, of course, implemented in
C) to do nasty pointer-munging -- it allows evil.rb's implementations
of #class= and #become, but could also let you start overwriting the
entire virtual memory space of the Ruby process with random noise. Is
it the Ruby interpreter's fault if the programmer suddenly decides to
go on a rampage inside the memory space of the entire process?

Lennon
 
J

Jim Weirich

Eric Hodel said:
Smalltalk's classes are better factored to handle such occurances.
Ruby's are not.

I found the following paragraph about Squeak Smalltalk interesting. Most
Smalltalks use an object table to aid in garbage collection. An added
benifit of the object table is that swapping two objects is just swapping
the pointers in the object table. Squeak doesn't use an object table, so
they had to work extra hard to make become: work. Here is the discussion
(from http://users.ipa.net/~dwighth/squeak/oopsla_squeak.html):

BEGIN QUOTE ===================

One more issue remained to be dealt with, and that was support of the
become operation without an object table. (The Smalltalk become
primitive atomically exchanges the identity of two objects; to
Smalltalk code, each object appears to turn into, or "become," the
other.) With an object table, the become primitive simply exchanges
the contents of two object table entries. Without an object table, it
requires a full scan of memory to replace every pointer to one object
with a pointer to the other. Since full memory scans are relatively
costly, we made two changes. First, we eliminated most uses of become
in the Squeak image by changing certain collection classes to store
their elements in separate Array objects instead of indexed fields.
However, become operations are essential when adding an instance
variable to a class with extant instances, as each instance must
mutate into a larger object to accommodate the new variable. So, our
second change was to restructure the primitive to one that exchanges
the identity of many objects at once. This allows all the instances
of a class to be mutated in a single pass through memory. The code
for this operation uses the same technique and, in fact, the very
same code, as that used to rectify pointers after compaction.

END QUOTE =====================
 
S

Sean O'Dell

Singletons are effectively subclasses of the original.

irb(main):001:0> a = /cat/
=> /cat/
irb(main):002:0> def a.speak; "meiow"; end
irb(main):005:0> a.speak
=> "meiow"
irb(main):006:0> a.class
=> Regexp

How would you handle
a = /cat/
a.class = File
a.read

It's a brave man that calls Guy 'wrong,' so I'm looking forward to
seeing your implementation of this.

How is that any different from:

class Regexp
include Enumerable
end

a = /cat/
a.each

You can do all sorts of crazy things in Ruby. Buyer beware. Enter at your own
risk.

Sean O'Dell
 
S

Sean O'Dell

S> You're wrong on that. It wouldn't crash Ruby to change the class of an

Just search in http://www.ruby-talk.org/

S> object. Objects already change their class when you turn them into
S> singletons. Changing it to any class of your choosing would be even
simpler, S> since creating a singleton involves inheriting all the old
class methods; S> changing a class wouldn't require all that work.

You have just forgotten that a class is an object ...

No I haven't. That has no bearing on whether or not you can change an
object's class.

Sean O'Dell
 
T

ts

L> It's usually Ruby's fault, except for the fact that you can, in "pure
L> Ruby" code, use modules like DL (which is, of course, implemented in

If you use a module like DL, it's not for me "pure ruby" code.

L> C) to do nasty pointer-munging -- it allows evil.rb's implementations
L> of #class= and #become, but could also let you start overwriting the
L> entire virtual memory space of the Ruby process with random noise. Is
L> it the Ruby interpreter's fault if the programmer suddenly decides to
L> go on a rampage inside the memory space of the entire process?

evil.rb is not distributed with ruby, if it want to crash ruby it can do
what it want.

The modification proposed is for the source of ruby : this is not the same
thing.


Guy Decoux
 
S

Sean O'Dell

S> It should be very easy to do. I'm wondering if a C extension could
possibly S> even do this.

You are right, a C extension can effectively crash ruby

Read carefully hash.c and array.c and just imagine what will be the result
if one method of hash.c will be applied to an array.

matz has one day say it in a message to ruby-talk : one information is
missing

You can do all sorts of things with Ruby, I see no reason why changing an
object's class would crash Ruby anymore than, say, redefining a method to
something different than an object expects, or including modules in a class
that don't belong there. Just be careful of what you're doing. I see no
FUNDAMENTAL reason why you couldn't change an object's class.

Sean O'Dell
 
S

Sean O'Dell

Supposed an object's class were changed to a different class
which was itself (or whose ancestor(s) were) implemented in 'C'
code. Something that expects that once it's initialized it
can go ahead and rely on its class invariants pointing to real
operating system file handles, window handles, etc.

No code should "expect" data to be there that isn't. If a C extension wraps a
native C struct as a Ruby object with Make_Struct, then when it unwraps it,
and gets nothing or a NULL pointer, it shouldn't continue to try and use it.
That's sloppy coding.

Sean O'Dell
 
D

Dave Thomas

How is that any different from:

class Regexp
include Enumerable
end

Modules (such as Enumerable) only add methods. Classes also have state.

Again, how would the File example work?

Cheers

Dave
 
S

Sean O'Dell

gabriele renzi said:

Are there limitations on evil.rb's implementation of become? How do you
get around Guy's concerns about crashing?

I don't know what crashing he's talking about, really. I see no reason for
Ruby to crash unless you, as a programmer, go out of your way to abuse a
feature like this such that you deliberately engineer a crash. I can
deliberately engineer crashes all day long right now, without such a feature.

Sean O'Dell
 
T

ts

D> Modules (such as Enumerable) only add methods.

This is worst than this : Enumerable rely on the method #each which is
implemented differently by each class, this is why it work


Guy Decoux
 
S

Sean O'Dell

Modules (such as Enumerable) only add methods. Classes also have state.

Again, how would the File example work?

a.read would do what #read does when it can't read because there's no open
file. What does #read do now when it encounters an error it can't handle?
Raise an exception?

Sean O'Dell
 
L

Lennon Day-Reynolds

Are there limitations on evil.rb's implementation of become? How do you
get around Guy's concerns about crashing?

The default implementation simply does a check to insure that you're
not trying to monkey with certain core classes (Object, Class, String,
etc.) in dangerous ways. It also has checks for circularity, and won't
allow you to call #become on immediate values (nil, true/false,
fixnums).

That being said, you can certainly still shoot yourself in the foot --
once you've done 'require "evil"', every object (including core
classes) has a method #internal_ptr, which gives you C-like raw access
to the memory space that object occupies.

Lennon
 
D

Dave Thomas

a.read would do what #read does when it can't read because there's no
open
file. What does #read do now when it encounters an error it can't
handle?
Raise an exception?

How does it know there's no open file? Go have a look at the code.


Cheers

Dave
 
M

Mauricio Fernández

You're wrong on that. It wouldn't crash Ruby to change the class of an
object.

Yes it will, in the current implementation.
You can download evil.rb, remove the safety checks in Object#become and
try

a = Object.new
a.class = String
a.size # or some other method from String

This is so because rb_str_* methods will treat the internal structure
as a RString, even though it's just a RObject.
Objects already change their class when you turn them into
singletons. Changing it to any class of your choosing would be even simpler,
since creating a singleton involves inheriting all the old class methods;
changing a class wouldn't require all that work.

While your description of the internal working of Ruby's singletons is
accurate (I'd say 'klass field' and not 'class', though), it's doesn't
change the fact that an unrestricted Object#become *is not* safe in all
circumstances, esp. when it involves Hash, Array, Regexp, File, String,
etc... objects, which are treated differently internally.

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Not only Guinness - Linux is good for you, too.
-- Banzai on IRC
 

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
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top