Maximum virtual memory allocation for a thread in RHEL6 - c

As RHEL6 introduced a new arena allocator design because of the same number of arena’s are increased for a single thread which is resulting into more virtual memory usage.
RHEL6 is allocating separate chunks of memory for each thread. Number of Arena per thread are calculated as below as per my understanding on 32/64 bit system:
On 32 Bit system :
Number of Arena = 2 * Number of cores .
On 64 Bit system :
Number of Arena = 8 * Number of cores .
Please validate if my understanding have some gap.
My machine has 4 cores and 64 bit system,
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 69
Stepping: 1
CPU MHz: 759.000
BogoMIPS: 4589.41
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 3072K
NUMA node0 CPU(s): 0-3
$ uname -a
Linux admin 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
So it has 4*8=32 Arena's per thread. Each arena has a maximum size of 64MB; pet thread virtual memory can be reached to 32*64=2GB(per thread).
Please let me know if my understanding is correct.
I have created a sample program. It is allocated 1.5 GB of heap memory.
#include <pthread.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <unistd.h>
static void *thread(void *arg)
{
int i=0;
char *x[1024];
unsigned int pid;
char str[15];
char cmd[30]="cat /proc/";
pid = getpid();
sprintf(str, "%d", pid);
strcat(cmd,str);
strcat(cmd,"/status");
system(cmd);
for(i=0;i<1536;i++)
{
x[i] = malloc(1*1024*1024);
printf("Memory Allocated %d:\n ",i);
system(cmd);
}
for(i=0;i<1536;i++)
{
*x[i] = 5;
free(x[i]);
}
return NULL;
}
int main(void)
{
unsigned i;
pthread_t t;
pthread_create(&t, NULL, thread, NULL);
pthread_join(t, NULL);
return 0;
}
thread t is heap memory allocation is lesser than 2GB. but it generates the coredump after allocating 1GB approx. For more detail please refer the below detail:
Name: arena
State: S (sleeping)
Tgid: 12511
Ngid: 0
Pid: 12511
PPid: 4417
TracerPid: 0
Uid: 1000 1000 1000 1000
Gid: 1000 1000 1000 1000
FDSize: 256
Groups: 4 24 27 30 46 108 124 129 1000
VmPeak: 1133924 kB
VmSize: 1133924 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 4568 kB
VmRSS: 4568 kB
VmData: 1127636 kB
VmStk: 136 kB
VmExe: 4 kB
VmLib: 2012 kB
VmPTE: 2092 kB
VmSwap: 0 kB
Threads: 2
SigQ: 0/46560
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000006
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000001fffffffff
Seccomp: 0
Cpus_allowed: ff
Cpus_allowed_list: 0-7
Mems_allowed: 00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1027
nonvoluntary_ctxt_switches: 4
Why the coredump generated? is my above understanding is incorrect to calculate the thread maximum virtual memory?
Also what are the consequences happened if virtual memory maximum limit reached
Please note I have set ulimit to unlimited
$ ulimit
unlimited

