Skip to content

Commit 61afef2

Browse files
committed
rt: Add a RUST_TRACK_ORIGINS debug flag to help track down memory corruption
1 parent dbdeff6 commit 61afef2

File tree

8 files changed

+120
-10
lines changed

8 files changed

+120
-10
lines changed

mk/rt.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ RUNTIME_CS := rt/sync/timer.cpp \
2828
rt/rust_gc.cpp \
2929
rt/rust_abi.cpp \
3030
rt/rust_cc.cpp \
31+
rt/rust_debug.cpp \
3132
rt/memory_region.cpp \
3233
rt/test/rust_test_harness.cpp \
3334
rt/test/rust_test_runtime.cpp \

src/rt/rust_debug.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Routines useful when debugging the Rust runtime.
2+
3+
#include "rust_debug.h"
4+
#include "rust_internal.h"
5+
6+
#include <iostream>
7+
#include <string>
8+
#include <sstream>
9+
#include <stdint.h>
10+
11+
#if defined(__APPLE__) || defined(__linux__)
12+
#define HAVE_BACKTRACE
13+
#include <execinfo.h>
14+
#elif defined(_WIN32)
15+
#include <windows.h>
16+
#endif
17+
18+
namespace {
19+
20+
debug::flag track_origins("RUST_TRACK_ORIGINS");
21+
22+
} // end anonymous namespace
23+
24+
namespace debug {
25+
26+
std::string
27+
backtrace() {
28+
void *call_stack[256];
29+
int n_frames = ::backtrace(call_stack, 256);
30+
char **syms = backtrace_symbols(call_stack, n_frames);
31+
32+
std::stringstream ss;
33+
for (int i = 0; i < n_frames; i++)
34+
ss << syms[i] << std::endl;
35+
36+
free(syms);
37+
38+
return ss.str();
39+
}
40+
41+
void
42+
maybe_track_origin(rust_task *task, void *ptr) {
43+
if (!*track_origins)
44+
return;
45+
task->debug.origins[ptr] = backtrace();
46+
}
47+
48+
void
49+
maybe_untrack_origin(rust_task *task, void *ptr) {
50+
if (!*track_origins)
51+
return;
52+
task->debug.origins.erase(ptr);
53+
}
54+
55+
// This function is intended to be called by the debugger.
56+
void
57+
dump_origin(rust_task *task, void *ptr) {
58+
if (!*track_origins) {
59+
std::cerr << "Try again with RUST_TRACK_ORIGINS=1." << std::endl;
60+
} else if (task->debug.origins.find(ptr) == task->debug.origins.end()) {
61+
std::cerr << "Pointer " << std::hex << (uintptr_t)ptr <<
62+
" does not have a tracked origin.";
63+
} else {
64+
std::cerr << "Origin of pointer " << std::hex << ":" << std::endl <<
65+
task->debug.origins[ptr];
66+
}
67+
}
68+
69+
} // end namespace debug
70+

src/rt/rust_debug.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@
33
#ifndef RUST_DEBUG_H
44
#define RUST_DEBUG_H
55

6+
#include <map>
7+
#include <string>
68
#include <cstdlib>
79

10+
struct rust_task;
11+
812
namespace debug {
913

1014
class flag {
@@ -27,6 +31,19 @@ class flag {
2731
}
2832
};
2933

34+
class task_debug_info {
35+
public:
36+
std::map<void *,std::string> origins;
37+
};
38+
39+
std::string backtrace();
40+
41+
void maybe_track_origin(rust_task *task, void *ptr);
42+
void maybe_untrack_origin(rust_task *task, void *ptr);
43+
44+
// This function is intended to be called by the debugger.
45+
void dump_origin(rust_task *task, void *ptr);
46+
3047
} // end namespace debug
3148

3249
#endif

src/rt/rust_internal.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ struct frame_glue_fns;
6767
typedef intptr_t rust_task_id;
6868
typedef intptr_t rust_port_id;
6969

