/* * Copyright (C) the libgit2 contributors. All rights reserved. * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. */ #ifndef INCLUDE_win32_w32_crtdbg_stacktrace_h__ #define INCLUDE_win32_w32_crtdbg_stacktrace_h__ #include "common.h" #if defined(GIT_MSVC_CRTDBG) #include #include #include "git2/errors.h" #include "strnlen.h" /** * Initialize our memory leak tracking and de-dup data structures. * This should ONLY be called by git_libgit2_init(). */ void git_win32__crtdbg_stacktrace_init(void); /** * Shutdown our memory leak tracking and dump summary data. * This should ONLY be called by git_libgit2_shutdown(). * * We explicitly call _CrtDumpMemoryLeaks() during here so * that we can compute summary data for the leaks. We print * the stacktrace of each unique leak. * * This cleanup does not happen if the app calls exit() * without calling the libgit2 shutdown code. * * This info we print here is independent of any automatic * reporting during exit() caused by _CRTDBG_LEAK_CHECK_DF. * Set it in your app if you also want traditional reporting. */ void git_win32__crtdbg_stacktrace_cleanup(void); /** * Checkpoint options. */ typedef enum git_win32__crtdbg_stacktrace_options { /** * Set checkpoint marker. */ GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK = (1 << 0), /** * Dump leaks since last checkpoint marker. * May not be combined with __LEAKS_TOTAL. * * Note that this may generate false positives for global TLS * error state and other global caches that aren't cleaned up * until the thread/process terminates. So when using this * around a region of interest, also check the final (at exit) * dump before digging into leaks reported here. */ GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK = (1 << 1), /** * Dump leaks since init. May not be combined * with __LEAKS_SINCE_MARK. */ GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL = (1 << 2), /** * Suppress printing during dumps. * Just return leak count. */ GIT_WIN32__CRTDBG_STACKTRACE__QUIET = (1 << 3), } git_win32__crtdbg_stacktrace_options; /** * Checkpoint memory state and/or dump unique stack traces of * current memory leaks. * * @return number of unique leaks (relative to requested starting * point) or error. */ GIT_EXTERN(int) git_win32__crtdbg_stacktrace__dump( git_win32__crtdbg_stacktrace_options opt, const char *label); /** * Construct stacktrace and append it to the global buffer. * Return pointer to start of this string. On any error or * lack of buffer space, just return the given file buffer * so it will behave as usual. * * This should ONLY be called by our internal memory allocations * routines. */ const char *git_win32__crtdbg_stacktrace(int skip, const char *file); GIT_INLINE(void *) git__crtdbg__malloc(size_t len, const char *file, int line) { void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(void *) git__crtdbg__calloc(size_t nelem, size_t elsize, const char *file, int line) { void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(char *) git__crtdbg__strdup(const char *str, const char *file, int line) { char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line); if (!ptr) giterr_set_oom(); return ptr; } GIT_INLINE(char *) git__crtdbg__strndup(const char *str, size_t n, const char *file, int line) { size_t length = 0, alloclength; char *ptr; length = p_strnlen(str, n); if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) || !(ptr = git__crtdbg__malloc(alloclength, file, line))) return NULL; if (length) memcpy(ptr, str, length); ptr[length] = '\0'; return ptr; } GIT_INLINE(char *) git__crtdbg__substrdup(const char *start, size_t n, const char *file, int line) { char *ptr; size_t alloclen; if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) || !(ptr = git__crtdbg__malloc(alloclen, file, line))) return NULL; memcpy(ptr, start, n); ptr[n] = '\0'; return ptr; } GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file, int line) { void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line); if (!new_ptr) giterr_set_oom(); return new_ptr; } GIT_INLINE(void *) git__crtdbg__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line) { size_t newsize; return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ? NULL : _realloc_dbg(ptr, newsize, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line); } GIT_INLINE(void *) git__crtdbg__mallocarray(size_t nelem, size_t elsize, const char *file, int line) { return git__crtdbg__reallocarray(NULL, nelem, elsize, file, line); } #endif #endif