Why the coredump generated?
You have
char *x[1024];
…
for(i=0;i<1536;i++)
{
x[i] = malloc(1*1024*1024);
- a plain case of array overflow.

Memory allocation generally isn't specific to any distribution. Typically, the allocator is the glibc implementation. However, the amount of memory a thread can allocate should be a function of the kernel, not the allocator. Some of the reasons you wouldn't be able to allocate memory might include exhausting physical memory, exhausting swap memory, ulimit, cgroups, etc...
If you still suspect the allocator though, you can try using mmap to directly map the memory into the process.

Related

Why does this very small C program use up so much memory?

int i = 0;
int main(){
while (true){
i = 1;
}
return 0;
}
The above program, (compiled with gnu g++, no extra compiler flags) which just loops forever, seems to use up more memory than it should (output of top shown below):
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
9392 root 20 0 4376 788 728 R 100.0 0.0 2:32.65 a.out
I get why the CPU usage is 100%, since it is constantly spinning in the while loop. Why is VIRT sitting at 4MB? Why is SHR sitting at 728KB? I am using no libraries. Finally, and most importantly, why the usage of 788KB to store just one variable? And where/how is the remaining (4376-788)KB being stored/used?
Why is VIRT sitting at 4MB? Why is SHR sitting at 728kB? I am using no libraries.
That is not accurate.
Let's compile:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
char buf[100];
snprintf(buf, sizeof buf, "pmap -x %u", (unsigned)getpid());
system(buf);
}
With command gcc -o test -W{all,extra,error} -xc test.cc.
And run it:
$ ./test
7360: ./test
Address Kbytes RSS Dirty Mode Mapping
0000000000400000 4 4 4 r-x-- test
0000000000600000 4 4 4 rw--- test
00007f1f4d96a000 1580 788 0 r-x-- libc-2.12.so
00007f1f4daf5000 2044 0 0 ----- libc-2.12.so
00007f1f4dcf4000 16 16 16 r---- libc-2.12.so
00007f1f4dcf8000 8 8 8 rw--- libc-2.12.so
00007f1f4dcfa000 16 8 8 rw--- [ anon ]
00007f1f4dcfe000 128 128 0 r-x-- ld-2.12.so
00007f1f4df0c000 12 12 12 rw--- [ anon ]
00007f1f4df1d000 4 4 4 rw--- [ anon ]
00007f1f4df1e000 4 4 4 r---- ld-2.12.so
00007f1f4df1f000 4 4 4 rw--- ld-2.12.so
00007f1f4df20000 4 4 4 rw--- [ anon ]
00007ffd4a872000 132 12 12 rw--- [ stack ]
00007ffd4a961000 12 0 0 r---- [ anon ]
00007ffd4a964000 8 4 0 r-x-- [ anon ]
ffffffffff600000 4 0 0 r-x-- [ anon ]
---------------- ------ ------ ------
total kB 3984 1000 80
(If you see duplicate lines in pmap -x output, this was a bug in older versions).
It loads:
test - the executable.
libc.so - C standard library.
ld.so - the dynamic linker.
The shared libraries are loaded into the virtual address space of the process at addresses below the address space reserved for thread stacks, each next library loads at a lower address. ld.so normally loads first.
The 1000kB of RSS are occupied by:
920kB is executable code of your executable (4kB) and the shared libraries (pages with r-x-- mode)
12kB is stack (marked as [ stack ]).
Pages marked as [ anon ] with rw--- mode are heap and 0-initialized data with static storage duration from .bss sections of the executable and shared libraries.
The rest is read-only and non-0-initialized data with static storage duration from .data and .rodata (r---- mode) sections of the executable and shared libraries.
Most of the memory overhead that surprises you comes from the C library and the dynamic linker, which will be fully loaded into memory even though you aren't using them ... much. (You are using them for a glob of code that runs before main, which many people don't realize exists, but it's there. It's responsible for things like setting up stdio, running C++ global constructors, and arranging for it to be possible to return from main without crashing.)
For comparison, this is just about the smallest busy-wait program you can have on Linux/x86 without hand-hacking the ELF file format:
$ cat tiny.s
.text
.globl _start
.type _start,#function
_start:
pause
jmp _start
.size _start, .-_start
.section .note.GNU-stack,"",#progbits
I've written it in assembly language so I can chop out all of the overhead associated with the C library. In order to exclude the code that runs before main, I have to name my program's "main function" _start instead. Compile thus:
$ gcc -nostdlib -nostartfiles -static -Wl,--build-id=none -o tiny tiny.s
-nostdlib to turn off most of the C library, -nostartfiles to turn off the code that runs before main, -static so it won't even pull in the dynamic linker, and -Wl,--build-id=none to suppress an annotation that makes the executable significantly bigger on disk. Here's what that gets us:
$ objdump -dr tiny
tiny: file format elf64-x86-64
Disassembly of section .text:
0000000000401000 <_start>:
401000: f3 90 pause
401002: eb fc jmp 401000 <_start>
$ size tiny
text data bss dec hex filename
4 0 0 4 4 a.out
$ ls -l tiny
-rwxr-xr-x 1 zack zack 4632 Nov 27 10:53 tiny
Four bytes of actual machine instructions. They get enlarged to slightly more than 4k of complete executable file with more padding and annotations. You can use the objdump and readelf commands to poke through the file and see what-all is in there.
Here's how it shows up in top:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
12154 zack 20 0 156 4 0 R 100.0 0.0 0:16.51 a.out
This still allocates 156kB¹ of address space and 4kB of actual RAM. To find out in more detail what this space is going to, we can look at /proc/<pid>/maps for the process: (note, the output on your system may differ a little)
$ cat /proc/12514/maps
000000400000-000000401000 r--p 00000000 fd:01 26477890 /home/zack/tiny
000000401000-000000402000 r-xp 00001000 fd:01 26477890 /home/zack/tiny
7fff5c9b3000-7fff5c9d4000 rw-p 00000000 00:00 0 [stack]
7fff5c9fb000-7fff5c9fe000 r--p 00000000 00:00 0 [vvar]
7fff5c9fe000-7fff5c9ff000 r-xp 00000000 00:00 0 [vdso]
There are five virtual memory allocations, with the first two numbers on each line being their starting and ending addresses, respectively. The first 0x1000 bytes (4kB) of the executable file have been mapped read-only, and the second 4kB of the executable file have been mapped read-execute. (Yes, this means the file is shorter than its memory map. The kernel will fill in the gap with zeroes.) Then we have
0x7fff5c9d4000 − 0x7fff5c9b3000 = 132kB allocated to the stack, 12kB allocated to "vvar", and 4kB allocated to "vdso". 8 + 132 + 12 + 4 = 156kB.
An interesting fact visible here: top's RES counts only pages that have been committed to the current process. In this case, that's one page of the stack allocation. The 8kB of mappings from the executable file are not counted, because they are read-only, shareable, and discardable -- if you had many processes running this same program, they would all share the same copy of the program code in physical RAM, and if the kernel needs to kick those pages out of RAM to make room for something else, it doesn't have to write them to the swap file. (The top manpage says something different about RES, but as far as I can tell, it's wrong.)
The "vvar" and "vdso" mappings are small globs of data and code, respectively, provided to all user space processes on Linux by the kernel. They are for low-level tricks like making it possible to do a gettimeofday without actually switching the CPU into kernel mode. This cuts out several thousand cycles of overhead, which matters for accurate timekeeping. As far as I know, there's no way to turn these off.
You can reduce the size of the stack allocation with the ulimit command. For instance, ulimit -s 4 cuts it to the absolute minimum, 4kB. If I run my program like this
$ (unset $(printenv | cut -d= -f1); ulimit -s 4; exec ./tiny)
then top reports
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14293 zack 20 0 28 4 0 R 100.0 0.0 0:06.02 tiny
and the stack line in /proc/14293/maps reads
7ffdf80e5000-7ffdf80e6000 rw-p 00000000 00:00 0 [stack]
But without that initial unset command (which clears all the environment variables), the program crashes on startup:
$ (ulimit -s 4; exec ./tiny)
Segmentation fault
This is because the kernel writes a bunch of data into the stack allocation -- the command-line argument vector, all the environment variables, and the ELF auxiliary vector -- before it starts the program running. If I don't clear the environment variables, that data takes up more than 4kB of space and the program crashes. I bet you didn't know it was possible to trigger a segfault inside the execve system call.
¹ Proper, binary kilobytes, that is: 1kB ≝ 1024 bytes. Do not listen to anyone who tells you different, not even the International Bureau of Weights and Measures.

