/* -*- Mode: C; c-basic-offset: 2; indent-tabs-mode: nil -*- */ /* Copyright (c) 2009, Google Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * --- * Author: Craig Silverstein * * This tests the c shims: malloc_extension_c.h and malloc_hook_c.h. * Mostly, we'll just care that these shims compile under gcc * (*not* g++!) * * NOTE: this is C code, not C++ code! */ #include #include #include /* for size_t */ #include #include #define FAIL(msg) do { \ fprintf(stderr, "FATAL ERROR: %s\n", msg); \ exit(1); \ } while (0) static int g_new_hook_calls = 0; static int g_delete_hook_calls = 0; void TestNewHook(const void* ptr, size_t size) { g_new_hook_calls++; } void TestDeleteHook(const void* ptr) { g_delete_hook_calls++; } static void *forced_malloc(size_t size) { extern void *tc_malloc(size_t); void *rv = tc_malloc(size); if (!rv) { FAIL("malloc is not supposed to fail here"); } return rv; } void TestMallocHook(void) { /* TODO(csilvers): figure out why we get: * E0100 00:00:00.000000 7383 malloc_hook.cc:244] RAW: google_malloc section is missing, thus InHookCaller is broken! */ #if 0 void* result[5]; if (MallocHook_GetCallerStackTrace(result, sizeof(result)/sizeof(*result), 0) < 2) { /* should have this and main */ FAIL("GetCallerStackTrace failed"); } #endif if (!MallocHook_AddNewHook(&TestNewHook)) { FAIL("Failed to add new hook"); } if (!MallocHook_AddDeleteHook(&TestDeleteHook)) { FAIL("Failed to add delete hook"); } free(forced_malloc(10)); free(forced_malloc(20)); if (g_new_hook_calls != 2) { FAIL("Wrong number of calls to the new hook"); } if (g_delete_hook_calls != 2) { FAIL("Wrong number of calls to the delete hook"); } if (!MallocHook_RemoveNewHook(&TestNewHook)) { FAIL("Failed to remove new hook"); } if (!MallocHook_RemoveDeleteHook(&TestDeleteHook)) { FAIL("Failed to remove delete hook"); } free(forced_malloc(10)); free(forced_malloc(20)); if (g_new_hook_calls != 2) { FAIL("Wrong number of calls to the new hook"); } MallocHook_SetNewHook(&TestNewHook); MallocHook_SetDeleteHook(&TestDeleteHook); free(forced_malloc(10)); free(forced_malloc(20)); if (g_new_hook_calls != 4) { FAIL("Wrong number of calls to the singular new hook"); } if (MallocHook_SetNewHook(NULL) == NULL) { FAIL("Failed to set new hook"); } if (MallocHook_SetDeleteHook(NULL) == NULL) { FAIL("Failed to set delete hook"); } } void TestMallocExtension(void) { int blocks; size_t total; int hist[64]; char buffer[200]; char* x = (char*)malloc(10); MallocExtension_VerifyAllMemory(); MallocExtension_VerifyMallocMemory(x); MallocExtension_MallocMemoryStats(&blocks, &total, hist); MallocExtension_GetStats(buffer, sizeof(buffer)); if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes", &total)) { FAIL("GetNumericProperty failed for generic.current_allocated_bytes"); } if (total < 10) { FAIL("GetNumericProperty had bad return for generic.current_allocated_bytes"); } if (!MallocExtension_GetNumericProperty("generic.current_allocated_bytes", &total)) { FAIL("GetNumericProperty failed for generic.current_allocated_bytes"); } MallocExtension_MarkThreadIdle(); MallocExtension_MarkThreadBusy(); MallocExtension_ReleaseToSystem(1); MallocExtension_ReleaseFreeMemory(); if (MallocExtension_GetEstimatedAllocatedSize(10) < 10) { FAIL("GetEstimatedAllocatedSize returned a bad value (too small)"); } if (MallocExtension_GetAllocatedSize(x) < 10) { FAIL("GetEstimatedAllocatedSize returned a bad value (too small)"); } if (MallocExtension_GetOwnership(x) != MallocExtension_kOwned) { FAIL("DidAllocatePtr returned a bad value (kNotOwned)"); } /* TODO(csilvers): this relies on undocumented behavior that GetOwnership works on stack-allocated variables. Use a better test. */ if (MallocExtension_GetOwnership(hist) != MallocExtension_kNotOwned) { FAIL("DidAllocatePtr returned a bad value (kOwned)"); } free(x); } int main(int argc, char** argv) { TestMallocHook(); TestMallocExtension(); printf("PASS\n"); return 0; }