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
Memory Map
Eric Hodel | Wed, 30 Aug 2006 21:49:31 GMT
Here’s a picture of my Ruby process’ heap slots:
| BLACK | unknown (char*, VALUE *, struct st_table, etc.) |
|---|---|
| GRAY | free memory |
| RED | nodes (code) |
| GREEN | Ruby objects |
| WHITE | Miscellaneous interpreter objects |
If you look really closely in the original you can see a white pixel that is probably a struct SCOPE.
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).
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.
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.
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...
$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.
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
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.
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.


Articles