rt: Add a RUST_TRACK_ORIGINS debug flag to help track down memory corruption

This commit is contained in:
Patrick Walton 2011-09-23 11:42:20 -07:00
parent dbdeff659f
commit 61afef29a1
8 changed files with 120 additions and 10 deletions

View File

@ -28,6 +28,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
rt/rust_gc.cpp \
rt/rust_abi.cpp \
rt/rust_cc.cpp \
rt/rust_debug.cpp \
rt/memory_region.cpp \
rt/test/rust_test_harness.cpp \
rt/test/rust_test_runtime.cpp \

70
src/rt/rust_debug.cpp Normal file
View File

@ -0,0 +1,70 @@
// Routines useful when debugging the Rust runtime.
#include "rust_debug.h"
#include "rust_internal.h"
#include <iostream>
#include <string>
#include <sstream>
#include <stdint.h>
#if defined(__APPLE__) || defined(__linux__)
#define HAVE_BACKTRACE
#include <execinfo.h>
#elif defined(_WIN32)
#include <windows.h>
#endif
namespace {
debug::flag track_origins("RUST_TRACK_ORIGINS");
} // end anonymous namespace
namespace debug {
std::string
backtrace() {
void *call_stack[256];
int n_frames = ::backtrace(call_stack, 256);
char **syms = backtrace_symbols(call_stack, n_frames);
std::stringstream ss;
for (int i = 0; i < n_frames; i++)
ss << syms[i] << std::endl;
free(syms);
return ss.str();
}
void
maybe_track_origin(rust_task *task, void *ptr) {
if (!*track_origins)
return;
task->debug.origins[ptr] = backtrace();
}
void
maybe_untrack_origin(rust_task *task, void *ptr) {
if (!*track_origins)
return;
task->debug.origins.erase(ptr);
}
// This function is intended to be called by the debugger.
void
dump_origin(rust_task *task, void *ptr) {
if (!*track_origins) {
std::cerr << "Try again with RUST_TRACK_ORIGINS=1." << std::endl;
} else if (task->debug.origins.find(ptr) == task->debug.origins.end()) {
std::cerr << "Pointer " << std::hex << (uintptr_t)ptr <<
" does not have a tracked origin.";
} else {
std::cerr << "Origin of pointer " << std::hex << ":" << std::endl <<
task->debug.origins[ptr];
}
}
} // end namespace debug

View File

@ -3,8 +3,12 @@
#ifndef RUST_DEBUG_H
#define RUST_DEBUG_H
#include <map>
#include <string>
#include <cstdlib>
struct rust_task;
namespace debug {
class flag {
@ -27,6 +31,19 @@ public:
}
};
class task_debug_info {
public:
std::map<void *,std::string> origins;
};
std::string backtrace();
void maybe_track_origin(rust_task *task, void *ptr);
void maybe_untrack_origin(rust_task *task, void *ptr);
// This function is intended to be called by the debugger.
void dump_origin(rust_task *task, void *ptr);
} // end namespace debug
#endif

View File

@ -67,12 +67,6 @@ struct frame_glue_fns;
typedef intptr_t rust_task_id;
typedef intptr_t rust_port_id;
// Corresponds to the rust chan (currently _chan) type.
struct chan_handle {
rust_task_id task;
rust_port_id port;
};
#ifndef __i386__
#error "Target CPU not supported."
#endif

View File

@ -2,6 +2,11 @@
#ifndef RUST_KERNEL_H
#define RUST_KERNEL_H
#include "memory_region.h"
#include "rust_log.h"
struct rust_scheduler;
/**
* A global object shared by all thread domains. Most of the data structures
* in this class are synchronized since they are accessed from multiple

View File

@ -16,11 +16,11 @@
#define ARENA_SIZE 256
//#define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
//#define DPRINTCX(cx) shape::print::print_cx(cx)
#define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
#define DPRINTCX(cx) shape::print::print_cx(cx)
#define DPRINT(fmt,...)
#define DPRINTCX(cx)
//#define DPRINT(fmt,...)
//#define DPRINTCX(cx)
namespace shape {
@ -526,6 +526,13 @@ public:
const rust_shape_tables *in_tables = NULL)
: ctxt<print>(other, in_sp, in_params, in_tables) {}
print(rust_task *in_task,
bool in_align,
const uint8_t *in_sp,
const type_param *in_params,
const rust_shape_tables *in_tables)
: ctxt<print>(in_task, in_align, in_sp, in_params, in_tables) {}
void walk_tag(tag_info &tinfo);
void walk_struct(const uint8_t *end_sp);
void walk_res(const rust_fn *dtor, unsigned n_params,

View File

@ -10,8 +10,17 @@
#include "util/array_list.h"
#include "context.h"
#include "rust_debug.h"
#include "rust_internal.h"
#include "rust_kernel.h"
#include "rust_obstack.h"
// Corresponds to the rust chan (currently _chan) type.
struct chan_handle {
rust_task_id task;
rust_port_id port;
};
struct rust_box;
struct stk_seg {
@ -117,6 +126,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
std::map<void *,const type_desc *> local_allocs;
debug::task_debug_info debug;
// Only a pointer to 'name' is kept, so it must live as long as this task.
rust_task(rust_scheduler *sched,
rust_task_list *state,

View File

@ -67,10 +67,13 @@ upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) {
// TODO: Maybe use dladdr here to find a more useful name for the
// type_desc.
// TODO: Implement RUST_TRACK_ORIGINS
void *p = task->malloc(nbytes, "tdesc", td);
memset(p, '\0', nbytes);
task->local_allocs[p] = td;
debug::maybe_track_origin(task, p);
LOG(task, mem,
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR,
@ -91,6 +94,8 @@ upcall_free(rust_task *task, void* ptr, uintptr_t is_gc) {
(uintptr_t)ptr, is_gc);
task->local_allocs.erase(ptr);
debug::maybe_untrack_origin(task, ptr);
task->free(ptr, (bool) is_gc);
}