summaryrefslogtreecommitdiff
path: root/src/plugins/scripts/ruby/weechat-ruby.c
diff options
context:
space:
mode:
authorEmmanuel Bouthenot <kolter@openics.org>2006-02-12 01:33:36 +0000
committerEmmanuel Bouthenot <kolter@openics.org>2006-02-12 01:33:36 +0000
commit06ecdfdd35d7b7a729ba8660d16b4c9a0cd62a09 (patch)
treea8f67f5948ffc7a6dcf5fafa9076a4e07034bd51 /src/plugins/scripts/ruby/weechat-ruby.c
parent00eef1c1bceb0042e8e177744ef9a4dce6b05d0d (diff)
downloadweechat-06ecdfdd35d7b7a729ba8660d16b4c9a0cd62a09.zip
fix some crash (unprotected code execution) and display some kind of backtrace when errors occurs
Diffstat (limited to 'src/plugins/scripts/ruby/weechat-ruby.c')
-rw-r--r--src/plugins/scripts/ruby/weechat-ruby.c151
1 files changed, 71 insertions, 80 deletions
diff --git a/src/plugins/scripts/ruby/weechat-ruby.c b/src/plugins/scripts/ruby/weechat-ruby.c
index 4f014e7eb..dc90544a5 100644
--- a/src/plugins/scripts/ruby/weechat-ruby.c
+++ b/src/plugins/scripts/ruby/weechat-ruby.c
@@ -48,83 +48,55 @@ VALUE mWeechat, mWeechatOutputs;
#define MOD_NAME_PREFIX "WeechatRubyModule"
int modnum = 0;
+typedef struct protect_call_arg {
+ VALUE recv;
+ ID mid;
+ int argc;
+ VALUE *argv;
+} protect_call_arg_t;
/*
- * protect_funcall0 :
- *
+ * protect_funcall0 : used to protect a function call
*/
static VALUE
-rb_funcall0 (VALUE args)
+protect_funcall0(VALUE arg)
{
- VALUE recv = rb_ary_shift (args);
- VALUE func = rb_ary_shift (args);
- VALUE argc = rb_ary_shift (args);
-
- return rb_funcall2(recv, rb_intern(STR2CSTR(func)), NUM2INT(argc), RARRAY(args)->ptr);
+ return rb_funcall2(((protect_call_arg_t *) arg)->recv,
+ ((protect_call_arg_t *) arg)->mid,
+ ((protect_call_arg_t *) arg)->argc,
+ ((protect_call_arg_t *) arg)->argv);
}
/*
- * protect_rescue0 :
- *
+ * rb_protect_funcall : function call in protect mode
*/
VALUE
-rb_rescue0 (VALUE func, VALUE error_info)
-{
- VALUE str = rb_funcall(error_info, rb_intern("to_s"), 0, NULL);
- VALUE errinfo = rb_inspect(ruby_errinfo);
-
- ruby_plugin->printf_server (ruby_plugin,
- "Ruby error: unable to run function \"%s\"",
- STR2CSTR(func));
- ruby_plugin->printf_server (ruby_plugin,
- "Ruby error: %s", STR2CSTR(str));
- ruby_plugin->printf_server (ruby_plugin,
- "Ruby error: %s", STR2CSTR(errinfo));
- //rb_backtrace ();
-
- return INT2FIX(PLUGIN_RC_KO);
-}
-
-
-/*
- * rb_rescue_funcall :
- *
- */
-
-
-VALUE
-rb_rescue_funcall (VALUE recv, VALUE func, int argc, ...)
+rb_protect_funcall(VALUE recv, ID mid, int *state, int argc, ...)
{
-
va_list ap;
- VALUE argv, ret;
+ VALUE *argv;
+ struct protect_call_arg arg;
- argv = rb_ary_new ();
-
- rb_ary_push (argv, recv);
- rb_ary_push (argv, func);
- rb_ary_push (argv, INT2FIX(argc));
-
if (argc > 0)
{
int i;
+ argv = ALLOCA_N(VALUE, argc);
va_start(ap, argc);
for (i = 0; i < argc; i++)
- rb_ary_push (argv, va_arg(ap, VALUE));
+ argv[i] = va_arg(ap, VALUE);
va_end(ap);
}
-
- ret = rb_rescue(rb_funcall0, argv, rb_rescue0, func);
-
- if (NIL_P(ret))
- ret = INT2FIX(PLUGIN_RC_KO);
-
- return ret;
+ else
+ argv = 0;
+ arg.recv = recv;
+ arg.mid = mid;
+ arg.argc = argc;
+ arg.argv = argv;
+ return rb_protect(protect_funcall0, (VALUE) &arg, state);
}
-
/*
* weechat_ruby_exec: execute a Ruby script
*/
@@ -135,15 +107,27 @@ weechat_ruby_exec (t_weechat_plugin *plugin,
char *function, char *server, char *arguments)
{
VALUE ruby_retcode;
-
+ int ruby_error;
/* make gcc happy */
(void) plugin;
ruby_current_script = script;
- ruby_retcode = rb_rescue_funcall ((VALUE) script->interpreter, rb_str_new2(function), 2,
- rb_str_new2((server == NULL) ? "" : server),
- rb_str_new2((arguments == NULL) ? "" : arguments));
+ ruby_retcode = rb_protect_funcall ((VALUE) script->interpreter, rb_intern(function),
+ &ruby_error, 2,
+ rb_str_new2((server == NULL) ? "" : server),
+ rb_str_new2((arguments == NULL) ? "" : arguments));
+ if (ruby_error)
+ {
+ ruby_plugin->printf_server (ruby_plugin,
+ "Ruby error: unable to run function \"%s\"",
+ function);
+
+ rb_eval_string_protect("Weechat.print(\"Ruby error: \" + $@.to_s)", NULL);
+ rb_eval_string_protect("Weechat.print(\"Ruby error: \" + $!.to_s)", NULL);
+
+ return PLUGIN_RC_KO;
+ }
return NUM2INT(ruby_retcode);
}
@@ -1176,12 +1160,21 @@ weechat_ruby_get_nick_info (VALUE class, VALUE server, VALUE channel)
static VALUE
weechat_ruby_output(VALUE self, VALUE str)
{
+ char *msg, *p;
/* make gcc happy */
(void) self;
- ruby_plugin->printf_server (ruby_plugin,
- "Ruby stdout/stderr: %s",
- STR2CSTR(str));
+ msg = strdup(STR2CSTR(str));
+
+ while ((p = strrchr(msg, '\n')) != NULL)
+ *p = '\0';
+
+ if (strlen(msg) > 0)
+ ruby_plugin->printf_server (ruby_plugin,
+ "Ruby stdout/stderr: %s", msg);
+ if (msg)
+ free (msg);
+
return Qnil;
}
@@ -1194,8 +1187,8 @@ int
weechat_ruby_load (t_weechat_plugin *plugin, char *filename)
{
char modname[64];
- VALUE curModule;
- VALUE ruby_retcode;
+ VALUE curModule, ruby_retcode;
+ int ruby_error;
plugin->printf_server (plugin, "Loading Ruby script \"%s\"", filename);
ruby_current_script = NULL;
@@ -1207,8 +1200,8 @@ weechat_ruby_load (t_weechat_plugin *plugin, char *filename)
ruby_current_script_filename = strdup (filename);
- ruby_retcode = rb_rescue_funcall (curModule, rb_str_new2("load_eval_file"),
- 1, rb_str_new2(filename));
+ ruby_retcode = rb_protect_funcall (curModule, rb_intern("load_eval_file"),
+ &ruby_error, 1, rb_str_new2(filename));
free (ruby_current_script_filename);
@@ -1224,6 +1217,8 @@ weechat_ruby_load (t_weechat_plugin *plugin, char *filename)
filename);
break;
case 2:
+
+
ruby_plugin->printf_server (ruby_plugin,
"Ruby error: error while loading file \"%s\"",
filename);
@@ -1246,16 +1241,18 @@ weechat_ruby_load (t_weechat_plugin *plugin, char *filename)
return 0;
}
- ruby_retcode = rb_rescue_funcall (curModule, rb_str_new2("weechat_init"), 0);
+ ruby_retcode = rb_protect_funcall (curModule, rb_intern("weechat_init"), &ruby_error, 0);
- if (NUM2INT(ruby_retcode) != PLUGIN_RC_OK)
+ if (ruby_error)
{
ruby_plugin->printf_server (ruby_plugin,
"Ruby error: unable to eval weechat_init in file \"%s\"",
filename);
+ rb_eval_string_protect("Weechat.print(\"Ruby error: \" + $@.to_s)", NULL);
+ rb_eval_string_protect("Weechat.print(\"Ruby error: \" + $!.to_s)", NULL);
+
if (ruby_current_script != NULL)
weechat_script_remove (plugin, &ruby_scripts, ruby_current_script);
-
return 0;
}
@@ -1266,7 +1263,7 @@ weechat_ruby_load (t_weechat_plugin *plugin, char *filename)
filename);
return 0;
}
-
+
ruby_current_script->interpreter = (VALUE *) curModule;
rb_gc_register_address (ruby_current_script->interpreter);
@@ -1492,16 +1489,9 @@ weechat_plugin_init (t_weechat_plugin *plugin)
{
int ruby_error;
char *weechat_ruby_code =
- {
- "class IO\n"
- " def write(msg)\n"
- " msg.each {|s|\n"
- " if (s.chomp != \"\")\n"
- " WeechatOutputs.write(msg.chomp)\n"
- " end\n"
- " }\n"
- " end\n"
- "end\n"
+ {
+ "$stdout = WeechatOutputs\n"
+ "$stderr = WeechatOutputs\n"
"\n"
"class Module\n"
" @load_eval_file_error = ''\n"
@@ -1575,6 +1565,8 @@ weechat_plugin_init (t_weechat_plugin *plugin)
/* redirect stdin and stdout */
mWeechatOutputs = rb_define_module("WeechatOutputs");
rb_define_singleton_method(mWeechatOutputs, "write", weechat_ruby_output, 1);
+ rb_define_singleton_method(mWeechatOutputs, "puts", weechat_ruby_output, 1);
+ rb_define_singleton_method(mWeechatOutputs, "p", weechat_ruby_output, 1);
plugin->cmd_handler_add (plugin, "ruby",
"list/load/unload Ruby scripts",
@@ -1588,9 +1580,8 @@ weechat_plugin_init (t_weechat_plugin *plugin)
plugin->mkdir_home (plugin, "ruby/autoload");
rb_eval_string_protect(weechat_ruby_code, &ruby_error);
- if (ruby_error) {
+ if (ruby_error) {
VALUE ruby_error_info = rb_inspect(ruby_errinfo);
- rb_backtrace();
ruby_plugin->printf_server (ruby_plugin,
"Ruby error: unable to eval weechat ruby internal code");
ruby_plugin->printf_server (ruby_plugin,