forked from iovisor/bcc
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
libbpf-tools: Add new feature lsan on libbpf-tools
Add leaksanitizer(lsan) feature on libbpf-tools lsan feature originally comes from llvm-project https://github.com/llvm/llvm-project cvector.h comes from c-vector project commit d3f3156373b0587336ac7ee1568755d6cf93dd39 https://github.com/eteran/c-vector uthash.h comes from uthash project commit bf15263081be6229be31addd48566df93921cb46 https://github.com/troydhanson/uthash This tool detect and report dangling pointers periodically Usage: lsan [OPTION...] Detect memory leak resulting from dangling pointers. Either -c or -p is a mandatory option EXAMPLES: lsan -p 1234 # Detect leaks on process id 1234 lsan -c a.out # Detect leaks on a.out lsan -c 'a.out arg' # Detect leaks on a.out with argument lsan -c "a.out arg" # Detect leaks on a.out with argument -c, --command=COMMAND Execute and trace the specified command -i, --interval=INTERVAL Set interval in second to detect leak -p, --pid=PID Set pid -s, --suppressions=SUPPRESSIONS Suppressions file name -T, --top=TOP Report only specified amount of backtraces -v, --verbose Verbose debug output -w, --stop-the-world Stop the world during tracing -?, --help Give this help list --usage Give a short usage message -V, --version Print program version Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options. Report example: $ sudo ./lsan -c a.out -s suppr.txt Info: Execute child process: a.out Info: execute command: a.out(pid 8335) [2022-07-19 16:07:26] Print leaks: Could not open [uprobes] 4 bytes direct leak found in 1 allocations from stack id(19863) iovisor#1 0x00564465ed71bf foo iovisor#2 0x00564465ed721b main iovisor#3 0x007fc0a33f7d90 __libc_init_first [2022-07-19 16:07:36] Print leaks: 8 bytes direct leak found in 2 allocations from stack id(19863) iovisor#1 0x00564465ed71bf foo iovisor#2 0x00564465ed721b main iovisor#3 0x007fc0a33f7d90 __libc_init_first [2022-07-19 16:07:46] Print leaks: 12 bytes direct leak found in 3 allocations from stack id(19863) iovisor#1 0x00564465ed71bf foo iovisor#2 0x00564465ed721b main iovisor#3 0x007fc0a33f7d90 __libc_init_first Source code of test program: \#include <stdio.h> \#include <stdlib.h> \#include <unistd.h> int* foo() { int *tmp = malloc(sizeof(int)); *tmp = 99; return tmp; } int* bar() { int *tmp = malloc(sizeof(int)); *tmp = 22; return tmp; } int main() { int *a = NULL; while (1) { a = foo(); printf("%d\n", *a); a = bar(); free(a); sleep(10); } }
- Loading branch information
Showing
7 changed files
with
2,835 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,7 @@ | |
/klockstat | ||
/ksnoop | ||
/llcstat | ||
/lsan | ||
/memleak | ||
/mdflush | ||
/mountsnoop | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,7 @@ APPS = \ | |
klockstat \ | ||
ksnoop \ | ||
llcstat \ | ||
lsan \ | ||
mdflush \ | ||
mountsnoop \ | ||
numamove \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
/* | ||
* Copyright (c) 2015 Evan Teran | ||
* | ||
* License: The MIT License (MIT) | ||
*/ | ||
|
||
#ifndef CVECTOR_H_ | ||
#define CVECTOR_H_ | ||
|
||
#include <assert.h> /* for assert */ | ||
#include <stdlib.h> /* for malloc/realloc/free */ | ||
#include <string.h> /* for memcpy/memmove */ | ||
|
||
/* cvector heap implemented using C library malloc() */ | ||
|
||
/* in case C library malloc() needs extra protection, | ||
* allow these defines to be overridden. | ||
*/ | ||
#ifndef cvector_clib_free | ||
#define cvector_clib_free free | ||
#endif | ||
#ifndef cvector_clib_malloc | ||
#define cvector_clib_malloc malloc | ||
#endif | ||
#ifndef cvector_clib_calloc | ||
#define cvector_clib_calloc calloc | ||
#endif | ||
#ifndef cvector_clib_realloc | ||
#define cvector_clib_realloc realloc | ||
#endif | ||
|
||
typedef void (*cvector_elem_destructor_t)(void *elem); | ||
|
||
/** | ||
* @brief cvector_vector_type - The vector type used in this library | ||
*/ | ||
#define cvector_vector_type(type) type * | ||
|
||
/** | ||
* @brief cvector_capacity - gets the current capacity of the vector | ||
* @param vec - the vector | ||
* @return the capacity as a size_t | ||
*/ | ||
#define cvector_capacity(vec) \ | ||
((vec) ? ((size_t *)(vec))[-1] : (size_t)0) | ||
|
||
/** | ||
* @brief cvector_size - gets the current size of the vector | ||
* @param vec - the vector | ||
* @return the size as a size_t | ||
*/ | ||
#define cvector_size(vec) \ | ||
((vec) ? ((size_t *)(vec))[-2] : (size_t)0) | ||
|
||
/** | ||
* @brief cvector_set_elem_destructor - set the element destructor function | ||
* used to clean up removed elements | ||
* @param vec - the vector | ||
* @return elem_destructor_fn - function pointer of type cvector_elem_destructor_t | ||
* @return the function pointer elem_destructor_fn or NULL on error | ||
*/ | ||
#define cvector_set_elem_destructor(vec, elem_destructor_fn) \ | ||
do { \ | ||
if (!(vec)) { \ | ||
cvector_grow((vec), 0); \ | ||
} \ | ||
((cvector_elem_destructor_t *)&(((size_t *)(vec))[-2]))[-1] = (elem_destructor_fn); \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_elem_destructor - get the element destructor function used | ||
* to clean up elements | ||
* @param vec - the vector | ||
* @return the function pointer as cvector_elem_destructor_t | ||
*/ | ||
#define cvector_elem_destructor(vec) \ | ||
((vec) ? (((cvector_elem_destructor_t *)&(((size_t *)(vec))[-2]))[-1]) : NULL) | ||
|
||
/** | ||
* @brief cvector_empty - returns non-zero if the vector is empty | ||
* @param vec - the vector | ||
* @return non-zero if empty, zero if non-empty | ||
*/ | ||
#define cvector_empty(vec) \ | ||
(cvector_size(vec) == 0) | ||
|
||
/** | ||
* @brief cvector_reserve - Requests that the vector capacity be at least enough | ||
* to contain n elements. If n is greater than the current vector capacity, the | ||
* function causes the container to reallocate its storage increasing its | ||
* capacity to n (or greater). | ||
* @param vec - the vector | ||
* @param n - Minimum capacity for the vector. | ||
* @return void | ||
*/ | ||
#define cvector_reserve(vec, capacity) \ | ||
do { \ | ||
size_t cv_cap__ = cvector_capacity(vec); \ | ||
if (cv_cap__ < (capacity)) { \ | ||
cvector_grow((vec), (capacity)); \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_erase - removes the element at index i from the vector | ||
* @param vec - the vector | ||
* @param i - index of element to remove | ||
* @return void | ||
*/ | ||
#define cvector_erase(vec, i) \ | ||
do { \ | ||
if ((vec)) { \ | ||
const size_t cv_sz__ = cvector_size(vec); \ | ||
if ((i) < cv_sz__) { \ | ||
cvector_set_size((vec), cv_sz__ - 1); \ | ||
memmove((vec) + (i), (vec) + (i) + 1, sizeof(*(vec)) * (cv_sz__ - 1 - (i))); \ | ||
} \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_free - frees all memory associated with the vector | ||
* @param vec - the vector | ||
* @return void | ||
*/ | ||
#define cvector_free(vec) \ | ||
do { \ | ||
if ((vec)) { \ | ||
size_t *p1__ = (size_t *)&(((cvector_elem_destructor_t *)&(((size_t *)(vec))[-2]))[-1]); \ | ||
cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor((vec)); \ | ||
if (elem_destructor__) { \ | ||
size_t i__; \ | ||
for (i__ = 0; i__ < cvector_size(vec); ++i__) \ | ||
elem_destructor__(&vec[i__]); \ | ||
} \ | ||
cvector_clib_free(p1__); \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_begin - returns an iterator to first element of the vector | ||
* @param vec - the vector | ||
* @return a pointer to the first element (or NULL) | ||
*/ | ||
#define cvector_begin(vec) \ | ||
(vec) | ||
|
||
/** | ||
* @brief cvector_end - returns an iterator to one past the last element of the vector | ||
* @param vec - the vector | ||
* @return a pointer to one past the last element (or NULL) | ||
*/ | ||
#define cvector_end(vec) \ | ||
((vec) ? &((vec)[cvector_size(vec)]) : NULL) | ||
|
||
/* user request to use logarithmic growth algorithm */ | ||
#ifdef CVECTOR_LOGARITHMIC_GROWTH | ||
|
||
/** | ||
* @brief cvector_compute_next_grow - returns an the computed size in next vector grow | ||
* size is increased by multiplication of 2 | ||
* @param size - current size | ||
* @return size after next vector grow | ||
*/ | ||
#define cvector_compute_next_grow(size) \ | ||
((size) ? ((size) << 1) : 1) | ||
|
||
#else | ||
|
||
/** | ||
* @brief cvector_compute_next_grow - returns an the computed size in next vector grow | ||
* size is increased by 1 | ||
* @param size - current size | ||
* @return size after next vector grow | ||
*/ | ||
#define cvector_compute_next_grow(size) \ | ||
((size) + 1) | ||
|
||
#endif /* CVECTOR_LOGARITHMIC_GROWTH */ | ||
|
||
/** | ||
* @brief cvector_push_back - adds an element to the end of the vector | ||
* @param vec - the vector | ||
* @param value - the value to add | ||
* @return void | ||
*/ | ||
#define cvector_push_back(vec, value) \ | ||
do { \ | ||
size_t cv_cap__ = cvector_capacity(vec); \ | ||
if (cv_cap__ <= cvector_size(vec)) { \ | ||
cvector_grow((vec), cvector_compute_next_grow(cv_cap__)); \ | ||
} \ | ||
(vec)[cvector_size(vec)] = (value); \ | ||
cvector_set_size((vec), cvector_size(vec) + 1); \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_insert - insert element at position pos to the vector | ||
* @param vec - the vector | ||
* @param pos - position in the vector where the new elements are inserted. | ||
* @param val - value to be copied (or moved) to the inserted elements. | ||
* @return void | ||
*/ | ||
#define cvector_insert(vec, pos, val) \ | ||
do { \ | ||
if (cvector_capacity(vec) <= cvector_size(vec) + 1) { \ | ||
cvector_grow((vec), cvector_compute_next_grow(cvector_capacity((vec)))); \ | ||
} \ | ||
if ((pos) < cvector_size(vec)) { \ | ||
memmove((vec) + (pos) + 1, (vec) + (pos), sizeof(*(vec)) * ((cvector_size(vec) + 1) - (pos))); \ | ||
} \ | ||
(vec)[(pos)] = (val); \ | ||
cvector_set_size((vec), cvector_size(vec) + 1); \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_pop_back - removes the last element from the vector | ||
* @param vec - the vector | ||
* @return void | ||
*/ | ||
#define cvector_pop_back(vec) \ | ||
do { \ | ||
cvector_elem_destructor_t elem_destructor__ = cvector_elem_destructor((vec)); \ | ||
if (elem_destructor__) \ | ||
elem_destructor__(&(vec)[cvector_size(vec) - 1]); \ | ||
cvector_set_size((vec), cvector_size(vec) - 1); \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_copy - copy a vector | ||
* @param from - the original vector | ||
* @param to - destination to which the function copy to | ||
* @return void | ||
*/ | ||
#define cvector_copy(from, to) \ | ||
do { \ | ||
if ((from)) { \ | ||
cvector_grow(to, cvector_size(from)); \ | ||
cvector_set_size(to, cvector_size(from)); \ | ||
memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector | ||
* @param vec - the vector | ||
* @param size - the new capacity to set | ||
* @return void | ||
*/ | ||
#define cvector_set_capacity(vec, size) \ | ||
do { \ | ||
if ((vec)) { \ | ||
((size_t *)(vec))[-1] = (size); \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_set_size - For internal use, sets the size variable of the vector | ||
* @param vec - the vector | ||
* @param size - the new capacity to set | ||
* @return void | ||
*/ | ||
#define cvector_set_size(vec, size) \ | ||
do { \ | ||
if ((vec)) { \ | ||
((size_t *)(vec))[-2] = (size); \ | ||
} \ | ||
} while (0) | ||
|
||
/** | ||
* @brief cvector_grow - For internal use, ensures that the vector is at least <count> elements big | ||
* @param vec - the vector | ||
* @param count - the new capacity to set | ||
* @return void | ||
*/ | ||
#define cvector_grow(vec, count) \ | ||
do { \ | ||
const size_t cv_sz__ = (count) * sizeof(*(vec)) + sizeof(size_t) * 2 + sizeof(cvector_elem_destructor_t); \ | ||
if ((vec)) { \ | ||
cvector_elem_destructor_t *cv_p1__ = &((cvector_elem_destructor_t *)&((size_t *)(vec))[-2])[-1]; \ | ||
cvector_elem_destructor_t *cv_p2__ = cvector_clib_realloc(cv_p1__, cv_sz__); \ | ||
assert(cv_p2__); \ | ||
(vec) = (void *)&((size_t *)&cv_p2__[1])[2]; \ | ||
} else { \ | ||
cvector_elem_destructor_t *cv_p__ = cvector_clib_malloc(cv_sz__); \ | ||
assert(cv_p__); \ | ||
(vec) = (void *)&((size_t *)&cv_p__[1])[2]; \ | ||
cvector_set_size((vec), 0); \ | ||
((cvector_elem_destructor_t *)&(((size_t *)(vec))[-2]))[-1] = NULL; \ | ||
} \ | ||
cvector_set_capacity((vec), (count)); \ | ||
} while (0) | ||
|
||
#endif /* CVECTOR_H_ */ |
Oops, something went wrong.