Invoke the command when RUBY_BUGREPORT_PATH starts with |
This commit is contained in:
parent
0f64290704
commit
7e2775b057
@ -6324,6 +6324,7 @@ error.$(OBJEXT): $(top_srcdir)/internal/imemo.h
|
|||||||
error.$(OBJEXT): $(top_srcdir)/internal/io.h
|
error.$(OBJEXT): $(top_srcdir)/internal/io.h
|
||||||
error.$(OBJEXT): $(top_srcdir)/internal/load.h
|
error.$(OBJEXT): $(top_srcdir)/internal/load.h
|
||||||
error.$(OBJEXT): $(top_srcdir)/internal/object.h
|
error.$(OBJEXT): $(top_srcdir)/internal/object.h
|
||||||
|
error.$(OBJEXT): $(top_srcdir)/internal/process.h
|
||||||
error.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
error.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||||
error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
error.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
||||||
error.$(OBJEXT): $(top_srcdir)/internal/string.h
|
error.$(OBJEXT): $(top_srcdir)/internal/string.h
|
||||||
@ -6516,6 +6517,7 @@ error.$(OBJEXT): {$(VPATH)}st.h
|
|||||||
error.$(OBJEXT): {$(VPATH)}subst.h
|
error.$(OBJEXT): {$(VPATH)}subst.h
|
||||||
error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
|
error.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
|
||||||
error.$(OBJEXT): {$(VPATH)}thread_native.h
|
error.$(OBJEXT): {$(VPATH)}thread_native.h
|
||||||
|
error.$(OBJEXT): {$(VPATH)}util.h
|
||||||
error.$(OBJEXT): {$(VPATH)}vm_core.h
|
error.$(OBJEXT): {$(VPATH)}vm_core.h
|
||||||
error.$(OBJEXT): {$(VPATH)}vm_opts.h
|
error.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||||
error.$(OBJEXT): {$(VPATH)}warning.rbinc
|
error.$(OBJEXT): {$(VPATH)}warning.rbinc
|
||||||
|
67
error.c
67
error.c
@ -23,6 +23,10 @@
|
|||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_SYS_WAIT_H
|
||||||
|
# include <sys/wait.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined __APPLE__
|
#if defined __APPLE__
|
||||||
# include <AvailabilityMacros.h>
|
# include <AvailabilityMacros.h>
|
||||||
#endif
|
#endif
|
||||||
@ -34,12 +38,14 @@
|
|||||||
#include "internal/io.h"
|
#include "internal/io.h"
|
||||||
#include "internal/load.h"
|
#include "internal/load.h"
|
||||||
#include "internal/object.h"
|
#include "internal/object.h"
|
||||||
|
#include "internal/process.h"
|
||||||
#include "internal/string.h"
|
#include "internal/string.h"
|
||||||
#include "internal/symbol.h"
|
#include "internal/symbol.h"
|
||||||
#include "internal/thread.h"
|
#include "internal/thread.h"
|
||||||
#include "internal/variable.h"
|
#include "internal/variable.h"
|
||||||
#include "ruby/encoding.h"
|
#include "ruby/encoding.h"
|
||||||
#include "ruby/st.h"
|
#include "ruby/st.h"
|
||||||
|
#include "ruby/util.h"
|
||||||
#include "ruby_assert.h"
|
#include "ruby_assert.h"
|
||||||
#include "vm_core.h"
|
#include "vm_core.h"
|
||||||
|
|
||||||
@ -716,9 +722,12 @@ append_basename(char *p, const char *pe, struct path_string *path, VALUE str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
finish_report(FILE *out)
|
finish_report(FILE *out, rb_pid_t pid)
|
||||||
{
|
{
|
||||||
if (out != stdout && out != stderr) fclose(out);
|
if (out != stdout && out != stderr) fclose(out);
|
||||||
|
#ifdef HAVE_WORKING_FORK
|
||||||
|
if (pid > 0) waitpid(pid, NULL, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct report_expansion {
|
struct report_expansion {
|
||||||
@ -743,19 +752,24 @@ struct report_expansion {
|
|||||||
* %p PID of dumped process in decimal.
|
* %p PID of dumped process in decimal.
|
||||||
* %t Time of dump, expressed as seconds since the Epoch,
|
* %t Time of dump, expressed as seconds since the Epoch,
|
||||||
* 1970-01-01 00:00:00 +0000 (UTC).
|
* 1970-01-01 00:00:00 +0000 (UTC).
|
||||||
|
* %NNN Octal char code, upto 3 digits.
|
||||||
*/
|
*/
|
||||||
static char *
|
static char *
|
||||||
expand_report_argument(const char **input_template, struct report_expansion *values,
|
expand_report_argument(const char **input_template, struct report_expansion *values,
|
||||||
char *buf, size_t size)
|
char *buf, size_t size, bool word)
|
||||||
{
|
{
|
||||||
char *p = buf;
|
char *p = buf;
|
||||||
char *end = buf + size;
|
char *end = buf + size;
|
||||||
const char *template = *input_template;
|
const char *template = *input_template;
|
||||||
|
bool store = true;
|
||||||
|
|
||||||
if (p >= end-1 || !*template) return NULL;
|
if (p >= end-1 || !*template) return NULL;
|
||||||
do {
|
do {
|
||||||
char c = *template++;
|
char c = *template++;
|
||||||
|
if (word && ISSPACE(c)) break;
|
||||||
|
if (!store) continue;
|
||||||
if (c == '%') {
|
if (c == '%') {
|
||||||
|
size_t n;
|
||||||
switch (c = *template++) {
|
switch (c = *template++) {
|
||||||
case 'e':
|
case 'e':
|
||||||
p = append_basename(p, end, &values->exe, rb_argv0);
|
p = append_basename(p, end, &values->exe, rb_argv0);
|
||||||
@ -779,6 +793,13 @@ expand_report_argument(const char **input_template, struct report_expansion *val
|
|||||||
snprintf(p, end-p, "%" PRI_TIMET_PREFIX "d", values->time);
|
snprintf(p, end-p, "%" PRI_TIMET_PREFIX "d", values->time);
|
||||||
p += strlen(p);
|
p += strlen(p);
|
||||||
continue;
|
continue;
|
||||||
|
default:
|
||||||
|
if (c >= '0' && c <= '7') {
|
||||||
|
c = (unsigned char)ruby_scan_oct(template-1, 3, &n);
|
||||||
|
template += n - 1;
|
||||||
|
if (!c) store = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (p < end-1) *p++ = c;
|
if (p < end-1) *p++ = c;
|
||||||
@ -788,15 +809,31 @@ expand_report_argument(const char **input_template, struct report_expansion *val
|
|||||||
return ++p;
|
return ++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE *ruby_popen_writer(char *const *argv, rb_pid_t *pid);
|
||||||
|
|
||||||
static FILE *
|
static FILE *
|
||||||
open_report_path(const char *template, char *buf, size_t size)
|
open_report_path(const char *template, char *buf, size_t size, rb_pid_t *pid)
|
||||||
{
|
{
|
||||||
struct report_expansion values = {{0}};
|
struct report_expansion values = {{0}};
|
||||||
|
|
||||||
if (!template) return NULL;
|
if (!template) return NULL;
|
||||||
if (0) fprintf(stderr, "RUBY_BUGREPORT_PATH=%s\n", buf);
|
if (0) fprintf(stderr, "RUBY_BUGREPORT_PATH=%s\n", buf);
|
||||||
if (*template) {
|
if (*template == '|') {
|
||||||
expand_report_argument(&template, &values, buf, size);
|
char *argv[16], *bufend = buf + size, *p;
|
||||||
|
int argc;
|
||||||
|
template++;
|
||||||
|
for (argc = 0; argc < numberof(argv) - 1; ++argc) {
|
||||||
|
while (*template && ISSPACE(*template)) template++;
|
||||||
|
p = expand_report_argument(&template, &values, buf, bufend-buf, true);
|
||||||
|
if (!p) break;
|
||||||
|
argv[argc] = buf;
|
||||||
|
buf = p;
|
||||||
|
}
|
||||||
|
argv[argc] = NULL;
|
||||||
|
if (!p) return ruby_popen_writer(argv, pid);
|
||||||
|
}
|
||||||
|
else if (*template) {
|
||||||
|
expand_report_argument(&template, &values, buf, size, false);
|
||||||
return fopen(buf, "w");
|
return fopen(buf, "w");
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -805,10 +842,10 @@ open_report_path(const char *template, char *buf, size_t size)
|
|||||||
/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
|
/* SIGSEGV handler might have a very small stack. Thus we need to use it carefully. */
|
||||||
#define REPORT_BUG_BUFSIZ 256
|
#define REPORT_BUG_BUFSIZ 256
|
||||||
static FILE *
|
static FILE *
|
||||||
bug_report_file(const char *file, int line)
|
bug_report_file(const char *file, int line, rb_pid_t *pid)
|
||||||
{
|
{
|
||||||
char buf[REPORT_BUG_BUFSIZ];
|
char buf[REPORT_BUG_BUFSIZ];
|
||||||
FILE *out = open_report_path(getenv("RUBY_BUGREPORT_PATH"), buf, sizeof(buf));
|
FILE *out = open_report_path(getenv("RUBY_BUGREPORT_PATH"), buf, sizeof(buf), pid);
|
||||||
int len = err_position_0(buf, sizeof(buf), file, line);
|
int len = err_position_0(buf, sizeof(buf), file, line);
|
||||||
|
|
||||||
if (out) {
|
if (out) {
|
||||||
@ -926,7 +963,7 @@ bug_report_begin_valist(FILE *out, const char *fmt, va_list args)
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bug_report_end(FILE *out)
|
bug_report_end(FILE *out, rb_pid_t pid)
|
||||||
{
|
{
|
||||||
/* call additional bug reporters */
|
/* call additional bug reporters */
|
||||||
{
|
{
|
||||||
@ -937,24 +974,26 @@ bug_report_end(FILE *out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
postscript_dump(out);
|
postscript_dump(out);
|
||||||
finish_report(out);
|
finish_report(out, pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define report_bug(file, line, fmt, ctx) do { \
|
#define report_bug(file, line, fmt, ctx) do { \
|
||||||
FILE *out = bug_report_file(file, line); \
|
rb_pid_t pid = -1; \
|
||||||
|
FILE *out = bug_report_file(file, line, &pid); \
|
||||||
if (out) { \
|
if (out) { \
|
||||||
bug_report_begin(out, fmt); \
|
bug_report_begin(out, fmt); \
|
||||||
rb_vm_bugreport(ctx, out); \
|
rb_vm_bugreport(ctx, out); \
|
||||||
bug_report_end(out); \
|
bug_report_end(out, pid); \
|
||||||
} \
|
} \
|
||||||
} while (0) \
|
} while (0) \
|
||||||
|
|
||||||
#define report_bug_valist(file, line, fmt, ctx, args) do { \
|
#define report_bug_valist(file, line, fmt, ctx, args) do { \
|
||||||
FILE *out = bug_report_file(file, line); \
|
rb_pid_t pid = -1; \
|
||||||
|
FILE *out = bug_report_file(file, line, &pid); \
|
||||||
if (out) { \
|
if (out) { \
|
||||||
bug_report_begin_valist(out, fmt, args); \
|
bug_report_begin_valist(out, fmt, args); \
|
||||||
rb_vm_bugreport(ctx, out); \
|
rb_vm_bugreport(ctx, out); \
|
||||||
bug_report_end(out); \
|
bug_report_end(out, pid); \
|
||||||
} \
|
} \
|
||||||
} while (0) \
|
} while (0) \
|
||||||
|
|
||||||
@ -1081,7 +1120,7 @@ rb_assert_failure(const char *file, int line, const char *name, const char *expr
|
|||||||
fprintf(out, "%s\n%s\n\n", expr, rb_dynamic_description);
|
fprintf(out, "%s\n%s\n\n", expr, rb_dynamic_description);
|
||||||
preface_dump(out);
|
preface_dump(out);
|
||||||
rb_vm_bugreport(NULL, out);
|
rb_vm_bugreport(NULL, out);
|
||||||
bug_report_end(out);
|
bug_report_end(out, -1);
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
55
io.c
55
io.c
@ -170,6 +170,7 @@ off_t __syscall(quad_t number, ...);
|
|||||||
#define open rb_w32_uopen
|
#define open rb_w32_uopen
|
||||||
#undef rename
|
#undef rename
|
||||||
#define rename(f, t) rb_w32_urename((f), (t))
|
#define rename(f, t) rb_w32_urename((f), (t))
|
||||||
|
#include "win32/file.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VALUE rb_cIO;
|
VALUE rb_cIO;
|
||||||
@ -7955,6 +7956,60 @@ popen_finish(VALUE port, VALUE klass)
|
|||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)
|
||||||
|
struct popen_writer_arg {
|
||||||
|
char *const *argv;
|
||||||
|
struct popen_arg popen;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
exec_popen_writer(void *arg, char *errmsg, size_t buflen)
|
||||||
|
{
|
||||||
|
struct popen_writer_arg *pw = arg;
|
||||||
|
pw->popen.modef = FMODE_WRITABLE;
|
||||||
|
popen_redirect(&pw->popen);
|
||||||
|
execv(pw->argv[0], pw->argv);
|
||||||
|
strlcpy(errmsg, strerror(errno), buflen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *
|
||||||
|
ruby_popen_writer(char *const *argv, rb_pid_t *pid)
|
||||||
|
{
|
||||||
|
#if (defined(HAVE_WORKING_FORK) && !defined(__EMSCRIPTEN__)) || defined(_WIN32)
|
||||||
|
# ifdef HAVE_WORKING_FORK
|
||||||
|
struct popen_writer_arg pw;
|
||||||
|
int *const write_pair = pw.popen.pair;
|
||||||
|
# else
|
||||||
|
int write_pair[2];
|
||||||
|
# endif
|
||||||
|
|
||||||
|
int result = rb_cloexec_pipe(write_pair);
|
||||||
|
*pid = -1;
|
||||||
|
if (result == 0) {
|
||||||
|
# ifdef HAVE_WORKING_FORK
|
||||||
|
pw.argv = argv;
|
||||||
|
int status;
|
||||||
|
char errmsg[80] = {'\0'};
|
||||||
|
*pid = rb_fork_async_signal_safe(&status, exec_popen_writer, &pw, Qnil, errmsg, sizeof(errmsg));
|
||||||
|
# else
|
||||||
|
*pid = rb_w32_uspawn_process(P_NOWAIT, argv[0], argv, write_pair[0], -1, -1, 0);
|
||||||
|
const char *errmsg = (*pid < 0) ? strerror(errno) : NULL;
|
||||||
|
# endif
|
||||||
|
close(write_pair[0]);
|
||||||
|
if (*pid < 0) {
|
||||||
|
close(write_pair[1]);
|
||||||
|
fprintf(stderr, "ruby_popen_writer(%s): %s\n", argv[0], errmsg);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return fdopen(write_pair[1], "w");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
rb_scan_open_args(int argc, const VALUE *argv,
|
rb_scan_open_args(int argc, const VALUE *argv,
|
||||||
VALUE *fname_p, int *oflags_p, int *fmode_p,
|
VALUE *fname_p, int *oflags_p, int *fmode_p,
|
||||||
|
@ -880,6 +880,21 @@ class TestRubyOptions < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_bugreport_path_pipe
|
||||||
|
if File.executable?(echo = "/bin/echo")
|
||||||
|
elsif /mswin|ming/ =~ RUBY_PLATFORM
|
||||||
|
echo = "echo"
|
||||||
|
else
|
||||||
|
omit "/bin/echo not found"
|
||||||
|
end
|
||||||
|
assert_in_out_err([{"RUBY_BUGREPORT_PATH"=>"| #{echo} %e:%f:%p"}], SEGVTest::KILL_SELF,
|
||||||
|
encoding: "ASCII-8BIT",
|
||||||
|
**SEGVTest::ExecOptions) do |stdout, stderr, status|
|
||||||
|
assert_empty(stderr)
|
||||||
|
assert_equal(["#{File.basename(EnvUtil.rubybin)}:-:#{status.pid}"], stdout)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_DATA
|
def test_DATA
|
||||||
Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
|
Tempfile.create(["test_ruby_test_rubyoption", ".rb"]) {|t|
|
||||||
t.puts "puts DATA.read.inspect"
|
t.puts "puts DATA.read.inspect"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user