diff options
author | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-03-11 22:15:11 +0000 |
---|---|---|
committer | nobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2010-03-11 22:15:11 +0000 |
commit | 1dcf1174ea2a803e6905a04760121fe1426035b3 (patch) | |
tree | 3f37ee14e1b8c7b5f6f9ce6e1e978bbf1d12d177 | |
parent | 9a5b57f61fd9ef14b1bc6c0b540c0edbb86a409a (diff) |
* ruby.c (ruby_init_loadpath_safe, ruby_init_gems): set and remove
TMP_RUBY_PREFIX.
* variable.c (rb_mod_remove_const): new function.
* tool/compile_prelude.rb: split each preludes.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@26881 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | include/ruby/intern.h | 1 | ||||
-rw-r--r-- | ruby.c | 10 | ||||
-rwxr-xr-x | tool/compile_prelude.rb | 222 | ||||
-rw-r--r-- | variable.c | 11 |
5 files changed, 172 insertions, 81 deletions
@@ -1,3 +1,12 @@ +Fri Mar 12 07:15:08 2010 Nobuyoshi Nakada <nobu@ruby-lang.org> + + * ruby.c (ruby_init_loadpath_safe, ruby_init_gems): set and remove + TMP_RUBY_PREFIX. + + * variable.c (rb_mod_remove_const): new function. + + * tool/compile_prelude.rb: split each preludes. + Fri Mar 12 07:09:20 2010 Nobuyoshi Nakada <nobu@ruby-lang.org> * Makefile.in (config.status): setup MINIRUBY environment for diff --git a/include/ruby/intern.h b/include/ruby/intern.h index ebbdd713b2..61f642b06a 100644 --- a/include/ruby/intern.h +++ b/include/ruby/intern.h @@ -817,6 +817,7 @@ VALUE rb_const_get(VALUE, ID); VALUE rb_const_get_at(VALUE, ID); VALUE rb_const_get_from(VALUE, ID); void rb_const_set(VALUE, ID, VALUE); +VALUE rb_const_remove(VALUE, ID); VALUE rb_mod_const_missing(VALUE,VALUE); VALUE rb_cvar_defined(VALUE, ID); void rb_cvar_set(VALUE, ID, VALUE); @@ -358,7 +358,7 @@ ruby_init_loadpath_safe(int safe_level) #if defined _WIN32 || defined __CYGWIN__ # if VARIABLE_LIBPATH - sopath = rb_str_tmp_new(MAXPATHLEN); + sopath = rb_str_new(0, MAXPATHLEN); libpath = RSTRING_PTR(sopath); GetModuleFileName(libruby, libpath, MAXPATHLEN); # else @@ -390,7 +390,7 @@ ruby_init_loadpath_safe(int safe_level) const int win_to_posix = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; size_t newsize = cygwin_conv_path(win_to_posix, libpath, 0, 0); if (newsize > 0) { - VALUE rubylib = rb_str_tmp_new(newsize); + VALUE rubylib = rb_str_new(0, newsize); p = RSTRING_PTR(rubylib); if (cygwin_conv_path(win_to_posix, libpath, p, newsize) == 0) { rb_str_resize(sopath, 0); @@ -418,8 +418,10 @@ ruby_init_loadpath_safe(int safe_level) strlcpy(libpath, ".", sizeof(libpath)); p = libpath + 1; } +#define PREFIX_PATH() rb_str_new(libpath, baselen) #else rb_str_set_len(sopath, p - libpath); +#define PREFIX_PATH() sopath #endif baselen = p - libpath; @@ -428,6 +430,7 @@ ruby_init_loadpath_safe(int safe_level) #define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), path, len) #else #define RUBY_RELATIVE(path, len) rubylib_mangled_path(path, len) +#define PREFIX_PATH() rubylib_mangled_path(RUBY_LIB_PREFIX, sizeof(RUBY_LIB_PREFIX)-1) #endif #define incpush(path) rb_ary_push(load_path, (path)) load_path = GET_VM()->load_path; @@ -441,6 +444,8 @@ ruby_init_loadpath_safe(int safe_level) incpush(RUBY_RELATIVE(paths, len)); paths += len + 1; } + + rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), rb_obj_freeze(PREFIX_PATH())); } @@ -1086,6 +1091,7 @@ ruby_init_gems(int enable) { if (enable) rb_define_module("Gem"); Init_prelude(); + rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX")); } static int diff --git a/tool/compile_prelude.rb b/tool/compile_prelude.rb index 7476e3910f..93a6dd9cf0 100755 --- a/tool/compile_prelude.rb +++ b/tool/compile_prelude.rb @@ -4,108 +4,170 @@ # Since $(BASERUBY) may be older than Ruby 1.9, # Ruby 1.9 feature should not be used. -$:.unshift(File.expand_path("../..", __FILE__)) +require 'erb' -preludes = ARGV.dup -outfile = preludes.pop -init_name = outfile[/\w+(?=_prelude.c\b)/] || 'prelude' +class Prelude + SRCDIR = File.dirname(File.dirname(__FILE__)) + $:.unshift(SRCDIR) -C_ESC = { - "\\" => "\\\\", - '"' => '\"', - "\n" => '\n', -} + C_ESC = { + "\\" => "\\\\", + '"' => '\"', + "\n" => '\n', + } -0x00.upto(0x1f) {|ch| C_ESC[[ch].pack("C")] ||= "\\%03o" % ch } -0x7f.upto(0xff) {|ch| C_ESC[[ch].pack("C")] = "\\%03o" % ch } -C_ESC_PAT = Regexp.union(*C_ESC.keys) + 0x00.upto(0x1f) {|ch| C_ESC[[ch].pack("C")] ||= "\\%03o" % ch } + 0x7f.upto(0xff) {|ch| C_ESC[[ch].pack("C")] = "\\%03o" % ch } + C_ESC_PAT = Regexp.union(*C_ESC.keys) -def c_esc(str) - '"' + str.gsub(C_ESC_PAT) { C_ESC[$&] } + '"' -end -def prelude_name(*path_nests) - prelude = path_nests.map{|prelude_path| File.basename(prelude_path, ".rb") }.join(":") - "<internal:" + prelude + ">" -end + def c_esc(str) + '"' + str.gsub(C_ESC_PAT) { C_ESC[$&] } + '"' + end + def prelude_base(filename) + filename[/\A#{Regexp.quote(SRCDIR)}\/(.*?)(\.rb)?\z/om, 1] + end + def prelude_name(filename) + "<internal:" + prelude_base(filename) + ">" + end -mkconf = nil -setup_ruby_prefix = nil -teardown_ruby_prefix = nil -lines_list = preludes.map {|filename| - lines = [] - need_ruby_prefix = false - File.readlines(filename).each {|line| - line.gsub!(/RbConfig::CONFIG\["(\w+)"\]/) { - key = $1 - unless mkconf - require './rbconfig' - mkconf = RbConfig::MAKEFILE_CONFIG.merge('prefix'=>'#{TMP_RUBY_PREFIX}') - setup_ruby_prefix = "TMP_RUBY_PREFIX = $:.reverse.find{|e|e!=\".\"}.sub(%r{(.*)/lib/.*}m, \"\\\\1\")\n" - teardown_ruby_prefix = 'Object.class_eval { remove_const "TMP_RUBY_PREFIX" }' - end - if RbConfig::MAKEFILE_CONFIG.has_key? key - val = RbConfig.expand("$(#{key})", mkconf) - need_ruby_prefix = true if /\A\#\{TMP_RUBY_PREFIX\}/ =~ val - c_esc(val) - else - "nil" - end - } - if /require\s*\(?\s*(["'])(.*?)\1\s*\)?/ =~ line - orig, path = $&, $2 - srcdir = File.expand_path("../..", __FILE__) - path = File.expand_path(path, srcdir) - if File.exist?(path) - lines << c_esc("eval(") - File.readlines(path).each do |line| - lines << c_esc(line.dump) + def initialize(preludes) + @mkconf = nil + @have_sublib = false + @need_ruby_prefix = false + @preludes = {} + @mains = preludes.map {|filename| translate(filename)[0]} + end + + def translate(filename, sub = false) + idx = @preludes[filename] + return idx if idx + lines = [] + @preludes[filename] = result = [@preludes.size, filename, lines, sub] + File.readlines(filename).each do |line| + line.gsub!(/RbConfig::CONFIG\["(\w+)"\]/) { + key = $1 + unless @mkconf + require './rbconfig' + @mkconf = RbConfig::MAKEFILE_CONFIG.merge('prefix'=>'#{TMP_RUBY_PREFIX}') + end + if RbConfig::MAKEFILE_CONFIG.has_key? key + val = RbConfig.expand("$(#{key})", @mkconf) + @need_ruby_prefix ||= /\A\#\{TMP_RUBY_PREFIX\}/ =~ val + c_esc(val) + else + "nil" + end + } + line.sub!(/require\s*\(?\s*(["'])(.*?)\1\)?/) do + orig, path = $&, $2 + path = File.join(SRCDIR, path) + if File.exist?(path) + @have_sublib = true + "TMP_RUBY_PREFIX.require(#{translate(path, true)[0]})" + else + orig end - lines << c_esc(", TOPLEVEL_BINDING, %s, %d)" % [ prelude_name(filename, path).dump, 1]) - else - lines << c_esc(orig) end - else lines << c_esc(line) end - } - setup_lines = [] - if need_ruby_prefix - setup_lines << c_esc(setup_ruby_prefix) - lines << c_esc(teardown_ruby_prefix) + result end - [setup_lines, lines] -} - -require 'erb' -tmp = ERB.new(<<'EOS', nil, '%').result(binding) + def emit(outfile) + init_name = outfile[/\w+(?=_prelude.c\b)/] || 'prelude' + erb = ERB.new(<<'EOS', nil, '%') /* -*-c-*- THIS FILE WAS AUTOGENERATED BY tool/compile_prelude.rb. DO NOT EDIT. - soruces: <%= preludes.join(', ') %> + soruces: <%= @preludes.map {|n,*| prelude_base(n)}.join(', ') %> */ #include "ruby/ruby.h" #include "vm_core.h" -% preludes.zip(lines_list).each_with_index {|(prelude, (setup_lines, lines)), i| -static const char prelude_name<%=i%>[] = <%=c_esc(prelude_name(prelude))%>; +% preludes = @preludes.values.sort +% preludes.each {|i, prelude, lines, sub| + +static const char prelude_name<%=i%>[] = <%=c_esc(prelude_name(*prelude))%>; static const char prelude_code<%=i%>[] = -% (setup_lines+lines).each {|line| +% lines.each {|line| <%=line%> % } ; % } +#define PRELUDE_COUNT <%=@have_sublib ? preludes.size : 0%> + +% if @have_sublib or @need_ruby_prefix +struct prelude_env { + volatile VALUE prefix_path; +#if PRELUDE_COUNT > 0 + char loaded[PRELUDE_COUNT]; +#endif +}; + +static VALUE +prelude_prefix_path(VALUE self) +{ + struct prelude_env *ptr = DATA_PTR(self); + return ptr->prefix_path; +} +% end + +% if @have_sublib +static VALUE +prelude_require(VALUE self, VALUE nth) +{ + struct prelude_env *ptr = DATA_PTR(self); + VALUE code, name; + int n = FIX2INT(nth); + + if (n > PRELUDE_COUNT) return Qfalse; + if (ptr->loaded[n]) return Qfalse; + ptr->loaded[n] = 1; + switch (n) { +% @preludes.each_value do |i, prelude, lines, sub| +% if sub + case <%=i%>: + code = rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1); + name = rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1); + break; +% end +% end + default: + return Qfalse; + } + rb_iseq_eval(rb_iseq_compile(code, name, INT2FIX(1))); + return Qtrue; +} + +% end void Init_<%=init_name%>(void) { -% lines_list.each_with_index {|(setup_lines, lines), i| - rb_iseq_eval(rb_iseq_compile( - rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1), - rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1), - INT2FIX(<%=1-setup_lines.length%>))); +% if @have_sublib or @need_ruby_prefix + struct prelude_env memo; + ID name = rb_intern("TMP_RUBY_PREFIX"); + VALUE prelude = Data_Wrap_Struct(rb_cData, 0, 0, &memo); + + memo.prefix_path = rb_const_remove(rb_cObject, name); + rb_const_set(rb_cObject, name, prelude); + rb_define_singleton_method(prelude, "to_s", prelude_prefix_path, 0); +% end +% if @have_sublib + memset(memo.loaded, 0, sizeof(memo.loaded)); + rb_define_singleton_method(prelude, "require", prelude_require, 1); +% end +% preludes.each do |i, prelude, lines, sub| +% next if sub + rb_iseq_eval(rb_iseq_compile( + rb_usascii_str_new(prelude_code<%=i%>, sizeof(prelude_code<%=i%>) - 1), + rb_usascii_str_new(prelude_name<%=i%>, sizeof(prelude_name<%=i%>) - 1), + INT2FIX(1))); +% end +% if @have_sublib or @need_ruby_prefix + rb_gc_force_recycle(prelude); +% end -% } #if 0 % preludes.length.times {|i| puts(prelude_code<%=i%>); @@ -113,8 +175,14 @@ Init_<%=init_name%>(void) #endif } EOS + tmp = erb.result(binding) + open(outfile, 'w'){|f| + f << tmp + } + end +end -open(outfile, 'w'){|f| - f << tmp -} +preludes = ARGV.dup +outfile = preludes.pop +Prelude.new(preludes).emit(outfile) diff --git a/variable.c b/variable.c index 62256a049e..d7b99f180b 100644 --- a/variable.c +++ b/variable.c @@ -1633,12 +1633,19 @@ VALUE rb_mod_remove_const(VALUE mod, VALUE name) { const ID id = rb_to_id(name); - VALUE val; - st_data_t v, n = id; if (!rb_is_const_id(id)) { rb_name_error(id, "`%s' is not allowed as a constant name", rb_id2name(id)); } + return rb_const_remove(mod, id); +} + +VALUE +rb_const_remove(VALUE mod, ID id) +{ + VALUE val; + st_data_t v, n = id; + if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove constant"); if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); |