Using fallocate() after shm_open() results in memory not being freed after shm_unlink()

I have an application that uses shared memory with memory mapped files. The target operating system is Ubuntu 14.04 (64-bit). The Linux kernel on this distro is at version 4.4.0. gcc is at version 4.8.4.
Until recently I was using the following function calls (in the shown order) to allocate and deallocate the shared memory.
shm_open
ftruncate
mmap
/* use shared memory */
munmap
shm_unlink
This approach has the problem that it does not detect if there is enough memory available for the shared memory. The application will crash at a later point with a SIGBUS signal when the shared memory is accessed.
I have found people had the same issue here and they solved it by using fallocate() instead of ftruncate(). fallocate() will return an error if there is not enough memory available for the requested size.
I have implemented the same in my application and fallocate() can properly detect the situation when not enough memory is available However, I am now running into a different problem.
The problem is that the memory reserved by fallocate() is not freed after calling shm_unlink(). This was not an issue when using ftruncate().
Consider the following minimal example (fallocate.c) that exhibit this behavior.
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <fcntl.h>
static const char* name = "/test";
static const size_t size = (size_t)4*1024*1024*1024;
int main ()
{
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO);
if (fd == -1) {
printf("shm_open failed (%s)\n", strerror(errno));
return 1;
}
if (fallocate(fd, 0, 0, size)) {
printf("fallocate failed (%s)\n", strerror(errno));
return 1;
}
if (shm_unlink(name)) {
printf("shm_unlink failed (%s)\n", strerror(errno));
return 1;
}
printf("break here to check if memory still used\n");
return 0;
}
I used the following CMakeLists.txt for compiling
add_executable(fallocate fallocate.c)
target_compile_definitions(fallocate PRIVATE _GNU_SOURCE)
target_link_libraries(fallocate PRIVATE rt)
Run this example in gdb and break on the last printf statement. You will see the following behavior.
The test file is no longer present in /dev/shm
The memory is still in the "used" category when looking at the top output; it will only move to the "free" category once the process terminates
Is this expected behavior or am I using the API wrongly?
Edit: as requested the process address space after shm_unlink() (using gets() after shm_unlink() to hold the process)
Output of cat /proc/<PID>/status
Name: fallocate
State: S (sleeping)
Tgid: 12445
Ngid: 0
Pid: 12445
PPid: 26349
TracerPid: 0
Uid: 1001 1001 1001 1001
Gid: 1001 1001 1001 1001
FDSize: 256
Groups: 4 27 108 124 999 1001 1002
NStgid: 12445
NSpid: 12445
NSpgid: 12445
NSsid: 26349
VmPeak: 8628 kB
VmSize: 8460 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 840 kB
VmRSS: 840 kB
VmData: 80 kB
VmStk: 132 kB
VmExe: 4 kB
VmLib: 2052 kB
VmPTE: 36 kB
VmPMD: 12 kB
VmSwap: 0 kB
HugetlbPages: 0 kB
Threads: 1
SigQ: 0/61795
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000180000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: ff
Cpus_allowed_list: 0-7
Mems_allowed: 00000000,00000001
Mems_allowed_list: 0
voluntary_ctxt_switches: 1
nonvoluntary_ctxt_switches: 2
Output of pmap <PID>
0000000000400000 4K r-x-- fallocate
0000000000600000 4K r---- fallocate
0000000000601000 4K rw--- fallocate
00007f1e92093000 100K r-x-- libpthread-2.19.so
00007f1e920ac000 2044K ----- libpthread-2.19.so
00007f1e922ab000 4K r---- libpthread-2.19.so
00007f1e922ac000 4K rw--- libpthread-2.19.so
00007f1e922ad000 16K rw--- [ anon ]
00007f1e922b1000 1784K r-x-- libc-2.19.so
00007f1e9246f000 2048K ----- libc-2.19.so
00007f1e9266f000 16K r---- libc-2.19.so
00007f1e92673000 8K rw--- libc-2.19.so
00007f1e92675000 20K rw--- [ anon ]
00007f1e9267a000 28K r-x-- librt-2.19.so
00007f1e92681000 2044K ----- librt-2.19.so
00007f1e92880000 4K r---- librt-2.19.so
00007f1e92881000 4K rw--- librt-2.19.so
00007f1e92882000 140K r-x-- ld-2.19.so
00007f1e92a75000 16K rw--- [ anon ]
00007f1e92aa3000 4K rw--- [ anon ]
00007f1e92aa4000 4K r---- ld-2.19.so
00007f1e92aa5000 4K rw--- ld-2.19.so
00007f1e92aa6000 4K rw--- [ anon ]
00007ffe6f72b000 132K rw--- [ stack ]
00007ffe6f7ee000 12K r---- [ anon ]
00007ffe6f7f1000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 8464K
You're not closing the open file descriptor, and the shared-memory "file" is likely in a tmpfs-memory based filesystem (assuming Linux).
This code creates a file:
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, S_IRWXU | S_IRWXG | S_IRWXO);
This code makes it big (4 GB):
if (fallocate(fd, 0, 0, size)) {
This code just unlinks it from the filesystem:
if (shm_unlink(name)) {
At that point, the open file descriptor means the backing file still exists even though it's been removed from the directory with its name. (That's literally what "unlink" means.) Such a file will not be actually removed from the filesystem until the last link to the file is closed - and that last link is your process's open file descriptor.
Add
close( fd );
and check system memory usage before and after the close() call.
shm_unlink only removes the name associated with a memory object. It won't delete the object if there are other things referencing it. You have an open file descriptor referencing the memory object. After you close it, the refcount should reach zero, and the memory should be deallocated.

How to write() data more than 2G in a time

I have already defined _LARGEFILE64_SOURCE and _FILE_OFFSET_BITS 64
to support open() file that more than 2G. That seems to be all right.
But if I try to write() data more than 2G at a time ( such as 64G ), write() will return a value much smaller than 64G (Exactly 2147479552). I guess that write() only can write data smaller than 2G in a time.
Here is my code:
#define _GNU_SOURCE
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <mmap.h>
#define SPACE_SIZE 68719476736
int main()
{
ssize_t err;
void* zeros;
int fd = open64("./test", O_CREAT|O_RDWR|O_LARGEFILE, 0644);
assert(fd != -1);
int zero_fd = open("/dev/zero", O_RDWR);
assert(zero_fd != -1);
zeros = mmap(NULL, SPACE_SIZE, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, zero_fd, 0);
assert(zeros != (void *)-1);
err = write(fd, zeros, SPACE_SIZE);
assert(err == SPACE_SIZE); // Received SIGABRT, err = 2147479552
munmap(zeros, SPACE_SIZE);
}
How to write() data more than 2G in a time?
Supplementary info:
The result of readelf -h ./a.out. a.out is my program's name
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x660
Start of program headers: 64 (bytes into file)
Start of section headers: 6672 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 29
Section header string table index: 28
Indeed, and this fact is well documented in man write:
On Linux, write() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually transferred. (This is true on both 32-bit and 64-bit systems.)
So if you're using Linux, there is no way to write 64GB in a single call to write().
You can, however, create a file which appears to contain 64GB of NUL bytes by seeking to offset 64GB-1 and writing a single NUL byte. (Or, as #o11c points out in a comment, you could use ftruncate(fd, SPACE_SIZE);.) Either of those will create a sparse file which will not actually occupy much disk space, but it will act as though it were 64GB of NULs.

Add to an array of structs using mmap

I would like to dispatch some tasks out via fork, and collect some information about the results of those tasks in an array.
My thought is to use mmap to share a data structure between the two, and have the child process update the array of structs with the result of the activity, but i'm having some issues.
#include <time.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/mman.h>
#include <stdlib.h>
typedef struct message_s {
int status;
char message[256];
} message_t;
void child(message_t **result) {
result[0]->status = 2;
sprintf((char *) &result[0]->message, "Hello World!");
usleep(1);
}
void parent() {
printf("Parent\n");
usleep(1);
return;
}
int main() {
size_t result_size = 1000 * sizeof(message_t);
message_t **result_ar = mmap(NULL, result_size,
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANON, -1, 0);
pid_t child_pid = fork();
switch (child_pid) {
case 0:
child(result_ar);
exit(0);
case -1:
exit(-1);
break;
default:
parent();
}
int child_status;
waitpid(child_pid, &child_status, 0);
printf("\nRESULT: %i: %s\n\n", result_ar[0]->status, result_ar[0]->message);
msync(result_ar, result_size, MS_SYNC);
munmap(result_ar, result_size);
return 0;
}
I'm really sort of lost here, and while i can find "similar" questions on SO, they either do not have answers or are plagued with other issues, or both.
When the code above runs, i get the following concatenated result.
Process: concurrent_test [2537]
Path: /Users/USER/Library/Caches/*/concurrent_test
Identifier: concurrent_test
Version: 0
Code Type: X86-64 (Native)
OS Version: Mac OS X 10.10.5 (14F1509)
Report Version: 11
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
VM Regions Near 0:
-->
__TEXT 000000010144a000-000000010144c000 [ 8K] r-x/rwx SM=COW /Users/USER/Library/Caches/*
Application Specific Information:
crashed on child side of fork pre-exec
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 concurrent_test 0x000000010144bb33 child + 35
1 concurrent_test 0x000000010144bc1f main + 127
2 concurrent_test 0x000000010144b5a9 _start + 247
3 concurrent_test 0x000000010144b4b1 start + 33
Thread 0 crashed with X86 Thread State (64-bit):
rax: 0x0000000000000000 rbx: 0x00007fff5e7b5908 rcx: 0x000000010144beb3 rdx: 0xffffffffffffffff
rdi: 0x0000000000000000 rsi: 0x0000000000000000 rbp: 0x00007fff5e7b5730 rsp: 0x00007fff5e7b5720
r8: 0x0000000000000303 r9: 0x0000000000000000 r10: 0x0000000000000030 r11: 0x0000000000000206
r12: 0x00007fff5e7b57e0 r13: 0x0000000000000000 r14: 0x00007fff5e7b57f0 r15: 0x0000000000000001
rip: 0x000000010144bb33 rfl: 0x0000000000010246 cr2: 0x0000000000000000
Logical CPU: 6
Error Code: 0x00000006
Trap Number: 14
And I'm using:
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix
You have one indirection too much in your code. Try message_t *result_ar = mmap(...); and result[0].status = 2; to fix this issue. Also, don't forget the error checking! mmap() can fail.

Interesting binary dump of executable file

For some reason I made simple program in C to output binary representation of given input:
int main()
{
char c;
while(read(0,&c,1) > 0)
{
unsigned char cmp = 128;
while(cmp)
{
if(c & cmp)
write(1,"1",1);
else
write(1,"0",1);
cmp >>= 1;
}
}
return 0;
}
After compilation:
$ gcc bindump.c -o bindump
I made simple test to check if program is able to print binary:
$ cat bindump | ./bindump | fold -b100 | nl
Output is following: http://pastebin.com/u7SasKDJ
I suspected the output to look like random series of ones and zeroes. However, output partially seems to be quite more interesting. For example take a look at the output between line 171 and 357. I wonder why there are lots of zeros in compare to other sections of executable ?
My architecture is:
$ lscpu
Architecture: i686
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 4
On-line CPU(s) list: 0-3
Thread(s) per core: 2
Core(s) per socket: 2
Socket(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 28
Stepping: 10
CPU MHz: 1000.000
BogoMIPS: 3325.21
Virtualization: VT-x
L1d cache: 24K
L1i cache: 32K
L2 cache: 512K
When you compile a program into an executable on Linux (and a number of other unix systems), it is written in the ELF format. The ELF format has a number of sections, which you can examine with readelf or objdump:
readelf -a bindump | less
For example, section .text contains CPU instructions, .data global variables, .bss uninitialized global variables (it is actually empty in the ELF file itself, but is created in the main memory when the program is executed), .plt and .got which are jump tables, debugging information, etc.
Btw. it is much more convenient to examine the binary content of files with hexdump:
hexdump -C bindata | less
There you can see that starting with offset 0x850 (approx. line 171 in your dump) there is a lot of zeros, and you can also see the ASCII representation on the right.
Let us look at which sections correspond to the block of your interest between 0x850 and 0x1160 (the field Off – offset in the file is important here):
> readelf -a bindata
...
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
...
[28] .shstrtab STRTAB 00000000 00074c 000106 00 0 0 1
[29] .symtab SYMTAB 00000000 000d2c 000440 10 30 45 4
...
You can examine the content of an individual section with -x:
> readelf -x .symtab bindump | less
0x00000000 00000000 00000000 00000000 00000000 ................
0x00000010 00000000 34810408 00000000 03000100 ....4...........
0x00000020 00000000 48810408 00000000 03000200 ....H...........
0x00000030 00000000 68810408 00000000 03000300 ....h...........
0x00000040 00000000 8c810408 00000000 03000400 ................
0x00000050 00000000 b8810408 00000000 03000500 ................
0x00000060 00000000 d8810408 00000000 03000600 ................
You would see that there are many zeros. The section is composed of 18-byte values (= one line in the -x output) defining symbols. From readelf -a you can see that it has 68 entries, and first 27 of them (excl. the very first one) are of type SECTION:
Symbol table '.symtab' contains 68 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 00000000 0 NOTYPE LOCAL DEFAULT UND
1: 08048134 0 SECTION LOCAL DEFAULT 1
2: 08048148 0 SECTION LOCAL DEFAULT 2
3: 08048168 0 SECTION LOCAL DEFAULT 3
4: 0804818c 0 SECTION LOCAL DEFAULT 4
...
According to the specification (page 1-18), each entry has the following format:
typedef struct {
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
Without going into too much detail here, I think what matters here is that st_name and st_size are both zeros for these SECTION entries. Both are 32-bit numbers, which means lots of zeros in this particular section.
This is not really a programming question, but however...
A binary normally consists of different sections: code, data, debugging info, etc. Since these sections contents differ by type, I would pretty much expect them to look different.
I.e. the symbol table consists of address offsets in your binary. If I read your lspci correctly, you are on a 32-bit system. That means Each offset has four bytes, and given the size of your program, in most cases two of those bytes will be zero. And there are more effects like this.
You didn't strip your program, that means there's still lots of information (symbol table etc.) present in the binary. Try stripping the binary and have a look at it again.

Resources