1
/****************************************************************************
2
**
3
** Copyright (C) 2012 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
** GNU Lesser General Public License Usage
11
** This file may be used under the terms of the GNU Lesser General Public
12
** License version 2.1 as published by the Free Software Foundation and
13
** appearing in the file LICENSE.LGPL included in the packaging of this
14
** file. Please review the following information to ensure the GNU Lesser
15
** General Public License version 2.1 requirements will be met:
16
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17
**
18
** In addition, as a special exception, Nokia gives you certain additional
19
** rights. These rights are described in the Nokia Qt LGPL Exception
20
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21
**
22
** GNU General Public License Usage
23
** Alternatively, this file may be used under the terms of the GNU General
24
** Public License version 3.0 as published by the Free Software Foundation
25
** and appearing in the file LICENSE.GPL included in the packaging of this
26
** file. Please review the following information to ensure the GNU General
27
** Public License version 3.0 requirements will be met:
28
** http://www.gnu.org/copyleft/gpl.html.
29
**
30
** Other Usage
31
** Alternatively, this file may be used in accordance with the terms and
32
** conditions contained in a signed written agreement between you and Nokia.
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.