blob: 84d438af7dccb50f0f857b052f7015ffb636c88d [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2009-2010 VMware, Inc. All rights reserved.
* **********************************************************/
/* Dr. Memory: the memory debugger
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License, and no later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef ASM_CODE_ONLY /* C code ***********************************************/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#ifdef UNIX
# include <unistd.h>
# include <signal.h>
# include <errno.h>
/* just use single-arg handlers */
typedef void (*handler_t)(int);
typedef void (*handler_3_t)(int, siginfo_t *, void *);
#endif
void infloop_asm(void **p2);
#ifdef UNIX
static void
signal_handler(int sig)
{
if (sig == SIGTERM)
fprintf(stderr, "done\n");
exit(1);
}
static void
intercept_signal(int sig, handler_t handler)
{
int rc;
struct sigaction act;
act.sa_sigaction = (handler_3_t) handler;
rc = sigemptyset(&act.sa_mask); /* block no signals within handler */
assert(rc == 0);
act.sa_flags = SA_NODEFER | SA_SIGINFO | SA_ONSTACK;
rc = sigaction(sig, &act, NULL);
assert(rc == 0);
}
#else
/* sort of a hack to avoid the MessageBox of the unhandled exception spoiling
* our batch runs
*/
# include <windows.h>
/* top-level exception handler */
static LONG
our_top_handler(struct _EXCEPTION_POINTERS * pExceptionInfo)
{
fprintf(stderr, "done\n");
return EXCEPTION_EXECUTE_HANDLER; /* => global unwind and silent death */
}
#endif
static void *p2;
void
foo(void)
{
int i;
void *p1;
/* error: both leaked, though one points to other neither is reachable
* once p1 goes out of scope
*/
p1 = malloc(42);
*((void**)p1) = malloc(17);
/* not a leak: still reachable through persistent pointer p2 */
p2 = malloc(8);
*((void**)p2) = malloc(19);
/* Ensure duplicate leaks are counted properly (xref PR 578897) even
* across multiple nudges
*/
for (i = 0; i < 20; i++) {
p1 = malloc(160);
}
}
int
main()
{
#ifdef UNIX
intercept_signal(SIGTERM, signal_handler);
#else
/* for nudge handle leak test */
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER) our_top_handler);
#endif
/* PR 428709: test leak detection via nudge */
foo();
/* indicate we're ready for the nudge: well, really we want to
* get to the infloop, but close enough
*/
fprintf(stderr, "starting\n");
fflush(stderr);
infloop_asm(&p2);
return 0;
}
#else /* asm code *************************************************************/
#include "cpp2asm_defines.h"
START_FILE
/* number of times to overflow 32-bit counter before exiting, since we don't
* really want to spin forever if somehow the test wrapper fails to kill us.
* overflowing a 32-bit counter takes betwee 2 and 3 seconds.
* this value of 20 ends up taking 56 seconds on my laptop.
* we want well over any time the test may take to complete.
*/
#define MAX_ITERS_DIV_4G HEX(14)
#define FUNCNAME infloop_asm
/* void infloop(void **p2); */
DECLARE_FUNC_SEH(FUNCNAME)
GLOBAL_LABEL(FUNCNAME:)
mov REG_XDX, ARG1
push REG_XBP
mov REG_XBP, REG_XSP
END_PROLOG
/* test register as root: the only pointer to p2's malloc will be in eax: */
mov REG_XAX, PTRSZ [REG_XDX]
mov PTRSZ [REG_XDX], 0
/* make sure no other registers point to p2 */
mov REG_XBX, 0
mov REG_XCX, 0
mov REG_XDX, 0
mov REG_XSI, 0
mov REG_XDI, 0
infloop_repeat:
inc ecx
cmp ecx, 0 /* wraparound */
jne infloop_repeat
inc edx
cmp edx, MAX_ITERS_DIV_4G
jne infloop_repeat
add REG_XSP, 0 /* make a legal SEH64 epilog */
mov REG_XSP, REG_XBP
pop REG_XBP
ret
END_FUNC(FUNCNAME)
#undef FUNCNAME
END_FILE
#endif