Coverage Report

Created: 2026-03-31 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/tests/fuzz/custom_memory_manager.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright 2018 (c) Stefan Profanter, fortiss GmbH
6
 */
7
8
/**
9
 * This memory manager allows to manually reduce the available RAM.
10
 *
11
 * It keeps track of malloc and free calls and counts the available RAM.
12
 * If the requested memory allocation results in hitting the limit,
13
 * it will return NULL and prevent the new allocation.
14
 */
15
16
#include "custom_memory_manager.h"
17
#include <stdlib.h>
18
#include <stdio.h>
19
#include <stdint.h>
20
#include <limits.h>
21
22
#include <pthread.h>
23
24
pthread_mutex_t mutex;
25
26
struct UA_mm_entry {
27
    size_t size;
28
    void* address;
29
    struct UA_mm_entry *next;
30
    struct UA_mm_entry *prev;
31
};
32
33
unsigned long long totalMemorySize = 0;
34
unsigned long long memoryLimit = ULONG_MAX;
35
36
/* Head and Tail of the double linked list */
37
struct UA_mm_entry *address_map_first = NULL;
38
struct UA_mm_entry *address_map_last = NULL;
39
40
/**
41
 * Add address entry to the linked list after it was allocated.
42
 *
43
 * @param size Size of the allocated memory block
44
 * @param addr Address of the allocated memory block
45
 * @return 1 on success, 0 if it failed
46
 */
47
5.22M
static int addToMap(size_t size, void *addr) {
48
5.22M
    struct UA_mm_entry *newEntry = (struct UA_mm_entry*)malloc(sizeof(struct UA_mm_entry));
49
5.22M
    if(!newEntry) {
50
        //printf("MemoryManager: Could not allocate memory");
51
0
        return 0;
52
0
    }
53
5.22M
    newEntry->size = size;
54
5.22M
    newEntry->address = addr;
55
5.22M
    newEntry->next = NULL;
56
5.22M
    pthread_mutex_lock(&mutex);
57
5.22M
    newEntry->prev = address_map_last;
58
5.22M
    if(address_map_last)
59
5.22M
        address_map_last->next = newEntry;
60
5.22M
    address_map_last = newEntry;
61
5.22M
    totalMemorySize += size;
62
5.22M
    if(address_map_first == NULL)
63
4.68k
        address_map_first = newEntry;
64
5.22M
    pthread_mutex_unlock(&mutex);
65
    //printf("Total size (malloc): %lld And new address: %p Entry %p\n", totalMemorySize, addr, (void*)newEntry);
66
67
5.22M
    return 1;
68
5.22M
}
69
70
/**
71
 * Remove entry from the list before the memory block is freed.
72
 *
73
 * @param addr Address of the memory block which is freed.
74
 *
75
 * @return 1 on success, 0 if the memory block was not found in the list.
76
 */
77
15.4M
static int removeFromMap(void *addr) {
78
15.4M
    if(addr == NULL)
79
10.2M
        return 1;
80
81
5.22M
    pthread_mutex_lock(&mutex);
82
83
5.22M
    struct UA_mm_entry *e = address_map_last;
84
85
6.44G
    while (e) {
86
6.44G
        if(e->address == addr) {
87
5.22M
            if(e == address_map_first)
88
5.43k
                address_map_first = e->next;
89
5.22M
            if(e == address_map_last)
90
1.69M
                address_map_last = e->prev;
91
5.22M
            if(e->prev)
92
5.22M
                e->prev->next = e->next;
93
5.22M
            if(e->next)
94
3.53M
                e->next->prev = e->prev;
95
5.22M
            totalMemorySize -= e->size;
96
97
            //printf("Total size (free): %lld after addr %p and deleting %p\n", totalMemorySize, addr, (void*)e);
98
5.22M
            free(e);
99
5.22M
            pthread_mutex_unlock(&mutex);
100
5.22M
            return 1;
101
5.22M
        }
102
6.44G
        e = e->prev;
103
6.44G
    }
104
3
    pthread_mutex_unlock(&mutex);
105
    //printf("MemoryManager: Entry with address %p not found", addr);
106
3
    return 0;
107
5.22M
}
108
109
1.19M
static void *UA_memoryManager_malloc(size_t size) {
110
1.19M
    if(totalMemorySize + size > memoryLimit)
111
243
        return NULL;
112
1.19M
    void *addr = malloc(size);
113
1.19M
    if(!addr)
114
0
        return NULL;
115
1.19M
    addToMap(size, addr);
116
1.19M
    return addr;
117
1.19M
}
118
119
2.33M
static void *UA_memoryManager_calloc(size_t num, size_t size) {
120
2.33M
    if(totalMemorySize + (size * num) > memoryLimit)
121
2.65k
        return NULL;
122
2.33M
    void *addr = calloc(num, size);
123
2.33M
    if(!addr)
124
0
        return NULL;
125
2.33M
    addToMap(size*num, addr);
126
2.33M
    return addr;
127
2.33M
}
128
129
1.70M
static void *UA_memoryManager_realloc(void *ptr, size_t new_size) {
130
1.70M
    removeFromMap(ptr);
131
1.70M
    if(totalMemorySize + new_size > memoryLimit)
132
3
        return NULL;
133
1.70M
    void *addr = realloc(ptr, new_size);
134
1.70M
    if(!addr)
135
0
        return NULL;
136
1.70M
    addToMap(new_size, addr);
137
1.70M
    return addr;
138
139
1.70M
}
140
141
13.7M
static void UA_memoryManager_free(void* ptr) {
142
13.7M
    removeFromMap(ptr);
143
13.7M
    free(ptr);
144
13.7M
}
145
146
273
void UA_memoryManager_setLimit(unsigned long long newLimit) {
147
273
    memoryLimit = newLimit;
148
    //printf("MemoryManager: Setting memory limit to %lld\n", newLimit);
149
150
273
    UA_mallocSingleton = UA_memoryManager_malloc;
151
273
    UA_freeSingleton = UA_memoryManager_free;
152
273
    UA_callocSingleton = UA_memoryManager_calloc;
153
273
    UA_reallocSingleton = UA_memoryManager_realloc;
154
273
}
155
156
14.8k
int UA_memoryManager_setLimitFromLast4Bytes(const uint8_t *data, size_t size) {
157
14.8k
    UA_mallocSingleton = UA_memoryManager_malloc;
158
14.8k
    UA_freeSingleton = UA_memoryManager_free;
159
14.8k
    UA_callocSingleton = UA_memoryManager_calloc;
160
14.8k
    UA_reallocSingleton = UA_memoryManager_realloc;
161
14.8k
    if(size <4)
162
181
        return 0;
163
    // just cast the last 4 bytes to uint32
164
14.6k
    const uint32_t *newLimit = (const uint32_t*)(uintptr_t)&(data[size-4]);
165
14.6k
    uint32_t limit;
166
    // use memcopy to avoid asan complaining on misaligned memory
167
14.6k
    memcpy(&limit, newLimit, sizeof(uint32_t));
168
14.6k
    memoryLimit = limit;
169
14.6k
    return 1;
170
14.8k
}