70-
// Corresponds to the rust chan (currently _chan) type.
71-
struct chan_handle {
72-
rust_task_id task;
73-
rust_port_id port;
74-
};
75-
7670
#ifndef __i386__
7771
#error "Target CPU not supported."
7872
#endif

src/rt/rust_kernel.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
#ifndef RUST_KERNEL_H
33
#define RUST_KERNEL_H
44

5+
#include "memory_region.h"
6+
#include "rust_log.h"
7+
8+
struct rust_scheduler;
9+
510
/**
611
* A global object shared by all thread domains. Most of the data structures
712
* in this class are synchronized since they are accessed from multiple

src/rt/rust_shape.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@
1616

1717
#define ARENA_SIZE 256
1818

19-
//#define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
20-
//#define DPRINTCX(cx) shape::print::print_cx(cx)
19+
#define DPRINT(fmt,...) fprintf(stderr, fmt, ##__VA_ARGS__)
20+
#define DPRINTCX(cx) shape::print::print_cx(cx)
2121

22-
#define DPRINT(fmt,...)
23-
#define DPRINTCX(cx)
22+
//#define DPRINT(fmt,...)
23+
//#define DPRINTCX(cx)
2424

2525

2626
namespace shape {
@@ -526,6 +526,13 @@ class print : public ctxt<print> {
526526
const rust_shape_tables *in_tables = NULL)
527527
: ctxt<print>(other, in_sp, in_params, in_tables) {}
528528

529+
print(rust_task *in_task,
530+
bool in_align,
531+
const uint8_t *in_sp,
532+
const type_param *in_params,
533+
const rust_shape_tables *in_tables)
534+
: ctxt<print>(in_task, in_align, in_sp, in_params, in_tables) {}
535+
529536
void walk_tag(tag_info &tinfo);
530537
void walk_struct(const uint8_t *end_sp);
531538
void walk_res(const rust_fn *dtor, unsigned n_params,

src/rt/rust_task.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,17 @@
1010
#include "util/array_list.h"
1111

1212
#include "context.h"
13+
#include "rust_debug.h"
14+
#include "rust_internal.h"
15+
#include "rust_kernel.h"
1316
#include "rust_obstack.h"
1417

18+
// Corresponds to the rust chan (currently _chan) type.
19+
struct chan_handle {
20+
rust_task_id task;
21+
rust_port_id port;
22+
};
23+
1524
struct rust_box;
1625

1726
struct stk_seg {
@@ -117,6 +126,8 @@ rust_task : public kernel_owned<rust_task>, rust_cond
117126

118127
std::map<void *,const type_desc *> local_allocs;
119128

129+
debug::task_debug_info debug;
130+
120131
// Only a pointer to 'name' is kept, so it must live as long as this task.
121132
rust_task(rust_scheduler *sched,
122133
rust_task_list *state,

src/rt/rust_upcall.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,13 @@ upcall_malloc(rust_task *task, size_t nbytes, type_desc *td) {
6767
// TODO: Maybe use dladdr here to find a more useful name for the
6868
// type_desc.
6969

70+
// TODO: Implement RUST_TRACK_ORIGINS
71+
7072
void *p = task->malloc(nbytes, "tdesc", td);
7173
memset(p, '\0', nbytes);
7274

7375
task->local_allocs[p] = td;
76+
debug::maybe_track_origin(task, p);
7477

7578
LOG(task, mem,
7679
"upcall malloc(%" PRIdPTR ", 0x%" PRIxPTR ") = 0x%" PRIxPTR,
@@ -91,6 +94,8 @@ upcall_free(rust_task *task, void* ptr, uintptr_t is_gc) {
9194
(uintptr_t)ptr, is_gc);
9295

9396
task->local_allocs.erase(ptr);
97+
debug::maybe_untrack_origin(task, ptr);
98+
9499
task->free(ptr, (bool) is_gc);
95100
}
96101

0 commit comments

Comments
 (0)