Skip to content

Commit

Permalink
Add new integration tests: backtrace, throw and longjmp
Browse files Browse the repository at this point in the history
  • Loading branch information
koute committed Oct 7, 2019
1 parent 0ad8b05 commit 9bed880
Show file tree
Hide file tree
Showing 4 changed files with 315 additions and 0 deletions.
130 changes: 130 additions & 0 deletions integration-tests/src/tests.rs
Expand Up @@ -201,6 +201,18 @@ impl Analysis {
}
}

fn assert_allocation_backtrace( alloc: &Allocation, expected: &[&str] ) {
let mut actual: Vec< _ > = alloc.backtrace.iter().map( |frame| frame.raw_function.clone().unwrap_or( String::new() ) ).collect();
actual.reverse();

let matches = actual.len() >= expected.len() && actual.iter().zip( expected.iter() ).all( |(lhs, rhs)| lhs == rhs );
if matches {
return;
}

panic!( "Unexpected backtrace!\n\nActual:\n{}\n\nExpected to start with:\n{}\n", actual.join( "\n" ), expected.join( "\n" ) );
}

fn workdir() -> PathBuf {
let path = repository_root().join( "target" );
let workdir = if let Some( target ) = target() {
Expand Down Expand Up @@ -789,3 +801,121 @@ fn test_dlopen() {
assert_eq!( a0.size, 123123 );
assert_eq!( iter.next(), None );
}

#[test]
fn test_throw() {
let cwd = workdir();
compile( "throw.cpp" );

run_on_target(
&cwd,
"./throw",
EMPTY_ARGS,
&[
("LD_PRELOAD", preload_path().into_os_string()),
("MEMORY_PROFILER_LOG", "debug".into()),
("MEMORY_PROFILER_OUTPUT", "throw.dat".into())
]
).assert_success();

let analysis = analyze( "throw", cwd.join( "throw.dat" ) );
let a0 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123456 ).unwrap();
let a1 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123457 ).unwrap();
let a2 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123458 ).unwrap();
let a3 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123459 ).unwrap();

assert_allocation_backtrace( a0, &[
"foobar_0",
"foobar_1",
"foobar_2",
"foobar_3",
"foobar_4",
"foobar_5",
"main"
]);

assert_allocation_backtrace( a1, &[
"foobar_3",
"foobar_4",
"foobar_5",
"main"
]);

assert_allocation_backtrace( a2, &[
"foobar_5",
"main"
]);

assert_allocation_backtrace( a3, &[
"main"
]);
}

#[test]
fn test_longjmp() {
let cwd = workdir();
compile( "longjmp.c" );

run_on_target(
&cwd,
"./longjmp",
EMPTY_ARGS,
&[
("LD_PRELOAD", preload_path().into_os_string()),
("MEMORY_PROFILER_LOG", "debug".into()),
("MEMORY_PROFILER_OUTPUT", "longjmp.dat".into())
]
).assert_success();

let analysis = analyze( "longjmp", cwd.join( "longjmp.dat" ) );
let a0 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123456 ).unwrap();
let a1 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123457 ).unwrap();
let a2 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123458 ).unwrap();
let a3 = analysis.response.allocations.iter().find( |alloc| alloc.size == 123459 ).unwrap();

assert_allocation_backtrace( a0, &[
"foobar_0",
"foobar_1",
"foobar_2",
"foobar_3",
"foobar_4",
"foobar_5",
"main"
]);

assert_allocation_backtrace( a1, &[
"foobar_3",
"foobar_4",
"foobar_5",
"main"
]);

assert_allocation_backtrace( a2, &[
"foobar_5",
"main"
]);

assert_allocation_backtrace( a3, &[
"main"
]);
}

#[test]
fn test_backtrace() {
let cwd = workdir();
compile_with_flags( "backtrace.c", &[ "-rdynamic" ] );

run_on_target(
&cwd,
"./backtrace",
EMPTY_ARGS,
&[
("LD_PRELOAD", preload_path().into_os_string()),
("MEMORY_PROFILER_LOG", "debug".into()),
("MEMORY_PROFILER_OUTPUT", "backtrace.dat".into())
]
).assert_success();

let analysis = analyze( "backtrace", cwd.join( "backtrace.dat" ) );
assert!( analysis.response.allocations.iter().any( |alloc| alloc.size == 123456 ) );
}
31 changes: 31 additions & 0 deletions integration-tests/test-programs/backtrace.c
@@ -0,0 +1,31 @@
#include <stdlib.h>
#include <execinfo.h>

