-
Notifications
You must be signed in to change notification settings - Fork 160
/
brk.c
123 lines (100 loc) · 3.27 KB
/
brk.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
/*
# brk
# sbrk
https://stackoverflow.com/questions/6988487/what-does-brk-system-call-do/31082353#31082353
Was in POSIX 2001, but got removed.
You must have in your mind:
---> brk
|
| Heap. Grows up ^^^
|
---> brk_start
|
| brk random offset ASLR
|
---> bss end
Get and set the break data segment (TODO is it really the data semgment? what about the brk offset?)
that the kernel assigns to the process.
Set it to an absolute value, and return -1 on failure, 0 on success:
int brk(void*)
Move it by the given delta, and return the *old* value on success, `-1` on failure:
void *sbrk(intptr_t increment);
This is where the heap lives: `malloc` may use those system calls to do its job,
although it can also use `mmap`.
Once the `brk` is changed,
the application can then use the newly allocated memory as it pleases,
and the Kernel must treat that zone as being used and preserve it.
The kernel may just say: you are taking up too much memory,
or "this would overlap with another memory regions", and deny the request.
# Get heap size
- http://stackoverflow.com/questions/8367001/how-to-check-heap-size-for-a-process-on-linux
- http://stackoverflow.com/questions/2354507/how-to-find-size-of-heap-present-in-linux
More precisely, how to get the `brk_start`?
*/
#include "common.h"
int main(void) {
/* Get the top of the heap. */
{
void *b = sbrk(0);
printf("sbrk(0) = %p\n", b);
}
/* Allocate 2 characters on the heap. */
{
/* With sbrk. */
{
size_t size = 2 * sizeof(char);
void *b = sbrk(size);
if (b != (void*)-1) {
/* Now we safely use s2 an s2 + 1 to store what we want. */
char *p = (char *)b;
*p = (char)1;
*(p + 1) = (char)2;
assert(*p == (char)1);
assert(*(p + 1) == (char)2);
/* Restore it back. This is more convenient with brk. */
if (sbrk(-size) == (void*)-1) {
perror("sbrk");
exit(EXIT_FAILURE);
}
} else {
perror("sbrk");
}
}
/*
With brk.
The initial allocation is more convenient with sbrk,
since we need an initial sbrk anyways to find the current break.
*/
{
size_t size = 2 * sizeof(char);
void *b = sbrk(0);
char *p = (char *)b;
if (brk(p + size) == 0) {
*p = (char)1;
*(p + 1) = (char)2;
assert(*p == (char)1);
assert(*(p + 1) == (char)2);
if (brk(b)) {
perror("brk");
exit(EXIT_FAILURE);
}
} else {
perror("brk");
}
}
}
#if 0
/*
Attempting this without changing `brk` is an almost sure segfault:
unlike the stack, you can't just increment the heap directly,
Linux prevents you.
*/
{
void *b = sbrk(0);
char *p = (char *)b;
/* SEGFAULT */
*p = 1;
}
#endif
return EXIT_SUCCESS;
}