-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enable tracking of C memory allocations #57
base: main
Are you sure you want to change the base?
Conversation
Nice stuff. Rather than putting this into zoslib, can you explore putting it into the clang address analyzer (https://clang.llvm.org/docs/AddressSanitizer.html). More people know about this. |
Thanks. Wouldn't that require adding support for those features (AddressSanitizer, LeakSanitizer, ?) to z/OS clang, using the same implementation as done for the other supported platforms? Here we also track allocations from iarv64 and 31-bit, and support an app to call |
src/zos-sys-info.cc
Outdated
// returns timestamp as yyyy-mm-dd hh:mm:ss, so char ts[20] | ||
time_t lt = time(NULL); | ||
struct tm *tm = localtime(<); | ||
sprintf(ts,"%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year+1900, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you check the return code in sprintf and return NULL if -1?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One comment, otherwise LGTM. Thanks!
Also init the passed ts arg to "(error)" in case an error occurred, instead of checking the return code.
This change was previously done in the internal zoslib to investigate a memory leak in a customer app running Node.js.
Previously, tracking of memory [de]allocations was only performed on memory from virtual storage (iarv64) and __malloc31, by using a
std::unordered_map
to store each allocated pointer and its size, and that was always performed regardless of any compiler option.In this PR each allocation from malloc, calloc, realloc, strdup, strndup, iarv64 and __malloc31 is stored as a node (
__taddr_t
) in a binary search tree that stores, for each allocation, the allocated address (key), its size, source (filename:linenum) from which the allocation call was made, and the address space (31-bit, 64-bit heap or 64-bit virtual storage). This is enabled only when zoslib and the app are built withCFLAGS=CXXFLAGS=-DZOSLIB_TRACE_ALLOCS
Another binary search tree keeps track of all source locations (filename:linenum) that allocated memory, storing details such as the filename:linenum (key), num of bytes currently still allocated from this location, max num of bytes allocated from this location, num of times an allocation has been called from this location, num of times an allocation from this location has been freed, and the address space for the allocation from this source.
It's possible to display the allocations report (e.g. below) by calling
__display_alloc_stats(false, false);
whenever some signal is received (e.g. SIGUSR2), where the 2nd arg is false so the report only contains those allocations that changed since the last report. This would be useful to monitor the memory status for a long-running app.As a test, I ran zoslib's
cctest_a
; the report shows all C allocations it makes, as well as a few memory leaks:The new internal environment variable
__MEMORY_USAGE_ALLOC_TB_WARNING
is effective only if__MEMORY_USAGE_LOG_LEVEL
is 1 or 2, and results in a traceback whenever a warning is encountered (e.g. address being freed is not in cache, or address allocated is already in cache, or realloc called with ptr=0 and new-size=0).and the following with example settings:
result in a source traceback displayed whenever an allocation is made from the given
__MEMORY_USAGE_ALLOC_TB_SOURCE
,or if
__MEMORY_USAGE_ALLOC_TB_SOURCE_I
is set, then when only the i'th allocation from the given source is made,or if
__MEMORY_USAGE_ALLOC_TB_SOURCE_J
is also set, then when only the allocation occurrence from the givenlocation is between the given range. A range will almost always be required because the order of allocations usually differs between different runs for the same test.