Commit 93b42728 by Jeff Hostetler Committed by Jeff Hostetler

Include stacktrace summary in memory leak output.

parent 4a0313bc
......@@ -336,6 +336,7 @@ IF (MSVC)
IF (MSVC_CRTDBG)
SET(CRT_FLAG_DEBUG "${CRT_FLAG_DEBUG} /DGIT_MSVC_CRTDBG")
SET(CMAKE_C_STANDARD_LIBRARIES "${CMAKE_C_STANDARD_LIBRARIES}" "Dbghelp.lib")
ENDIF()
# /Zi - Create debugging information
......
......@@ -46,6 +46,10 @@
# ifdef GIT_THREADS
# include "win32/pthread.h"
# endif
# if defined(GIT_MSVC_CRTDBG)
# include "win32/w32_stack.h"
# include "win32/w32_crtdbg_stacktrace.h"
# endif
#else
......
......@@ -11,7 +11,10 @@
#include "git2/global.h"
#include "git2/sys/openssl.h"
#include "thread-utils.h"
#if defined(GIT_MSVC_CRTDBG)
#include "win32/w32_stack.h"
#include "win32/w32_crtdbg_stacktrace.h"
#endif
git_mutex git__mwindow_mutex;
......@@ -225,6 +228,11 @@ int git_libgit2_init(void)
/* Only do work on a 0 -> 1 transition of the refcount */
if ((ret = git_atomic_inc(&git__n_inits)) == 1) {
#if defined(GIT_MSVC_CRTDBG)
git_win32__crtdbg_stacktrace_init();
git_win32__stack_init();
#endif
if (synchronized_threads_init() < 0)
ret = -1;
}
......@@ -254,9 +262,15 @@ int git_libgit2_shutdown(void)
while (InterlockedCompareExchange(&_mutex, 1, 0)) { Sleep(0); }
/* Only do work on a 1 -> 0 transition of the refcount */
if ((ret = git_atomic_dec(&git__n_inits)) == 0)
if ((ret = git_atomic_dec(&git__n_inits)) == 0) {
synchronized_threads_shutdown();
#if defined(GIT_MSVC_CRTDBG)
git_win32__crtdbg_stacktrace_cleanup();
git_win32__stack_cleanup();
#endif
}
/* Exit the lock */
InterlockedExchange(&_mutex, 0);
......
......@@ -35,6 +35,7 @@
*/
#include <stdlib.h>
#include <crtdbg.h>
#include "win32/w32_crtdbg_stacktrace.h"
#endif
#include "common.h"
......@@ -62,23 +63,24 @@
#define CONST_STRLEN(x) ((sizeof(x)/sizeof(x[0])) - 1)
#if defined(GIT_MSVC_CRTDBG)
GIT_INLINE(void *) git__crtdbg__malloc(size_t len, const char *file, int line)
{
void *ptr = _malloc_dbg(len, _NORMAL_BLOCK, file, 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, file, 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, file, line);
char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32__crtdbg_stacktrace(1,file), line);
if (!ptr) giterr_set_oom();
return ptr;
}
......@@ -118,7 +120,7 @@ GIT_INLINE(char *) git__crtdbg__substrdup(const char *start, size_t n, const cha
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, file, 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;
}
......@@ -126,8 +128,9 @@ GIT_INLINE(void *) git__crtdbg__realloc(void *ptr, size_t size, const char *file
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, file, line);
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)
......
/*
* 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_w32_crtdbg_stacktrace_h__
#define INCLUDE_w32_crtdbg_stacktrace_h__
#if defined(GIT_MSVC_CRTDBG)
/**
* 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);
#endif
#endif
/*
* 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.
*/
#if defined(GIT_MSVC_CRTDBG)
#include "Windows.h"
#include "Dbghelp.h"
#include "win32/posix.h"
#include "w32_stack.h"
#include "hash.h"
/**
* This is supposedly defined in WinBase.h (from Windows.h) but there were linker issues.
*/
USHORT WINAPI RtlCaptureStackBackTrace(ULONG, ULONG, PVOID*, PULONG);
static bool g_win32_stack_initialized = false;
static HANDLE g_win32_stack_process = INVALID_HANDLE_VALUE;
static git_win32__stack__aux_cb_alloc g_aux_cb_alloc = NULL;
static git_win32__stack__aux_cb_lookup g_aux_cb_lookup = NULL;
int git_win32__stack__set_aux_cb(
git_win32__stack__aux_cb_alloc cb_alloc,
git_win32__stack__aux_cb_lookup cb_lookup)
{
g_aux_cb_alloc = cb_alloc;
g_aux_cb_lookup = cb_lookup;
return 0;
}
void git_win32__stack_init(void)
{
if (!g_win32_stack_initialized) {
g_win32_stack_process = GetCurrentProcess();
SymSetOptions(SYMOPT_LOAD_LINES);
SymInitialize(g_win32_stack_process, NULL, TRUE);
g_win32_stack_initialized = true;
}
}
void git_win32__stack_cleanup(void)
{
if (g_win32_stack_initialized) {
SymCleanup(g_win32_stack_process);
g_win32_stack_process = INVALID_HANDLE_VALUE;
g_win32_stack_initialized = false;
}
}
int git_win32__stack_capture(git_win32__stack__raw_data *pdata, int skip)
{
if (!g_win32_stack_initialized) {
giterr_set(GITERR_INVALID, "git_win32_stack not initialized.");
return GIT_ERROR;
}
memset(pdata, 0, sizeof(*pdata));
pdata->nr_frames = RtlCaptureStackBackTrace(
skip+1, GIT_WIN32__STACK__MAX_FRAMES, pdata->frames, NULL);
/* If an "aux" data provider was registered, ask it to capture
* whatever data it needs and give us an "aux_id" to it so that
* we can refer to it later when reporting.
*/
if (g_aux_cb_alloc)
(g_aux_cb_alloc)(&pdata->aux_id);
return 0;
}
int git_win32__stack_compare(
git_win32__stack__raw_data *d1,
git_win32__stack__raw_data *d2)
{
return memcmp(d1, d2, sizeof(d1));
}
int git_win32__stack_format(
char *pbuf, int buf_len,
const git_win32__stack__raw_data *pdata,
const char *prefix, const char *suffix)
{
#define MY_MAX_FILENAME 255
/* SYMBOL_INFO has char FileName[1] at the end. The docs say to
* to malloc it with extra space for your desired max filename.
* We use a union to do the same thing without mallocing.
*/
struct {
SYMBOL_INFO symbol;
char extra[MY_MAX_FILENAME + 1];
} s;
IMAGEHLP_LINE64 line;
int buf_used = 0;
unsigned int k;
char detail[MY_MAX_FILENAME * 2]; /* filename plus space for function name and formatting */
int detail_len;
if (!g_win32_stack_initialized) {
giterr_set(GITERR_INVALID, "git_win32_stack not initialized.");
return GIT_ERROR;
}
if (!prefix)
prefix = "\t";
if (!suffix)
suffix = "\n";
memset(pbuf, 0, buf_len);
memset(&s, 0, sizeof(s));
s.symbol.MaxNameLen = MY_MAX_FILENAME;
s.symbol.SizeOfStruct = sizeof(SYMBOL_INFO);
memset(&line, 0, sizeof(line));
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
for (k=0; k < pdata->nr_frames; k++) {
DWORD64 frame_k = (DWORD64)pdata->frames[k];
DWORD dwUnused;
if (SymFromAddr(g_win32_stack_process, frame_k, 0, &s.symbol) &&
SymGetLineFromAddr64(g_win32_stack_process, frame_k, &dwUnused, &line)) {
const char *pslash;
const char *pfile;
pslash = strrchr(line.FileName, '\\');
pfile = ((pslash) ? (pslash+1) : line.FileName);
p_snprintf(detail, sizeof(detail), "%s%s:%d> %s%s",
prefix, pfile, line.LineNumber, s.symbol.Name, suffix);
} else {
/* This happens when we cross into another module.
* For example, in CLAR tests, this is typically
* the CRT startup code. Just print an unknown
* frame and continue.
*/
p_snprintf(detail, sizeof(detail), "%s??%s", prefix, suffix);
}
detail_len = strlen(detail);
if (buf_len < (buf_used + detail_len + 1)) {
/* we don't have room for this frame in the buffer, so just stop. */
break;
}
memcpy(&pbuf[buf_used], detail, detail_len);
buf_used += detail_len;
}
/* If an "aux" data provider was registered, ask it to append its detailed
* data to the end of ours using the "aux_id" it gave us when this de-duped
* item was created.
*/
if (g_aux_cb_lookup)
(g_aux_cb_lookup)(pdata->aux_id, &pbuf[buf_used], (buf_len - buf_used - 1));
return GIT_OK;
}
int git_win32__stack(
char * pbuf, int buf_len,
int skip,
const char *prefix, const char *suffix)
{
git_win32__stack__raw_data data;
int error;
if ((error = git_win32__stack_capture(&data, skip)) < 0)
return error;
if ((error = git_win32__stack_format(pbuf, buf_len, &data, prefix, suffix)) < 0)
return error;
return 0;
}
#endif
/*
* 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_w32_stack_h__
#define INCLUDE_w32_stack_h__
#if defined(GIT_MSVC_CRTDBG)
/**
* This type defines a callback to be used to augment a C stacktrace
* with "aux" data. This can be used, for example, to allow LibGit2Sharp
* (or other interpreted consumer libraries) to give us C# stacktrace
* data for the PInvoke.
*
* This callback will be called during crtdbg-instrumented allocs.
*
* @param aux_id [out] A returned "aux_id" representing a unique
* (de-duped at the C# layer) stacktrace.
*/
typedef void (*git_win32__stack__aux_cb_alloc)(unsigned int *aux_id);
/**
* This type defines a callback to be used to augment the output of
* a stacktrace. This will be used to request the C# layer format
* the C# stacktrace associated with "aux_id" into the provided
* buffer.
*
* This callback will be called during leak reporting.
*
* @param aux_id The "aux_id" key associated with a stacktrace.
* @param aux_msg A buffer where a formatted message should be written.
* @param aux_msg_len The size of the buffer.
*/
typedef void (*git_win32__stack__aux_cb_lookup)(unsigned int aux_id, char *aux_msg, unsigned int aux_msg_len);
/**
* Register an "aux" data provider to augment our C stacktrace data.
*
* This can be used, for example, to allow LibGit2Sharp (or other
* interpreted consumer libraries) to give us the C# stacktrace of
* the PInvoke.
*
* If you choose to use this feature, it should be registered during
* initialization and not changed for the duration of the process.
*/
GIT_EXTERN(int) git_win32__stack__set_aux_cb(
git_win32__stack__aux_cb_alloc cb_alloc,
git_win32__stack__aux_cb_lookup cb_lookup);
/**
* Maximum number of stackframes to record for a
* single stacktrace.
*/
#define GIT_WIN32__STACK__MAX_FRAMES 30
/**
* Wrapper containing the raw unprocessed stackframe
* data for a single stacktrace and any "aux_id".
*/
typedef struct {
void *frames[GIT_WIN32__STACK__MAX_FRAMES];
unsigned int nr_frames;
unsigned int aux_id;
} git_win32__stack__raw_data;
/**
* Load symbol table data. This should be done in the primary
* thread at startup (under a lock if there are other threads
* active).
*/
void git_win32__stack_init(void);
/**
* Cleanup symbol table data. This should be done in the
* primary thead at shutdown (under a lock if there are other
* threads active).
*/
void git_win32__stack_cleanup(void);
/**
* Capture raw stack trace data for the current process/thread.
*
* @param skip Number of initial frames to skip. Pass 0 to
* begin with the caller of this routine. Pass 1 to begin
* with its caller. And so on.
*/
int git_win32__stack_capture(git_win32__stack__raw_data *pdata, int skip);
/**
* Compare 2 raw stacktraces with the usual -1,0,+1 result.
* This includes any "aux_id" values in the comparison, so that
* our de-dup is also "aux" context relative.
*/
int git_win32__stack_compare(
git_win32__stack__raw_data *d1,
git_win32__stack__raw_data *d2);
/**
* Format raw stacktrace data into buffer WITHOUT using any mallocs.
*
* @param prefix String written before each frame; defaults to "\t".
* @param suffix String written after each frame; defaults to "\n".
*/
int git_win32__stack_format(
char *pbuf, int buf_len,
const git_win32__stack__raw_data *pdata,
const char *prefix, const char *suffix);
/**
* Convenience routine to capture and format stacktrace into
* a buffer WITHOUT using any mallocs. This is primarily a
* wrapper for testing.
*
* @param skip Number of initial frames to skip. Pass 0 to
* begin with the caller of this routine. Pass 1 to begin
* with its caller. And so on.
* @param prefix String written before each frame; defaults to "\t".
* @param suffix String written after each frame; defaults to "\n".
*/
int git_win32__stack(
char * pbuf, int buf_len,
int skip,
const char *prefix, const char *suffix);
#endif /* GIT_MSVC_CRTDBG */
#endif /* INCLUDE_w32_stack_h__ */
......@@ -142,9 +142,28 @@ void _cl_trace_cb__event_handler(
switch (ev) {
case CL_TRACE__SUITE_BEGIN:
git_trace(GIT_TRACE_TRACE, "\n\n%s\n%s: Begin Suite", HR, suite_name);
#if 0 && defined(GIT_MSVC_CRTDBG)
git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
suite_name);
#endif
break;
case CL_TRACE__SUITE_END:
#if 0 && defined(GIT_MSVC_CRTDBG)
/* As an example of checkpointing, dump leaks within this suite.
* This may generate false positives for things like the global
* TLS error state and maybe the odb cache since they aren't
* freed until the global shutdown and outside the scope of this
* set of tests.
*
* This may under-report if the test itself uses a checkpoint.
* See tests/trace/windows/stacktrace.c
*/
git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
suite_name);
#endif
git_trace(GIT_TRACE_TRACE, "\n\n%s: End Suite\n%s", suite_name, HR);
break;
......
#if defined(GIT_MSVC_CRTDBG)
/* Enable MSVC CRTDBG memory leak reporting. See src/util.h for details. */
#include <stdlib.h>
#include <crtdbg.h>
#endif
#include "clar_libgit2.h"
#include "clar_libgit2_trace.h"
......@@ -16,18 +9,6 @@ int main(int argc, char *argv[])
{
int res;
#if defined(GIT_MSVC_CRTDBG)
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
#endif
clar_test_init(argc, argv);
git_libgit2_init();
......
#include "clar_libgit2.h"
#include "win32/w32_stack.h"
#if defined(GIT_MSVC_CRTDBG)
static void a(void)
{
char buf[10000];
cl_assert(git_win32__stack(buf, sizeof(buf), 0, NULL, NULL) == 0);
#if 0
fprintf(stderr, "Stacktrace from [%s:%d]:\n%s\n", __FILE__, __LINE__, buf);
#endif
}
static void b(void)
{
a();
}
static void c(void)
{
b();
}
#endif
void test_trace_windows_stacktrace__basic(void)
{
#if defined(GIT_MSVC_CRTDBG)
c();
#endif
}
void test_trace_windows_stacktrace__leaks(void)
{
#if defined(GIT_MSVC_CRTDBG)
void * p1;
void * p2;
void * p3;
void * p4;
int before, after;
int leaks;
int error;
/* remember outstanding leaks due to set setup
* and set mark/checkpoint.
*/
before = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL |
GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
NULL);
p1 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1");
cl_assert((leaks == 1));
p2 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p2");
cl_assert((leaks == 2));
p3 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p2,p3");
cl_assert((leaks == 3));
git__free(p2);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p1,p3");
cl_assert((leaks == 2));
/* move the mark. only new leaks should appear afterwards */
error = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__SET_MARK,
NULL);
cl_assert((error == 0));
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"not_p1,not_p3");
cl_assert((leaks == 0));
p4 = git__malloc(5);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p4,not_p1,not_p3");
cl_assert((leaks == 1));
git__free(p1);
git__free(p3);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"p4");
cl_assert((leaks == 1));
git__free(p4);
leaks = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_SINCE_MARK,
"end");
cl_assert((leaks == 0));
/* confirm current absolute leaks count matches beginning value. */
after = git_win32__crtdbg_stacktrace__dump(
GIT_WIN32__CRTDBG_STACKTRACE__QUIET |
GIT_WIN32__CRTDBG_STACKTRACE__LEAKS_TOTAL,
"total");
cl_assert((before == after));
#endif
}
#if defined(GIT_MSVC_CRTDBG)
static void aux_cb_alloc__1(unsigned int *aux_id)
{
static unsigned int aux_counter = 0;
*aux_id = aux_counter++;
}
static void aux_cb_lookup__1(unsigned int aux_id, char *aux_msg, unsigned int aux_msg_len)
{
p_snprintf(aux_msg, aux_msg_len, "\tQQ%08x\n", aux_id);
}
#endif
void test_trace_windows_stacktrace__aux1(void)
{
#if defined(GIT_MSVC_CRTDBG)
git_win32__stack__set_aux_cb(aux_cb_alloc__1, aux_cb_lookup__1);
c();
c();
c();
c();
git_win32__stack__set_aux_cb(NULL, NULL);
#endif
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment