Skip to content

Commit 1a03dd3

Browse files
committed
add test to ensure the size of prof_stacktrace_s is correct,
do not write to buffer if the size exceeds the buffer
1 parent 93f28d0 commit 1a03dd3

3 files changed

Lines changed: 38 additions & 6 deletions

File tree

src/_vmprof.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ sample_stack_now(PyObject *module, PyObject * args)
378378
vmprof_ignore_signals(0);
379379
return NULL;
380380
}
381-
entry_count = vmp_walk_and_record_stack(tstate->frame, m, MAX_STACK_DEPTH-1, skip, 0);
381+
entry_count = vmp_walk_and_record_stack(tstate->frame, m, SINGLE_BUF_SIZE/sizeof(void*)-1, skip, 0);
382382

383383
for (i = 0; i < entry_count; i++) {
384384
routine_ip = m[i];

src/vmp_stack.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ static int (*unw_getcontext)(unw_context_t *) = NULL;
4444
#include <dlfcn.h>
4545
#endif
4646

47+
int _per_loop(void) {
48+
// how many void* are written to the stack trace per loop iterations?
49+
#ifdef RPYTHON_VMPROF
50+
return 2;
51+
#else
52+
if (vmp_profiles_python_lines()) {
53+
return 2;
54+
}
55+
return 1;
56+
#endif
57+
}
58+
59+
4760
#ifdef PY_TEST
4861
// for testing only!
4962
PY_EVAL_RETURN_T * vmprof_eval(PY_STACK_FRAME_T *f, int throwflag) { return NULL; }
@@ -130,19 +143,27 @@ static PY_STACK_FRAME_T * _write_python_stack_entry(PY_STACK_FRAME_T * frame, vo
130143
int vmp_walk_and_record_python_stack_only(PY_STACK_FRAME_T *frame, void ** result,
131144
int max_depth, int depth, intptr_t pc)
132145
{
133-
while (depth < max_depth && frame) {
146+
while ((depth + _per_loop()) <= max_depth && frame) {
134147
frame = _write_python_stack_entry(frame, result, &depth, max_depth);
135148
}
136149
return depth;
137150
}
138151

139152
#ifdef VMP_SUPPORTS_NATIVE_PROFILING
140-
int _write_native_stack(void* addr, void ** result, int depth) {
153+
int _write_native_stack(void* addr, void ** result, int depth, int max_depth) {
141154
#ifdef RPYTHON_VMPROF
155+
if (depth + 2 >= max_depth) {
156+
// bail, do not write to unknown memory
157+
return depth;
158+
}
142159
result[depth++] = (void*)VMPROF_NATIVE_TAG;
143160
#else
144161
if (vmp_profiles_python_lines()) {
145-
// even if we do not log a python stack frame,
162+
if (depth + 2 >= max_depth) {
163+
// bail, do not write to unknown memory
164+
return depth;
165+
}
166+
// even if we do not log a python line number,
146167
// we must keep the profile readable
147168
result[depth++] = 0;
148169
}
@@ -227,7 +248,7 @@ int vmp_walk_and_record_stack(PY_STACK_FRAME_T *frame, void ** result,
227248

228249
int depth = 0;
229250
PY_STACK_FRAME_T * top_most_frame = frame;
230-
while (depth < max_depth) {
251+
while ((depth + _per_loop()) <= max_depth) {
231252
unw_get_proc_info(&cursor, &pip);
232253

233254
func_addr = pip.start_ip;
@@ -269,7 +290,7 @@ int vmp_walk_and_record_stack(PY_STACK_FRAME_T *frame, void ** result,
269290
// this is possible because compiler align to 8 bytes.
270291
//
271292
if (func_addr != 0x0) {
272-
depth = _write_native_stack((void*)(func_addr | 0x1), result, depth);
293+
depth = _write_native_stack((void*)(func_addr | 0x1), result, depth, max_depth);
273294
}
274295
}
275296

vmprof/test/test_c_source.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,17 @@ def setup_class(cls):
1818
void vmp_set_ignore_symbols(ptr_t * symbols, int count);
1919
int vmp_read_vmaps(const char * fname);
2020
void vmp_native_disable();
21+
int sizeof_prof_stacktrace_s(void);
2122
""")
2223
with open("src/vmp_stack.c", "rb") as fd:
2324
source = fd.read().decode()
2425
libs = [] #['unwind', 'unwind-x86_64']
2526
if sys.platform.startswith('linux'):
2627
libs = ['unwind', 'unwind-x86_64']
28+
source += """
29+
#include "vmprof_common.h"
30+
int sizeof_prof_stacktrace_s(void) { return sizeof(prof_stacktrace_s); }
31+
"""
2732
# trick: compile with _CFFI_USE_EMBEDDING=1 which will not define Py_LIMITED_API
2833
stack_ffi.set_source("vmprof.test._test_stack", source, include_dirs=['src'],
2934
define_macros=[('_CFFI_USE_EMBEDDING',1), ('PY_TEST',1),
@@ -126,3 +131,9 @@ def test_overflow_vmaps(self, tmpdir):
126131
assert self.lib.vmp_ignore_ip(l) == 1
127132
assert self.lib.vmp_ignore_ip(10001) == 0
128133

134+
def test_sizes(self):
135+
if sys.maxsize == 2**63-1:
136+
word_size = 8
137+
else:
138+
word_size = 4
139+
assert self.lib.sizeof_prof_stacktrace_s() == 3*word_size

0 commit comments

Comments
 (0)