Skip to content
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

Feature: Support reports on demand #12

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Library
add_library(heapusage SHARED src/humain.cpp src/hulog.cpp src/humalloc.cpp)
add_library(heapusage SHARED src/humain.cpp src/hulog.cpp src/humalloc.cpp src/huapi.cpp)
set_target_properties(heapusage PROPERTIES PUBLIC_HEADER "src/huapi.h")
target_compile_features(heapusage PRIVATE cxx_variadic_templates)
install(TARGETS heapusage LIBRARY DESTINATION lib)
install(TARGETS heapusage
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
target_link_libraries(heapusage pthread dl)

# Dependency backward-cpp providing more detailed stacktraces on Linux, when
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,20 @@ Examples:
heapusage -t all -m 0 ./ex002
analyze heap allocations of any size with all tools.

Programs being ran with Heapusage can themselves also request reports from
Heapusage, while the program is running, by using the `hu_report()` public API
function. For doing so, they must include the `huapi.h` public header file, link
with the Heapusage shared library itself and call `hu_report()` when wanted.
Still, this only works if the program is running through the `heapusage` tool.

Alternatively, on Linux, sending a `SIGUSR1` signal to the program being run
through Heapusage will also produce a Heapusage report on demand.

For both `hu_report()` and `SIGUSR1`, it should be noted that the report will
reflect the state when they are used, which can e.g. report non-freed memory
that might be still released before the program exits and, therefore, not
necessarily constitute a memory leak.

Output Format
=============
Example output:
Expand Down
22 changes: 22 additions & 0 deletions src/huapi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* huapi.cpp
*
* Copyright (C) 2017-2021 Kristofer Berggren
* All rights reserved.
*
* heapusage is distributed under the BSD 3-Clause license, see LICENSE for details.
*
*/


/* ----------- Includes ------------------------------------------ */
#include "hulog.h"


/* ----------- Global Functions ---------------------------------- */

extern "C" void hu_report()
{
log_message("hu_report: Request Log Summary\n");
log_summary_safe();
}
27 changes: 27 additions & 0 deletions src/huapi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* huapi.h
*
* Copyright (C) 2021 Kristofer Berggren
* All rights reserved.
*
* heapusage is distributed under the BSD 3-Clause license, see LICENSE for details.
*
*/

#ifndef _HUAPI_H_
#define _HUAPI_H_


/* ----------- Global Function Prototypes ------------------------ */

#ifdef __cplusplus
extern "C" {
#endif

void hu_report(void);

#ifdef __cplusplus
}
#endif

#endif /* _HUAPI_H_ */
38 changes: 37 additions & 1 deletion src/hulog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h>

#include <map>
#include <set>
Expand Down Expand Up @@ -385,6 +386,30 @@ void hu_sig_handler(int sig, siginfo_t* si, void* /*ucontext*/)
exit(EXIT_FAILURE);
}

void log_message(const char *format, ...)
{
va_list args;

FILE *f = NULL;
if (hu_log_file)
{
f = fopen(hu_log_file, "a");
}

if (!f)
{
return;
}

fprintf(f, "==%d== MESSAGE: ", pid);

va_start(args, format);
vfprintf(f, format, args);
va_end(args);

fclose(f);
}

void log_summary()
{
FILE *f = NULL;
Expand All @@ -402,7 +427,7 @@ void log_summary()
unsigned long long leak_total_blocks = 0;

/* Group results by callstack */
static std::map<std::vector<void*>, hu_allocinfo_t> allocations_by_callstack;
std::map<std::vector<void*>, hu_allocinfo_t> allocations_by_callstack;
for (auto it = allocations->begin(); it != allocations->end(); ++it)
{
std::vector<void*> callstack;
Expand Down Expand Up @@ -465,6 +490,17 @@ void log_summary()
fclose(f);
}

void log_summary_safe()
{
hu_set_bypass(true);
log_enable(0);

log_summary();

log_enable(1);
hu_set_bypass(false);
}

void hu_log_remove_freed_allocation(void* ptr)
{
if (!hu_log_free)
Expand Down
2 changes: 2 additions & 0 deletions src/hulog.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@ void log_enable(int flag);
void log_event(int event, void* ptr, size_t size);
void log_invalid_access(void* ptr);
void hu_sig_handler(int sig, siginfo_t* si, void* /*ucontext*/);
void log_message(const char *format, ...);
void log_summary();
void log_summary_safe();
void hu_log_remove_freed_allocation(void* ptr);
30 changes: 30 additions & 0 deletions src/humain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,34 @@ static inline bool hu_get_env_bool(const char* name)
return (strcmp(value, "1") == 0);
}

#if defined(__linux__)
static void hu_sigusr_handler(int sig)
{
switch (sig) {
case SIGUSR1:
log_message("Caught User Signal: SIGUSR1 (%d): Request Log Summary\n", sig);
log_summary_safe();
break;
default:
log_message("Caught User Signal: Unexpected Signal (%d): Ignore\n", sig);
break;
}
}
#endif

static void hu_sigusr_init(void)
{
#if defined(__linux__)
struct sigaction sa;

sa.sa_handler = hu_sigusr_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
#endif
}


/* ----------- Global Functions ---------------------------------- */
extern "C"
Expand All @@ -116,6 +144,8 @@ void __attribute__ ((constructor)) hu_init(void)
hu_malloc_init(hu_overflow, hu_useafterfree, hu_minsize);
}

hu_sigusr_init();

/* Do not enable preload for child processes */
unsetenv("DYLD_INSERT_LIBRARIES");
unsetenv("LD_PRELOAD");
Expand Down
Loading