Reducing $SAFE

Eric Hodel | Thu, 31 Aug 2006 00:30:00 GMT

Ya you are correct, it won't let you change the safe level. I wonder how hard it would be to bypass it though using something like rubyinline?

Re: $SAFE =4 safe enough? via snacktime

require 'rubygems'
require 'inline'

class DeSafe
  inline do |builder|
    builder.prefix "RUBY_EXTERN int ruby_safe_level;"

    builder.c <<-EOC
      static void
      reduce() {
        ruby_safe_level = 0;
      }
    EOC
  end
end


$SAFE = ARGV.shift.to_i rescue 0

p $SAFE

DeSafe.new.reduce

p $SAFE
$ rm -fr ~/.ruby_inline/; ruby desafe.rb 4
desafe.rb:20:in `write': Insecure operation `write' at level 4 (SecurityError)
        from desafe.rb:20:in `p'
        from desafe.rb:20
$ rm -fr ~/.ruby_inline/; ruby desafe.rb 3
3
0

Posted in ,  | 4 comments

Memory Map

Eric Hodel | Wed, 30 Aug 2006 21:49:31 GMT

Here’s a picture of my Ruby process’ heap slots:

Memory Map

BLACKunknown (char*, VALUE *, struct st_table, etc.)
GRAYfree memory
REDnodes (code)
GREENRuby objects
WHITEMiscellaneous interpreter objects

If you look really closely in the original you can see a white pixel that is probably a struct SCOPE.

Posted in ,  | no comments

Memory Inspector

Eric Hodel | Wed, 30 Aug 2006 08:13:00 GMT

I've hacked into gc.c and added an alternative to ObjectSpace.each_object that gives you the contents of every heap slot in Ruby's memory space.

$ ./ruby -I ~/Work/p4/zss/src/RubyInline/dev/ ~/heapwalk.rb
[id, size, inspect]
0x001aa004 0x00000000                                                    :__free
0x001aa018 0x00000000                                                    :__free
0x001aa02c 0x00000000                                                    :__free
0x001aa040 0x00000000                                                    :__free
[the beginning is boring...]
0x001caa20 0x00000014                                           #<Class:Marshal>
0x001caa34 0x00000014                                                    :__node
0x001caa48 0x00000014                                                    :__node
0x001caa5c 0x0000000c                                                    Marshal
[but there's things like nodes, singleton classes, modules,]
0x001caae8 0x0000000c                #<NoMemoryError: failed to allocate memory>
0x001caafc 0x0000002d                                "failed to allocate memory"
0x001cab10 0x00000014                                                         []
[exceptions, strings, arrays and other objects,]
0x001ce5f8 0x00000014                                                  :__iclass
[included Modules,]
0x001dad30 0x00000014                                                   :__scope
[scopes, and some other stuff that's too hard to find]

It requires a hack to gc.c to gain access to the heap, but combined with Ryan's memory visualizer this might generate something usable.

Code will be available later I've audited my object size calculations (and have slept).

Posted in ,  | 3 comments

Unleashing ri

Eric Hodel | Sun, 27 Aug 2006 23:45:00 GMT

Now that ruby 1.8.5 has been released (Changelog) and ri includes a bunch more documentation and integrates with gems you just might be suffering from ri overload.
$ ri --system -l | wc -l
    8882
$ ri -l | wc -l
   11918
$ echo 11918 - 8882 | bc
3036
I have 31 extra gems installed, including Rails, which gives me a ton more at-my-fingertips documentation! Some people would rather have less documentation, and there are a handful of new options that control where ri will search for documentation.
$ ri -h
[...]

  --doc-dir, -d <dirname>
                  A directory to search for documentation. If not
                  specified, we search the standard rdoc/ri directories.
                  May be repeated.

       --system   Include documentation from Ruby's standard library:
                    /usr/local/share/ri/1.8/system

         --site   Include documentation from libraries installed in site_lib:
                    /usr/local/share/ri/1.8/site

         --home   Include documentation stored in ~/.rdoc:
                    /Users/drbrain/.rdoc

         --gems   Include documentation from Rubygems:
                    /usr/local/lib/ruby/gems/1.8/doc/*/ri

[...]
Options may also be passed in the 'RI' environment variable
$
I've set my RI environment variable is -T -f ansi to turn off the pager and give me fancy colors, but you can do mix-and-match options to your liking. To only search the system libraries by default, export RI='--system'. To make an alias that searches only rails documentation:
alias rri="ri -d /usr/local/lib/ruby/gems/1.8/doc/actionmailer*/ri \
              -d /usr/local/lib/ruby/gems/1.8/doc/actionpack*/ri \
              -d /usr/local/lib/ruby/gems/1.8/doc/actionwebservice*/ri \
              -d /usr/local/lib/ruby/gems/1.8/doc/activerecord*/ri \
              -d /usr/local/lib/ruby/gems/1.8/doc/activesupport*/ri \
              -T -f ansi"
(If you have multiple rails versions you'll need to explicitly list the versions of each gem.)
$ rri ActiveRecord::Base.find
----------------------------------------------- ActiveRecord::Base::find
     ActiveRecord::Base::find(*args)
------------------------------------------------------------------------
     Find operates with three different retrieval approaches:

[...]
Also, note that if you install multiple versions of a gem you'll either need to run gem cleanup and remove the old versions or manually remove their ri if you want the older versions to hang around. If you don't, you might get duplicate documentation.

Posted in ,  | no comments

Subclassing vs include

Eric Hodel | Wed, 23 Aug 2006 18:15:00 GMT

In memcached Basics for Rails Rob Sanheim asked:

[W]hy make the cached model a class to extend instead of a module? Whether or not a model is cached should be an implementation detail, and shouldn’t define the hierarchy for a class. I know I would rather not use the power of (single!) inheritance just to cache something, when a mix-in should be plenty powerful to do it.

The short answer is:

Using a class the correct way to overlay features on top of another class.

Here’s my long answer:

When you use a class you get super, and super is a beautiful thing. It automatically walks your class’ ancestors and calls the right method in the right order.

A module doesn’t have this property so you can’t use it to overlay features on top of a class. The class’ implementation will always be called before the module’s implementation.

Now you’re going to say something about using alias to shuffle methods around. You could do that, but you’ll have to do this for each method you want to overlay (five in CachedModel) which involves lots of extra typing “do_the_thingy_without_the_stuff” that you could have had for free (and more-prettily) with “super”.

You also get another problem that may cause subtle bugs. When you use alias to overlay features the order of execution is dependent upon the order the files are required in! Intentionally writing code where the behavior may change file load order gives me the heebie-jeebies.

Having to do all that work to get the benefits of a subclass tells me that a module isn’t powerful enough to do what a subclass can, so a module isn’t the right way to add a cache.

I avoid* using modules to overlay features of a class, but do use them to add orthogonal or complementary features. Typically when I write a module it ends up being used like Comparable, Enumerable or Singleton. When I need to do something invasive a subclass is better.

Finally, making the argument that adding caching to ActiveRecord::Base via a subclass shouldn’t define the inheritance argument is very subjective. I could justify using a subclass by saying that ActiveRecord is a data storage class, and CachedModel is just another data store. If you want caching, inherit from CachedModel. If you don’t want caching, inherit from ActiveRecord::Base.

Except void or where prohibited by law. Your milage may vary. Break glass in case of emergency.

Posted in , ,  | 9 comments

Finding primes with Rinda::TupleSpace

Eric Hodel | Sat, 19 Aug 2006 09:09:00 GMT

While at FOSCON 2006 I watched Lucas Carlson's presentation on Rinda and DRb, but he barely scratched the surface of Rinda's capabilities with his prime finding implementation.

Rinda::TupleSpace is more powerful than just a name service for DRb. Since a TupleSpace has synchronized access to all its items, you can use a TupleSpace to coordinate processes as well.

I started rewriting Lucas' DRb using prime finder at FOSCON, but wasn't able to finish it until now. This version coordinates all the activities of the prime finding via the TupleSpace. No locking is necessary in any of the code because the TupleSpace takes care of it for us. Read more...

Posted in , ,  | no comments

$stdout vs STDOUT

Eric Hodel | Thu, 17 Aug 2006 16:47:00 GMT

You may have noticed me using both $stdout and STDOUT in my last post and been puzzled by how I could use both.

When Ruby starts up the process’ standard output file descriptor is stored in both the constant STDOUT and the global variable $stdout. STDOUT holds the process’ original stdout while $stdout is reassignable. Kernel#puts and friends use $stdout to write their output, not STDOUT.

To be most-friendly, when you want to redirect stdout you should assign to $stdout instead of fiddling with STDOUT. When outputting to an explicit file descriptor, use $stdout or $stderr instead of STDOUT or STDERR.

STDOUT can only be changed by calling IO#reopen, but you can assign any object that responds to #write to $stdout, which is what made my ThreadOut hack work.

Posted in  | 1 comment

Setting $stdout per-thread

Eric Hodel | Wed, 16 Aug 2006 18:58:00 GMT

cdfh on #ruby-lang asked how to redirect $stdout per-thread and I came up with this solution, redirect via a thread-local variable:
##
# Allows $stdout to be set via Thread.current[:stdout] per thread.

module ThreadOut

  ##
  # Writes to Thread.current[:stdout] instead of STDOUT if the thread local is
  # set.

  def self.write(stuff)
    if Thread.current[:stdout] then
      Thread.current[:stdout].write stuff 
    else
      STDOUT.write stuff
    end
  end
  
end

$stdout = ThreadOut
Simple test:
require 'stringio'
require 'threadout'

s = StringIO.new

Thread.start do 
  Thread.current[:stdout] = s
  puts 'redirected to StringIO'
end.join

Thread.start do
  puts 'no redirection'
end.join

puts s.string
Output:
no redirection
redirected to StringIO

Posted in ,  | no comments

RDoc Mega Update

Eric Hodel | Sat, 05 Aug 2006 05:08:56 GMT

With many thanks to Hugh Sasse for doing much of the gruntwork, there will be a huge increase in RDoc available in Ruby 1.8.5. If you have the time, get the latest from CVS (HEAD or ruby_1_8) and make install install-doc, check it out, and report back anything busted, poorly worded, or in need of general cleanup.

I have until Sunday night to fix anything you find.

Posted in ,  | no comments

Ruby to JavaScript

Eric Hodel | Wed, 05 Jul 2006 21:35:04 GMT

Paul Battley wrote on the ruby-talk mailing list:

Here’s something for the hungry mob to tear apart: automatic Ruby to JavaScript conversion. It seems somehow wrong, like grafting a pretty girl’s head onto a donkey, but I’ve done it anyway!

[...]

It uses Ryan Davis et al’s ParseTree and Florian Gro’s ruby.js for most of the hard work. It’s still very limited, and there are many warts, not least of which is the requirement for an explicit receiver on every method.

That said, the code’s here: http://po-ru.com/files/ruby2js.tar.gz

This is a pretty nifty use of ParseTree, hopefully I’ll get him using ParseTree’s SexpProcessor, too.

UPDATE: The Convert Ruby to JavaScript homepage.

Posted in  | 1 comment

Older posts: 1 ... 3 4 5 6 7 8