void __attribute__ ((noinline)) foo() {
malloc( 123456 );

void * buffer[ 32 ];
const int count = backtrace( buffer, 32 );
if( count == 0 ) {
exit( 1 );
}
char ** symbols = backtrace_symbols( buffer, count );
free( symbols );
}

void __attribute__ ((noinline)) bar() {
foo();

void * buffer[ 32 ];
const int count = backtrace( buffer, 32 );
if( count == 0 ) {
exit( 1 );
}
char ** symbols = backtrace_symbols( buffer, count );
free( symbols );
}

int main() {
bar();
return 0;
}
77 changes: 77 additions & 0 deletions integration-tests/test-programs/longjmp.c
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <setjmp.h>

int catch_1 = 0;
int catch_2 = 0;

int f1 = 0;
int f2 = 0;
int f3a = 0;
int f3b = 0;
int f4 = 0;
int f5a = 0;
int f5b = 0;

jmp_buf buf_a;
jmp_buf buf_b;

void __attribute__ ((noinline)) foobar_0() {
malloc( 123456 );
}

void __attribute__ ((noinline)) foobar_1() {
foobar_0();

printf( ">> before throw\n" );
longjmp( buf_a, 1 );
f1 = 1;
}

void __attribute__ ((noinline)) foobar_2() {
foobar_1();
f2 = 1;
}

void __attribute__ ((noinline)) foobar_3() {
printf( ">> before try\n" );
if( setjmp( buf_a ) == 0 ) {
foobar_2();
f3a = 1;
} else {
catch_1 = 1;
printf( ">> inside catch\n" );
malloc( 123457 );
longjmp( buf_b, 1 );
}
f3b = 1;
}

void __attribute__ ((noinline)) foobar_4() {
foobar_3();
f4 = 1;
}

void __attribute__ ((noinline)) foobar_5() {
if( setjmp( buf_b ) == 0 ) {
foobar_4();
f5a = 1;
} else {
catch_2 = 1;
malloc( 123458 );
}
f5b = 1;
}

int main() {
printf( ">> start\n" );
foobar_5();

if( catch_1 && catch_2 && !f1 && !f2 && !f3a && !f3b && !f4 && !f5a && f5b ) {
malloc( 123459 );
return 0;
}

abort();
}
77 changes: 77 additions & 0 deletions integration-tests/test-programs/throw.cpp
@@ -0,0 +1,77 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

bool catch_1 = false;
bool catch_2 = false;

bool f1 = false;
bool f2 = false;
bool f3a = false;
bool f3b = false;
bool f4 = false;
bool f5a = false;
bool f5b = false;

extern "C" {

void __attribute__ ((noinline)) foobar_0() {
malloc( 123456 );
}

void __attribute__ ((noinline)) foobar_1() {
foobar_0();

printf( ">> before throw\n" );
throw "dummy";
f1 = true;
}

void __attribute__ ((noinline)) foobar_2() {
foobar_1();
f2 = true;
}

void __attribute__ ((noinline)) foobar_3() {
printf( ">> before try\n" );
try {
foobar_2();
f3a = true;
} catch (...) {
catch_1 = true;
printf( ">> inside catch\n" );
malloc( 123457 );
throw;
}
f3b = true;
}

void __attribute__ ((noinline)) foobar_4() {
foobar_3();
f4 = true;
}

void __attribute__ ((noinline)) foobar_5() {
try {
foobar_4();
f5a = true;
} catch (...) {
catch_2 = true;
malloc( 123458 );
}
f5b = true;
}

}

int main() {
printf( ">> start\n" );
foobar_5();

if( catch_1 && catch_2 && !f1 && !f2 && !f3a && !f3b && !f4 && !f5a && f5b ) {
malloc( 123459 );
return 0;
}

abort();
}

0 comments on commit 9bed880

Please sign in to comment.