tests/auto/exceptionsafety_objects/oomsimulator.h
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #ifndef Q_OS_SYMBIAN
       
    43 #include <malloc.h>
       
    44 #endif
       
    45 #include <limits.h>
       
    46 #include <stdio.h>
       
    47 #include <exception>
       
    48 
       
    49 #if !defined(Q_OS_WIN) && !defined(Q_OS_SYMBIAN)
       
    50 #  include "3rdparty/memcheck.h"
       
    51 #endif
       
    52 
       
    53 static bool mallocFailActive = false;
       
    54 static int mallocFailIndex = 0;
       
    55 static int mallocCount = 0;
       
    56 
       
    57 static void my_terminate_handler()
       
    58 {
       
    59     // set a breakpoint here to get a backtrace for your uncaught exceptions
       
    60     fprintf(stderr, "Uncaught Exception Detected. Set a breakpoint in my_terminate_handler()\n");
       
    61     exit(1);
       
    62 }
       
    63 
       
    64 #ifdef __GLIBC__
       
    65 /* Use glibc's memory allocation hooks */
       
    66 
       
    67 /* our hooks */
       
    68 static void *my_malloc_hook(size_t, const void *);
       
    69 static void *my_realloc_hook(void *, size_t, const void *);
       
    70 static void *my_memalign_hook(size_t, size_t, const void *);
       
    71 static void my_free_hook(void *, const void *);
       
    72 
       
    73 /* original hooks. */
       
    74 static void *(*old_malloc_hook)(size_t, const void *);
       
    75 static void *(*old_realloc_hook)(void *, size_t, const void *);
       
    76 static void *(*old_memalign_hook)(size_t, size_t, const void *);
       
    77 static void (*old_free_hook)(void *, const void *);
       
    78 
       
    79 /* initializer function */
       
    80 static void my_init_hook();
       
    81 
       
    82 /* Override initialising hook from the C library. */
       
    83 void (*__malloc_initialize_hook) (void) = my_init_hook;
       
    84 
       
    85 static void disableHooks()
       
    86 {
       
    87     __malloc_hook = old_malloc_hook;
       
    88     __realloc_hook = old_realloc_hook;
       
    89     __memalign_hook = old_memalign_hook;
       
    90     __free_hook = old_free_hook;
       
    91 }
       
    92 
       
    93 static void enableHooks()
       
    94 {
       
    95     __malloc_hook = my_malloc_hook;
       
    96     __realloc_hook = my_realloc_hook;
       
    97     __memalign_hook = my_memalign_hook;
       
    98     __free_hook = my_free_hook;
       
    99 }
       
   100 
       
   101 void my_init_hook()
       
   102 {
       
   103     old_malloc_hook = __malloc_hook;
       
   104     old_realloc_hook = __realloc_hook;
       
   105     old_memalign_hook = __memalign_hook;
       
   106     old_free_hook = __free_hook;
       
   107     enableHooks();
       
   108 }
       
   109 
       
   110 void *my_malloc_hook(size_t size, const void *)
       
   111 {
       
   112     ++mallocCount;
       
   113 
       
   114     if (mallocFailActive && --mallocFailIndex < 0)
       
   115         return 0; // simulate OOM
       
   116 
       
   117     __malloc_hook = old_malloc_hook;
       
   118     void *result = ::malloc (size);
       
   119     __malloc_hook = my_malloc_hook;
       
   120 
       
   121     return result;
       
   122 }
       
   123 
       
   124 void *my_memalign_hook(size_t alignment, size_t size, const void *)
       
   125 {
       
   126     ++mallocCount;
       
   127 
       
   128     if (mallocFailActive && --mallocFailIndex < 0)
       
   129         return 0; // simulate OOM
       
   130 
       
   131     __memalign_hook = old_memalign_hook;
       
   132     void *result = ::memalign(alignment, size);
       
   133     __memalign_hook = my_memalign_hook;
       
   134 
       
   135     return result;
       
   136 }
       
   137 
       
   138 void *my_realloc_hook(void *ptr, size_t size, const void *)
       
   139 {
       
   140     ++mallocCount;
       
   141 
       
   142     if (mallocFailActive && --mallocFailIndex < 0)
       
   143         return 0; // simulate OOM
       
   144 
       
   145     __realloc_hook = old_realloc_hook;
       
   146     __malloc_hook = old_malloc_hook;
       
   147     void *result = ::realloc(ptr, size);
       
   148     __malloc_hook = my_malloc_hook;
       
   149     __realloc_hook = my_realloc_hook;
       
   150 
       
   151     return result;
       
   152 }
       
   153 
       
   154 void my_free_hook(void *ptr, const void *)
       
   155 {
       
   156     __free_hook = old_free_hook;
       
   157     ::free(ptr);
       
   158     __free_hook = my_free_hook;
       
   159 }
       
   160 
       
   161 #elif defined(Q_CC_MSVC)
       
   162 
       
   163 #include "crtdbg.h"
       
   164 
       
   165 static int qCrtAllocHook(int allocType, void * /*userData*/, size_t /*size*/,
       
   166                          int blockType, long /*requestNumber*/,
       
   167                          const unsigned char * /*filename*/, int /*lineNumber*/)
       
   168 {
       
   169     if (blockType == _CRT_BLOCK)
       
   170         return TRUE; // ignore allocations from the C library
       
   171 
       
   172     switch (allocType) {
       
   173         case _HOOK_ALLOC:
       
   174         case _HOOK_REALLOC:
       
   175             ++mallocCount;
       
   176             if (mallocFailActive && --mallocFailIndex < 0)
       
   177                 return FALSE; // simulate OOM
       
   178     }
       
   179 
       
   180     return TRUE;
       
   181 }
       
   182 
       
   183 static struct QCrtDebugRegistrator
       
   184 {
       
   185     QCrtDebugRegistrator()
       
   186     {
       
   187         _CrtSetAllocHook(qCrtAllocHook);
       
   188     }
       
   189 
       
   190 } crtDebugRegistrator;
       
   191 
       
   192 #elif defined(Q_OS_SYMBIAN)
       
   193 
       
   194 struct QAllocFailAllocator : public RAllocator
       
   195 {
       
   196     QAllocFailAllocator() : allocator(User::Allocator())
       
   197     {
       
   198         User::SwitchAllocator(this);
       
   199     }
       
   200 
       
   201     ~QAllocFailAllocator()
       
   202     {
       
   203         User::SwitchAllocator(&allocator);
       
   204     }
       
   205 
       
   206     RAllocator& allocator;
       
   207 
       
   208     // from MAllocator
       
   209     TAny* Alloc(TInt aSize)
       
   210     {
       
   211         ++mallocCount;
       
   212         if (mallocFailActive && --mallocFailIndex < 0)
       
   213             return 0; // simulate OOM
       
   214         return allocator.Alloc(aSize);
       
   215     }
       
   216 
       
   217     void Free(TAny* aPtr)
       
   218     {
       
   219         allocator.Free(aPtr);
       
   220     }
       
   221 
       
   222     TAny* ReAlloc(TAny* aPtr, TInt aSize, TInt aMode)
       
   223     {
       
   224         ++mallocCount;
       
   225         if (mallocFailActive && --mallocFailIndex < 0)
       
   226             return 0; // simulate OOM
       
   227         return allocator.ReAlloc(aPtr, aSize, aMode);
       
   228     }
       
   229 
       
   230     TInt AllocLen(const TAny* aCell) const
       
   231     {
       
   232         return allocator.AllocLen(aCell);
       
   233     }
       
   234 
       
   235     TInt Compress()
       
   236     {
       
   237         return allocator.Compress();
       
   238     }
       
   239 
       
   240     void Reset()
       
   241     {
       
   242         allocator.Reset();
       
   243     }
       
   244 
       
   245     TInt AllocSize(TInt& aTotalAllocSize) const
       
   246     {
       
   247         return allocator.AllocSize(aTotalAllocSize);
       
   248     }
       
   249 
       
   250     TInt Available(TInt& aBiggestBlock) const
       
   251     {
       
   252         return allocator.Available(aBiggestBlock);
       
   253     }
       
   254 
       
   255     TInt DebugFunction(TInt aFunc, TAny* a1, TAny* a2)
       
   256     {
       
   257         return allocator.DebugFunction(aFunc, a1, a2);
       
   258     }
       
   259 
       
   260     TInt Extension_(TUint aExtensionId, TAny*& a0, TAny* a1)
       
   261     {
       
   262         return ((MAllocator&)allocator).Extension_(aExtensionId, a0, a1);
       
   263     }
       
   264 };
       
   265 
       
   266 QAllocFailAllocator symbianTestAllocator;
       
   267 
       
   268 #endif
       
   269 
       
   270 struct AllocFailer
       
   271 {
       
   272     inline AllocFailer(int index) { reactivateAt(index); }
       
   273     inline ~AllocFailer() { deactivate(); }
       
   274 
       
   275     inline void reactivateAt(int index)
       
   276     {
       
   277 #ifdef RUNNING_ON_VALGRIND
       
   278         if (RUNNING_ON_VALGRIND)
       
   279             VALGRIND_ENABLE_OOM_AT_ALLOC_INDEX(VALGRIND_GET_ALLOC_INDEX + index + 1);
       
   280 #endif
       
   281         mallocFailIndex = index;
       
   282         mallocFailActive = true;
       
   283     }
       
   284 
       
   285     inline void deactivate()
       
   286     {
       
   287         mallocFailActive = false;
       
   288 #ifdef RUNNING_ON_VALGRIND
       
   289         VALGRIND_ENABLE_OOM_AT_ALLOC_INDEX(0);
       
   290 #endif
       
   291     }
       
   292 
       
   293     inline int currentAllocIndex() const
       
   294     {
       
   295 #ifdef RUNNING_ON_VALGRIND
       
   296         if (RUNNING_ON_VALGRIND)
       
   297             return VALGRIND_GET_ALLOC_INDEX;
       
   298 #endif
       
   299         return mallocCount;
       
   300     }
       
   301 
       
   302     static bool initialize()
       
   303     {
       
   304         std::set_terminate(my_terminate_handler);
       
   305 #ifdef RUNNING_ON_VALGRIND
       
   306         if (RUNNING_ON_VALGRIND) {
       
   307             if (VALGRIND_GET_ALLOC_INDEX == -1u) {
       
   308                 qWarning("You must use a valgrind with oom simulation support");
       
   309                 return false;
       
   310             }
       
   311             // running in valgrind - don't use glibc hooks
       
   312             disableHooks();
       
   313 
       
   314             // never stop simulating OOM
       
   315             VALGRIND_DISABLE_OOM_AT_ALLOC_INDEX(-1u);
       
   316         }
       
   317 #endif
       
   318          return true;
       
   319     }
       
   320 };
       
   321 
       
   322 #ifndef Q_OS_SYMBIAN
       
   323 
       
   324 static void *new_helper(std::size_t size)
       
   325 {
       
   326     void *ptr = malloc(size);
       
   327     if (!ptr)
       
   328         throw std::bad_alloc();
       
   329     return ptr;
       
   330 }
       
   331 
       
   332 #ifdef Q_CC_MSVC
       
   333 #  pragma warning(push)
       
   334 #  pragma warning(disable: 4290)
       
   335 #endif
       
   336 
       
   337 // overload operator new
       
   338 void* operator new(size_t size) throw (std::bad_alloc) { return new_helper(size); }
       
   339 void* operator new[](size_t size) throw (std::bad_alloc) { return new_helper(size); }
       
   340 void* operator new(size_t size, const std::nothrow_t&) throw() { return malloc(size); }
       
   341 void* operator new[](std::size_t size, const std::nothrow_t&) throw() { return malloc(size); }
       
   342 
       
   343 // overload operator delete
       
   344 void operator delete(void *ptr) throw() { if (ptr) free(ptr); }
       
   345 void operator delete[](void *ptr) throw() { if (ptr) free(ptr); }
       
   346 void operator delete(void *ptr, const std::nothrow_t&) throw() { if (ptr) free(ptr); }
       
   347 void operator delete[](void *ptr, const std::nothrow_t&) throw() { if (ptr) free (ptr); }
       
   348 
       
   349 #ifdef Q_CC_MSVC
       
   350 #  pragma warning(pop)
       
   351 #endif
       
   352 
       
   353 #endif
       
   354 
       
   355 // ignore placement new and placement delete - those don't allocate.
       
   356 
       
   357