-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
oominject.c
138 lines (110 loc) · 2.94 KB
/
oominject.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include "oomify.h"
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdlib.h>
#include <unistd.h>
static struct oomctl ctl;
__attribute__((constructor))
static void init_oominject(void) {
if (read(OOMCTL_FILENO, &ctl, sizeof(ctl)) != sizeof(ctl)) {
static const char message[] = "liboomify: Failed to read oomctl\n";
write(STDERR_FILENO, message, sizeof(message) - 1);
abort();
}
close(OOMCTL_FILENO);
// Don't pass OOMSTAT_FILENO to exec'd children
int flags = fcntl(OOMSTAT_FILENO, F_GETFD);
if (flags >= 0 && !(flags & FD_CLOEXEC)) {
fcntl(OOMSTAT_FILENO, F_SETFD, flags | FD_CLOEXEC);
}
// Don't apply oomify to any exec'd children
unsetenv("LD_PRELOAD");
}
static struct oomstat stats;
// glibc hook to free its own private allocations
void __libc_freeres(void);
__attribute__((destructor))
static void fini_oominject(void) {
__libc_freeres();
struct oomstat copy = stats;
if (write(OOMSTAT_FILENO, ©, sizeof(copy)) != sizeof(copy)) {
static const char message[] = "liboomify: Failed to write oomstat\n";
write(STDERR_FILENO, message, sizeof(message) - 1);
abort();
}
}
static bool should_inject(atomic_size_t *stat) {
atomic_fetch_add_explicit(stat, 1, memory_order_relaxed);
size_t n = atomic_fetch_add_explicit(&stats.total, 1, memory_order_seq_cst);
if (n == ctl.inject_at) {
if (ctl.stop) {
raise(SIGSTOP);
}
errno = ENOMEM;
return true;
} else if (ctl.inject_after && n >= ctl.inject_at) {
errno = ENOMEM;
return true;
} else {
return false;
}
}
void *__libc_malloc(size_t size);
void *__libc_calloc(size_t nmemb, size_t size);
void *__libc_realloc(void *ptr, size_t size);
void *__libc_memalign(size_t align, size_t size);
void __libc_free(void* ptr);
void *malloc(size_t size) {
if (should_inject(&stats.malloc)) {
return NULL;
}
return __libc_malloc(size);
}
void *calloc(size_t nmemb, size_t size) {
if (should_inject(&stats.calloc)) {
return NULL;
}
return __libc_calloc(nmemb, size);
}
void *realloc(void *ptr, size_t size) {
if (should_inject(ptr ? &stats.realloc_ptr : &stats.realloc_null)) {
return NULL;
}
return __libc_realloc(ptr, size);
}
void *aligned_alloc(size_t align, size_t size) {
if (should_inject(&stats.aligned_alloc)) {
return NULL;
}
return __libc_memalign(align, size);
}
int posix_memalign(void **memptr, size_t align, size_t size) {
// posix_memalign() doesn't modify errno
int saved = errno;
if (should_inject(&stats.posix_memalign)) {
errno = saved;
return ENOMEM;
}
void *ptr = __libc_memalign(align, size);
int error = errno;
errno = saved;
if (ptr) {
*memptr = ptr;
return 0;
} else {
return error;
}
}
void *memalign(size_t align, size_t size) {
if (should_inject(&stats.memalign)) {
return NULL;
}
return __libc_memalign(align, size);
}
void free(void *ptr) {
atomic_fetch_add_explicit(ptr ? &stats.free_ptr : &stats.free_null, 1, memory_order_relaxed);
__libc_free(ptr);
}