Check amount of heap space by running a program; not matching with actual boundaries - c

I need to know the amount of heap space allocated for a process. In theory call malloc(1) (in C program) only once will get a start address of heap in my code. And call sbrk(0) a system call which return end of heap space allocated to that process. Below is my test code.
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#ifndef ALLOCATE_BYTES
#define ALLOCATE_BYTES 0x1000000
#endif /* #ifndef ALLOCATE_BYTES */
void subroutine (void);
int main()
{
void *init_ptr = malloc((size_t) 1);
void *end_ptr = sbrk((intptr_t) 0);
printf(" Total Heap space = %lld B = %lld kB \n",
(long long) (init_ptr - end_ptr),
(long long) (init_ptr - end_ptr)/1024);
subroutine();
end_ptr = sbrk((intptr_t) 0); /* New edit 1 */
printf(" Total Heap space = %lld B = %lld kB \n",
(long long) (init_ptr - end_ptr),
(long long) (init_ptr - end_ptr)/1024);
return 0;
}
void subroutine (void)
{
void *ptr;
long long count = 0;
size_t size = ALLOCATE_BYTES;
size_t size_p = ALLOCATE_BYTES + 1;
long long mem_alocated = 0;
printf(" start rate to %u \n", size);
while (1)
{
ptr = malloc((size_t)size);
if (ptr != NULL)
{
mem_alocated += size;
count++;
}
if ((ptr == NULL) && (size == size_p))
{
size/=2;
printf("overflow --> reduced Bytes SIZE %*u & "
"current count = %lld ---> total bytes %lld \n"
, 7, size, count, mem_alocated);
}
if ((ptr == NULL) && (size == 1))
{
printf("overflow....!! at %lld for %lld bytes\n",
count, count * ALLOCATE_BYTES);
break;
}
size_p = size;
}
}
The following is the results:
$ gcc -o exmpl_heap_consume exmpl_heap_consume.c -DALLOCATE_BYTES=0x10000
$ ./exmpl_heap_consume
Total Heap space = -135160 B = -131 kB
start rate to 65536
overflow --> reduced Bytes SIZE 32768 & current count = 48792 ---> total bytes 3197632512
overflow --> reduced Bytes SIZE 16384 & current count = 49084 ---> total bytes 3207200768
overflow --> reduced Bytes SIZE 8192 & current count = 49371 ---> total bytes 3211902976
overflow --> reduced Bytes SIZE 4096 & current count = 49658 ---> total bytes 3214254080
overflow --> reduced Bytes SIZE 2048 & current count = 49945 ---> total bytes 3215429632
overflow --> reduced Bytes SIZE 1024 & current count = 50233 ---> total bytes 3216019456
overflow --> reduced Bytes SIZE 512 & current count = 50521 ---> total bytes 3216314368
overflow --> reduced Bytes SIZE 256 & current count = 50809 ---> total bytes 3216461824
overflow --> reduced Bytes SIZE 128 & current count = 51098 ---> total bytes 3216535808
overflow --> reduced Bytes SIZE 64 & current count = 51100 ---> total bytes 3216536064
overflow --> reduced Bytes SIZE 32 & current count = 51100 ---> total bytes 3216536064
overflow --> reduced Bytes SIZE 16 & current count = 51387 ---> total bytes 3216545248
overflow --> reduced Bytes SIZE 8 & current count = 51389 ---> total bytes 3216545280
overflow --> reduced Bytes SIZE 4 & current count = 51676 ---> total bytes 3216547576
overflow --> reduced Bytes SIZE 2 & current count = 51676 ---> total bytes 3216547576
overflow --> reduced Bytes SIZE 1 & current count = 51676 ---> total bytes 3216547576
overflow....!! at 51676 for 3386638336 bytes
Total Heap space = -135160 B = -131 kB
This result says theoretical I have "135160 bytes" of memory locations for heap. But if I start consuming all of it till the repeated malloc() function call returns NULL. While doing so I keep track of how many bytes of memory my program has consumed now.
But here the question is my theoretical heap space (135160 bytes) is not matching with my practical counts (3386638336 bytes). Am I missing anything?
Edit 2:
I added some checks for the pointer return by the malloc() call and aggregated it to see the total. I observed the total bytes allocated is just less than the my theoretical heap space. This would suggest two things malloc() internally not calling sbrk() and secondly it is allocating memory elsewhere. Am I right till this point or anything missing here?

You've completely misunderstood brk/sbrk. sbrk(0) will tell the location of current program break, aka the end of data segment. When malloc runs out of space, it will call sbrk with a positive offset that will resize the data segment, thus moving the program break further. The Linux man page for sbrk clarifies this:
DESCRIPTION
brk() and sbrk() change the location of the program break, which
defines the end of the process's data segment (i.e., the program break
is the first location after the end of the uninitialized data seg‐
ment). Increasing the program break has the effect of allocating mem‐
ory to the process; decreasing the break deallocates memory.
brk() sets the end of the data segment to the value specified by addr,
when that value is reasonable, the system has enough memory, and the
process does not exceed its maximum data size (see setrlimit(2)).
sbrk() increments the program's data space by increment bytes. Call‐
ing sbrk() with an increment of 0 can be used to find the current
location of the program break.
(emphasis mine)
Furthermore usually on modern malloc implementations allocations of sufficient size (say >128kB) are allocated directly with mmap outside of the data segment. I'd test if the pointer returned from malloc(65536) even were between an address that is in the initialized data segment (do a global int foo = 42;, then &foo should be before the .bss/uninitialized data) and the current program break.

I think what you are not remembering is that your `practical count' is the available RAM on your system, which is used for multiple things. For example, I modified your program to:
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#ifndef ALLOCATE_BYTES
#define ALLOCATE_BYTES 0x1000000
#endif /* #ifndef ALLOCATE_BYTES */
int main()
{
void *init_ptr = malloc((size_t) 1);
void *end_ptr = sbrk((intptr_t) 0);
printf("\nmalloc returned: 0x%08x\n", (uint64_t)init_ptr);
printf("sbrk returned: 0x%08x\n", (uint64_t)end_ptr);
printf(" Total Heap space = %lld B = %lld kB \n",
(long long) (end_ptr - init_ptr),
(long long) (end_ptr - init_ptr)/1024);
sleep(300);
return 0;
}
I compiled the above using gcc (version 4.8.4) on Ubuntu 14.04 as: gcc -std=c11 -pedantic -Wall temp.c -o temp; then I ran the following commands at the command prompt:
******#crossbow:~/junk$ ./temp &
[2] 2069
******#crossbow:~/junk$
malloc returned: 0x01cac010
sbrk returned: 0x01ccd000
Total Heap space = 135152 B = 131 kB
******#crossbow:ps
PID TTY TIME CMD
1681 pts/0 00:00:00 bash
1775 pts/0 00:00:15 emacs
2069 pts/0 00:00:00 temp
2070 pts/0 00:00:00 ps
******#crossbow:~/junk$ cat /proc/2069/maps
00400000- 00401000 r-xp 00000000 fc:02 10616872 /home/******/junk/temp
00600000- 00601000 r--p 00000000 fc:02 10616872 /home/******/junk/temp
00601000- 00602000 rw-p 00001000 fc:02 10616872 /home/******/junk/temp
01cac000- 01ccd000 rw-p 00000000 00:00 0 [heap]
7f16a2e44000- 7f16a2fff000 r-xp 00000000 fc:02 70779581 /lib/x86_64-linux-gnu/libc-2.19.so
7f16a2fff000- 7f16a31fe000 ---p 001bb000 fc:02 70779581 /lib/x86_64-linux-gnu/libc-2.19.so
7f16a31fe000- 7f16a3202000 r--p 001ba000 fc:02 70779581 /lib/x86_64-linux-gnu/libc-2.19.so
7f16a3202000- 7f16a3204000 rw-p 001be000 fc:02 70779581 /lib/x86_64-linux-gnu/libc-2.19.so
7f16a3204000- 7f16a3209000 rw-p 00000000 00:00 0
7f16a3209000- 7f16a322c000 r-xp 00000000 fc:02 70779574 /lib/x86_64-linux-gnu/ld-2.19.so
7f16a3407000- 7f16a340a000 rw-p 00000000 00:00 0
7f16a3428000- 7f16a342b000 rw-p 00000000 00:00 0
7f16a342b000- 7f16a342c000 r--p 00022000 fc:02 70779574 /lib/x86_64-linux-gnu/ld-2.19.so
7f16a342c000- 7f16a342d000 rw-p 00023000 fc:02 70779574 /lib/x86_64-linux-gnu/ld-2.19.so
7f16a342d000- 7f16a342e000 rw-p 00000000 00:00 0
7ffcee9ab000- 7ffcee9cc000 rw-p 00000000 00:00 0 [stack]
7ffcee9ef000- 7ffcee9f1000 r-xp 00000000 00:00 0 [vdso]
7ffcee9f1000- 7ffcee9f3000 r--p 00000000 00:00 0 [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Now, from this you can see that currently the heap starts at 0x01cac000 and runs to 0x01ccd000. Notice, that malloc does not allocate memory starting from the beginning of the heap.
Also, notice, that the heap can grow upwards till it bumps into the area that dynamic libraries are loaded (in this case, this is at 0x7f16a2e44000).
From the memory map listing above, you can also see where the stack is located, if you have any interest in that, as well as where various parts of your program are loaded. You can determine what those blocks are by using the readelf utility, and you can see:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000040 0x0000000000400040 0x0000000000400040 0x0001f8 0x0001f8 R E 0x8
INTERP 0x000238 0x0000000000400238 0x0000000000400238 0x00001c 0x00001c R 0x1
[Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
LOAD 0x000000 0x0000000000400000 0x0000000000400000 0x0008d4 0x0008d4 R E 0x200000
LOAD 0x000e10 0x0000000000600e10 0x0000000000600e10 0x000248 0x000250 RW 0x200000
DYNAMIC 0x000e28 0x0000000000600e28 0x0000000000600e28 0x0001d0 0x0001d0 RW 0x8
NOTE 0x000254 0x0000000000400254 0x0000000000400254 0x000044 0x000044 R 0x4
GNU_EH_FRAME 0x0007a8 0x00000000004007a8 0x00000000004007a8 0x000034 0x000034 R 0x4
GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x10
GNU_RELRO 0x000e10 0x0000000000600e10 0x0000000000600e10 0x0001f0 0x0001f0 R 0x1
From looking at this, we can see that the area in memory from 0x00400000 to 0x00401000 is occupied by the contents of the file described by the second program header. This segment contains the following program sections: .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame. Probably the most important for you would be the .text section, which contains your code. In fact, the programs entry point is located at 0x00400520 (as determined by readelf -h).
Looking at the next area in memory from 0x00601000 to 0x00602000 and referring to the above, we can see that this corresponds to the section of the file described by the third program header. This segment contains the following program sections: .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss.

Related

Win32 WriteFile return 0 bytes as the number of byte written. lpBuffer contained 4455 bytes

I have the following code which creates two files. When the write operation for the last 4455 byte is invoked it returns 0 as the number of bytes written. Could this be due to the dwFlagAttributes of sequential scan and no buffering?
hIn = CreateFile (fIn, GENERIC_READ, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | SSF | NBF, NULL);
Desired Access: Generic Read
Disposition: Open
Options: Sequential Access, No Buffering, Synchronous IO Non-Alert, Non-Directory File
Attributes: N
ShareMode: None
AllocationSize: n/a
OpenResult: Opened
hOut = CreateFile (fOut, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | SSF | NBF, NULL);
Desired Access: Generic Write, Read Attributes
Disposition: OverwriteIf
Options: Sequential Access, No Buffering, Synchronous IO Non-Alert, Non-Directory File
Attributes: N
ShareMode: None
AllocationSize: 0
OpenResult: Created
After the files are created there is a while loop that reads file1. Then writes the bytes to file2. file1 is approximately 13MB.
while (ReadFile (hIn, aBuffer, BUF_SIZE, &nIn, NULL) && nIn > 0 && WriteOK) {
for (iCopy = 0; iCopy < nIn; iCopy++)
ccBuffer [iCopy] = (BYTE)((aBuffer [iCopy] + shift) % 256);
WriteOK = WriteFile (hOut, ccBuffer, nIn, &nOut, NULL);
}
From the disassembly below its evident that the last 4455 bytes are not being written to file2. Could this be due to the CreateFile dwFlagAttributes?
0:000> kb
# ChildEBP RetAddr Args to Child
00 0018bd00 00411612 00000038 0018bdf8 00001167 kernel32!WriteFile
01 0018fe64 0041144c 00273a99 00273ac9 0000000a cci!cci_f+0x162
02 0018ff44 00411bbb 00000004 00273a78 002723e8 cci!main+0x6c
03 0018ff88 7698336a 7efde000 0018ffd4 77c29f72 cci!__tmainCRTStartup+0x122
04 0018ff94 77c29f72 7efde000 76d02536 00000000 kernel32!BaseThreadInitThunk+0xe
05 0018ffd4 77c29f45 00411122 7efde000 00000000 ntdll!__RtlUserThreadStart+0x70
06 0018ffec 00000000 00411122 7efde000 00000000 ntdll!_RtlUserThreadStart+0x1b
0:000> dd 0018bd00 la
0018bd00 0018fe64 00411612 00000038 0018bdf8
0018bd10 00001167 0018fe34 00000000 0018ff44
0018bd20 0018fe78 00000000
0:000> $number of bytes to be written 0x1167
0:000> .formats 00001167
Evaluate expression:
Hex: 00001167
Decimal: 4455
Octal: 00000010547
Binary: 00000000 00000000 00010001 01100111
Chars: ...g
Time: Wed Dec 31 20:14:15 1969
Float: low 6.24278e-042 high 0
Double: 2.20106e-320
0:000> gu
eax=00000000 ebx=00000000 ecx=76b2df07 edx=00000057 esi=0018bd1c edi=0018fe64
eip=00411612 esp=0018bd1c ebp=0018fe64 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
cci!cci_f+0x162:
00411612 cmp esi,esp
0:000> $number of bytes written
0:000> dd 0018fe34 l1
0018fe34 00000000
Since you are writing non-buffered, you need to adhere to the alignment requirements that are documented here: https://msdn.microsoft.com/en-us/library/windows/desktop/cc644950.aspx
Specifically the file access must start at a multiple of the volume sector size, and have a size that is a multiple of the volume sector size. Your 4455 sized buffer does not meet the second requirement.
Of course, if you want to write those final 4455 bytes and no more then you are in a quandry. You need to round it up to a multiple of the volume sector size and write the actual 4455 bytes followed by padding. The set the file pointer back to the end of those 4455 bytes, and call SetEndOfFile.

!heap -stat -h doesn't show allocations

I'm trying to determine why my applications consumes 4GB of Private Bytes. So I took a full memory dump, loaded it in windbg. But analyzing using !heap -stat -h produces weird results which don't add up:
0:000> !heap -s
(...)
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-------------------------------------------------------------------------------------
000002d0a0000000 00000002 2800804 2780508 2800700 2984 1980 177 0 6 LFH
000002d09fe10000 00008000 64 4 64 2 1 1 0 0
000002d09ff70000 00001002 1342924 1334876 1342820 13042 3342 87 0 0 LFH
Ok, I got a 2.8GB heap and a 1.34GB heap. Let's look at the allocations of the first one:
0:000> !heap -stat -h 000002d0a0000000
heap # 000002d0a0000000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
651 291 - 1035e1 (16.00)
79c 1df - e3ce4 (14.06)
28 156d - 35908 (3.31)
(...)
IIUC, the first line means block size 0x651(=1617 bytes), number blocks 0x291(=657), for total bytes of 0x103531(=1062369 bytes =~1MB), and that's 16% of total busy bytes. But looking at the summary, there should be ~2.8GB of busy bytes!
Another disparity:
0:000> !heap -stat -h 000002d0a0000000 -grp A
heap # 000002d0a0000000
group-by: ALLOCATIONSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
a160 1 - a160 (0.62)
7e50 2 - fca0 (0.97)
0:000> !heap -h 000002d0a0000000
(...)
(509 lines that note allocations with size 7e50, like this one:)
000002d0a3f48000: 11560 . 07e60 [101] - busy (7e50)
Edit: Many lines also say Internal at the end, which appears to mean HEAP_ENTRY_VIRTUAL_ALLOC - but the 509 lines with (7e50) don't.
My question: How can I get !heap -stat -h to show all the allocations, so they add up to the output of !heap -s?
At the moment I can only explain the busy percentage, but that may already be helpful. Its value is a bit misleading.
Virtual memory is memory taken from VirtualAlloc(). The C++ heap manager uses that basic mechanism to get memory from the operating system. That virtual memory can be committed (ready to use) or reserved (can be committed later). The output of !heap -s tells you the status of the heaps with respect to that virtual memory.
So we agree that any memory the C++ heap manager can use is committed memory. This coarse granular virtual memory is split into finer blocks by the C++ heap manager. The heap manager may allocate such smaller blocks and free them, depending on the need of malloc()/free() or new/delete operations.
When blocks become free, they are no longer busy. At the same time, the C++ heap manager may decide to not give the free block back to the OS, because
it can't, since other parts of the 64k virtual memory are still in use
or it doesn't want to (internal reasons we can't exactly know, e.g. performance reasons)
Since the free parts do not count as busy, the busy percentage seems to be too high when compared to the virtual memory.
Mapped to your case, this means:
you have 2.8 GB of virtual memory
in heap 000002d0a0000000, you have ~1 MB / 16% = 6.25 MB of memory in use, the rest could be in free heap blocks (it possibly isn't)
The following example is based on this C++ code:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <iomanip>
int main()
{
HANDLE hHeap = HeapCreate(0, 0x1000000, 0x10000000); // no options, initial 16M, max 256M
HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, 511000); // max. allocation size for non-growing heap
std::cout << "Debug now, handle is 0x" << std::hex << std::setfill('0') << std::setw(sizeof(HANDLE)) << hHeap << std::endl;
std::string dummy;
std::getline(std::cin, dummy);
return 0;
}
The only 511kB block will be reported as 100%, although it is only ~1/32 of the 16 MB:
0:001> !heap -stat -h 009c0000
heap # 009c0000
group-by: TOTSIZE max-display: 20
size #blocks total ( %) (percent of total busy bytes)
7cc18 1 - 7cc18 (100.00)
To see the free parts as well, use !heap -h <heap> -f:
0:001> !heap -h 0x01430000 -f
Index Address Name Debugging options enabled
3: 01430000
Segment at 01430000 to 11430000 (01000000 bytes committed)
Flags: 00001000
ForceFlags: 00000000
Granularity: 8 bytes
Segment Reserve: 00100000
Segment Commit: 00002000
DeCommit Block Thres: 00000200
DeCommit Total Thres: 00002000
Total Free Size: 001f05c7
Max. Allocation Size: 7ffdefff
Lock Variable at: 01430138
Next TagIndex: 0000
Maximum TagIndex: 0000
Tag Entries: 00000000
PsuedoTag Entries: 00000000
Virtual Alloc List: 014300a0
Uncommitted ranges: 01430090
FreeList[ 00 ] at 014300c4: 01430590 . 0240e1b0
0240e1a8: 7cc20 . 21e38 [100] - free <-- no. 1
02312588: 7f000 . 7f000 [100] - free <-- no. 2
[...]
01430588: 00588 . 7f000 [100] - free <-- no. 32
Heap entries for Segment00 in Heap 01430000
address: psize . size flags state (requested size)
01430000: 00000 . 00588 [101] - busy (587)
01430588: 00588 . 7f000 [100]
[...]
02312588: 7f000 . 7f000 [100]
02391588: 7f000 . 7cc20 [101] - busy (7cc18)
0240e1a8: 7cc20 . 21e38 [100]
0242ffe0: 21e38 . 00020 [111] - busy (1d)
02430000: 0f000000 - uncommitted bytes.
0:001> ? 7cc18
Evaluate expression: 511000 = 0007cc18
Here we see that I have a heap of 256 MB (240 MB uncommitted, 0x0f000000 + 16 MB committed, 0x01000000). Summing up the items in the FreeList, I get
0:001> ? 0n31 * 7f000 + 21e38
Evaluate expression: 16264760 = 00f82e38
So almost everything (~16 MB) is considered as free and not busy by the C++ heap manager. Memory like that 16 MB is reported by !heap -s in this way in WinDbg 6.2.9200:
0:001> !heap -s
LFH Key : 0x23e41d0e
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
004d0000 00000002 1024 212 1024 6 5 1 0 0 LFH
00750000 00001002 64 20 64 9 2 1 0 0
01430000 00001000 262144 16384 262144 15883 32 1 0 0
External fragmentation 96 % (32 free blocks)
-----------------------------------------------------------------------------
IMHO there's a bug regarding reserved and committed memory: it should be 262144k virtual - 16384 committed = 245760k reserved.
Note how the list length matches the number of free blocks reported before.
Above explains the busy percentage only. The remaining question is: the free memory reported in your case doesn't match this scenario.
Usually I'd say the remaining memory is in virtual blocks, i.e. memory blocks that are larger than 512 kB (32 bit) or 1 MB (64 bit) as mentioned on MSDN for growable heaps. But that's not the case here.
There is no output about virtual blocks and the number of virtual blocks is reported as 0.
A program that generates a virtual block would be
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
#include <string>
#include <iomanip>
int main()
{
HANDLE hHeap = HeapCreate(0, 0x1000000, 0); // no options, initial 16M, growable
HeapAlloc(hHeap, HEAP_GENERATE_EXCEPTIONS, 20*1024*1024); // 20 MB, force growing
std::cout << "Debug now, handle is 0x" << std::hex << std::setfill('0') << std::setw(sizeof(HANDLE)) << hHeap << std::endl;
std::string dummy;
std::getline(std::cin, dummy);
return 0;
}
and the !heap command would mention the virtual block:
0:001> !heap -s
LFH Key : 0x7140028b
Termination on corruption : ENABLED
Heap Flags Reserv Commit Virt Free List UCR Virt Lock Fast
(k) (k) (k) (k) length blocks cont. heap
-----------------------------------------------------------------------------
006d0000 00000002 1024 212 1024 6 5 1 0 0 LFH
001d0000 00001002 64 20 64 9 2 1 0 0
Virtual block: 01810000 - 01810000 (size 00000000)
00810000 00001002 16384 16384 16384 16382 33 1 1 0
External fragmentation 99 % (33 free blocks)
-----------------------------------------------------------------------------
In your case however, the value virtual blocks is 0. Perhaps this what is reported as "Internal" in your version of WinDbg. If you have not upgraded yet, try version 6.2.9200 to get the same output as I do.

glibc detected invalid pointer [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
So for one of my school assignments I have to implement my own memory allocation package. I use a struct block that represents a free block of memory and create a list of those blocks showing where the free spaces on my memory heap are, also known as my 'free list'. Below is the block struct I create.
typedef struct block {
struct block *next;
struct block *prev;
int size;
unsigned char *buffer;
} block;
my_malloc() implementation (see below) seems to be working fine under my tests.
void *my_malloc(int size){
//if my_malloc has never been called before create the first
// free block who's data buffer spans the entire heap
if(!initialized){
initialized = 1; //Next time, we've already inited
// Create the first block
*(block *)head = (block){NULL, NULL, 0, NULL};
block *p = (block *)head;
//try setting size to 128KB and point buffer properly
p->size = 1024*128;
p->buffer = p+ 1;
printf("Address of buffer is %p\n", p->buffer);
// set the program break
brk(head + (sizeof(block)+p->size));
}
block *p = (block *)head; //point to the head, we don't want to move the head...
// find the appropriate free block and check for nullity
block *selected = find_block(size);
if(selected==NULL){
printf("Had no space first time around!\n");
//go to the end of the free list
while(p->next!=NULL){
p=p->next;
}
// increase it's size by 128KB
p->size=p->size+(128*1024);
// move the program break by additional 128KB
sbrk(128*1024);
//now the last free block has enough space, so make it the selected block
selected=p;
}
block *new_block; // new block we will create
// if the block we have to allocate is pointed by head, we need a new
// head
if ((block *)selected==(block *)head){
//shift head
head = selected->buffer+ size;
//Create a new block there, it wil be our new head and we don't return it
*(block *)head = (block){NULL, NULL, 0, NULL};
block *new_block = (block *)head;
new_block->prev = selected->prev;
new_block->next = selected->next;
new_block->size = selected->size-size;
new_block->buffer = new_block +1;
printf("The split new_block->buffer points to %p\n", new_block->buffer);
//return the pointer to original head, not the new one.
total_malloced=+size;
return selected->buffer;
}
// The selected node is not the head so we don't move the head
else{
new_block = selected->buffer+size;
new_block->prev = selected->prev;
new_block->next = selected->next;
new_block->size = selected->size-size;
new_block->buffer = new_block +1;
//remove that selected block from the free list
(selected->prev)->next=new_block;
total_malloced=+size;
return selected->buffer;
}
}
The issue occurs when sending the returned pointer of my_malloc to a method like my_free().
void my_free(void *ptr) {
printf("Dummy instruct.\n");
}
I get the following error:
*** glibc detected *** ./myMalloc: munmap_chunk(): invalid pointer: 0x0804a17e ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x75ee2)[0xb7e7cee2]
/lib/i386-linux-gnu/libc.so.6(+0x765c5)[0xb7e7d5c5]
./myMalloc[0x80485b1]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0xb7e204d3]
./myMalloc[0x8048401]
======= Memory map: ========
08048000-08049000 r-xp 00000000 00:3d 8557227 /home/2009/gkrink/os/myMalloc
08049000-0804a000 r--p 00000000 00:3d 8557227 /home/2009/gkrink/os/myMalloc
0804a000-0804b000 rw-p 00001000 00:3d 8557227 /home/2009/gkrink/os/myMalloc
0804b000-0808c000 rw-p 00000000 00:00 0 [heap]
b7e06000-b7e07000 rw-p 00000000 00:00 0
b7e07000-b7faa000 r-xp 00000000 00:11 4370765 /lib/i386-linux-gnu/libc-2.15.so
b7faa000-b7fab000 ---p 001a3000 00:11 4370765 /lib/i386-linux-gnu/libc-2.15.so
b7fab000-b7fad000 r--p 001a3000 00:11 4370765 /lib/i386-linux-gnu/libc-2.15.so
b7fad000-b7fae000 rw-p 001a5000 00:11 4370765 /lib/i386-linux-gnu/libc-2.15.so
b7fae000-b7fb1000 rw-p 00000000 00:00 0
b7fbb000-b7fd7000 r-xp 00000000 00:11 6829467 /lib/i386-linux-gnu/libgcc_s.so.1
b7fd7000-b7fd8000 r--p 0001b000 00:11 6829467 /lib/i386-linux-gnu/libgcc_s.so.1
b7fd8000-b7fd9000 rw-p 0001c000 00:11 6829467 /lib/i386-linux-gnu/libgcc_s.so.1
b7fd9000-b7fdd000 rw-p 00000000 00:00 0
b7fdd000-b7fde000 r-xp 00000000 00:00 0 [vdso]
b7fde000-b7ffe000 r-xp 00000000 00:11 4370778 /lib/i386-linux-gnu/ld-2.15.so
b7ffe000-b7fff000 r--p 0001f000 00:11 4370778 /lib/i386-linux-gnu/ld-2.15.so
b7fff000-b8000000 rw-p 00020000 00:11 4370778 /lib/i386-linux-gnu/ld-2.15.so
bffdf000-c0000000 rw-p 00000000 00:00 0 [stack]
Aborted
And here is my test function:
void main(void){
printf("Testing initiated...\n");
printf("head is located at %p\n\n", head);
void * tester;
printf("mallocing 100...\n");
tester = my_malloc(100);
printf("The allocated memory starts at %p\n", tester);
printf("mallocing 150...\n");
tester=my_malloc(150);
printf("The allocated memory starts at %p\n", tester);
printf("head is located at %p\n\n", head);
printf("brk is firstly located at %p\n", sbrk(0));
printf("mallocing 10...");
tester=my_malloc(10);
printf("The allocated memory starts at %p\n", tester);
printf("brk is still at %p\n", sbrk(0));
free(tester);
}
And without sending the returned pointer of my_malloc() to my_free() I get correct output such as:
Testing initiated... head is located at 0x804a054
mallocing 100... Address of buffer is 0x804a064 The split
new_block->buffer points to 0x804a0d8 The allocated memory starts at
0x804a064 mallocing 150... The split new_block->buffer points to
0x804a17e The allocated memory starts at 0x804a0d8 head is located at
0x804a16e
brk is firstly located at 0x806a064 mallocing 10...The split
new_block->buffer points to 0x804a198 The allocated memory starts at
0x804a17e brk is still at 0x806a064
Why can't I send pointers to another function like that?
If this is the actual code, you're calling the standard library free instead of your own version:
free(tester);
Passing a pointer to memory you haven't allocated with malloc will definitely not do good things.

compilation break when reallocating the memory in C

I'm trying an example
int main(){
int count = 5;
char *a = "JOSUA";
char *c = "JANETALAE";
char *b = NULL;
char *d = NULL;
b = (char *)malloc(sizeof(char)*5);
b = a;
if(b == NULL){
printf("\n malloc failed");
}
printf("\nChar is:%s\n",b);
d = (char *)realloc(b,sizeof(char) * 9);
if(d == NULL){
printf("\n realloc failed");
}
else{
b = d;
b = c;
}
printf("\nChar is:%s\n",b);
return 0;
}
I'm trying a sample program to allocate and reallocate memory. But i couldn't reallocate the memory and getting a compilation break as below.
Char is:JOSUA
*** glibc detected *** ./realloc: realloc(): invalid pointer: 0x080485b4 ***
======= Backtrace: ========= /lib/libc.so.6[0x88ffd1] /lib/libc.so.6(realloc+0x2cf)[0x89613f] /lib/libc.so.6(realloc+0x2e7)[0x896157] ./realloc[0x80484aa] /lib/libc.so.6(__libc_start_main+0xe6)[0x836e16] ./realloc[0x8048391]
======= Memory map: ======== 007fc000-0081c000 r-xp 00000000 fd:00 659977 /lib/ld-2.12.90.so 0081c000-0081d000 r--p 0001f000 fd:00 659977 /lib/ld-2.12.90.so 0081d000-0081e000 rw-p 00020000 fd:00 659977 /lib/ld-2.12.90.so 00820000-009ad000 r-xp 00000000 fd:00 660018 /lib/libc-2.12.90.so 009ad000-009af000 r--p 0018c000 fd:00 660018 /lib/libc-2.12.90.so 009af000-009b0000 rw-p 0018e000 fd:00 660018 /lib/libc-2.12.90.so 009b0000-009b3000 rw-p 00000000 00:00 0 00a29000-00a45000 r-xp 00000000 fd:00 660039 /lib/libgcc_s-4.5.1-20100924.so.1 00a45000-00a46000 rw-p 0001b000 fd:00 660039 /lib/libgcc_s-4.5.1-20100924.so.1 00a84000-00a85000 r-xp 00000000 00:00 0 [vdso] 08048000-08049000 r-xp 00000000 fd:02 9440701 /home/user/beata/c_samples/realloc 08049000-0804a000 rw-p 00000000 fd:02 9440701 /home/user/beata/c_samples/realloc 092ac000-092cd000 rw-p 00000000 00:00 0 [heap] b78bc000-b78bd000 rw-p 00000000 00:00 0 b78d3000-b78d5000 rw-p 00000000 00:00 0 bfbd8000-bfbf9000 rw-p 00000000 00:00 0 [stack] Aborted (core dumped)
Could not understand why the compilation break happened.
You can't use realloc on a static-memory variable (which is a, actually):
b = (char *)malloc(sizeof(char)*5);
b = a;
maybe replacing:
b=a;
with:
strcpy(b,a);
will get you heading in the right direction. I think maybe you think thats what b=a; is actually doing?
but make sure you have allocated enough memory on the heap, i.e. don't forget the '\0' implicit at the end of the string, e.g.
b = (char *)malloc(sizeof(char)*5);
should be:
b = malloc(6);
if you want to fit "JOSUA" in it ("JOSUA" is actually "JOSUA\0")
You are passing an invalid pointer to realloc(), just as the error says.
It's from this line:
b = a;
where you overwrite the return value of malloc() with the address of a string literal. You cannot pass that to realloc().
Your overall logic in this program is very broken; if malloc() fails, there's little reason to believe realloc() will succeed (assuming the above line is an editing error and shouldn't be there).
Also, this is a run-time error, not a "compilation error" as you say.
Further, the typical errors apply:
In C, don't cast the return value of malloc(). This applies just as well to realloc(), too.
Don't use sizeof (char), it's just a very cumbersome way to write 1.
b = (char *)malloc(sizeof(char)*5);
b = a;
There you just lost the address returned by malloc.
You need to pass the address returned by malloc to realloc if you pass any other address it results in Undefined Behavior and that is what your code does.
You try to realloc memory that has not been malloc'd :
9 b = (char *)malloc(sizeof(char)*5);
10 b = a;
Your line 9 here is rendered useless by the 10th, and the adress returned by malloc is lost.
Also, do not cast the return of malloc as this can hide other errors.
This is the line:
10 b = a;
Here, you are setting the pointer b to the address stored in the pointer a. So b now points to the string "JOSHUA".
When you try to realloc b, you are feeding it that address, which was not initially allocated by malloc. what you want to do is copy the string from a to b:
strcpy(b,a);
However, you will need to increase the size of the memory pointed to by b.
Problem is
b = (char *) malloc(sizeof(char) * 5);
and then immediately you are changing the address pointing by b
by assigning base address to which a is pointing to.
i.e. b = a; /* which is the error */.
For the re-alloc you have to pass the address returned by the malloc,
not the base address to which the a pointing to.

Dynamic memory allocation in C problem

I'm trying to increase memory of a, but realloc doesnt seem to do anything. At 4th number program crashes. It seems also that numbers are put into a[0] even though counter is increased and should be a[counter]. I know I start at a[1], because I'm writing counter itself in a[0] when I'm done inputing.
Translation of printf: Input vector (you end input with any nonnumber character except dot).
#include <stdio.h>
#include <stdlib.h>
typedef float* vektor;
vektor beriVektor() {
int counter = 0;
float zacasna;
float *a = (float *) malloc(sizeof(float));
printf("Vpisi vektor (vpis zakljucis s katerim koli nestevilskim znakom razen pike):\n");
while(scanf("%f", &zacasna)) {
counter++;
printf("%d\n", counter);
printf("%d\n", sizeof(a));
a = realloc(a, (sizeof(a) + sizeof(float)));
a[counter] = zacasna;
}
if (sizeof(a) == sizeof(float)) {
return NULL;
}
a[0] = counter;
return a;
}
void izpisiVektor(vektor a) {
if (a == NULL) {
return;
}
else {
int velikost = sizeof(a)/sizeof(float);
for (int i = 0; i < velikost; i++) {
printf("%f", *(a+i));
}
}
}
void main(){
vektor a = beriVektor();
izpisiVektor(a);
}
output:
ragezor#ragezor-VirtualBox:~$ ./dn09.o
Vpisi vektor (vpis zakljucis s katerim koli nestevilskim znakom razen pike):
1 2 3 4
1
4
2
4
3
4
4
4
*** glibc detected *** ./dn09.o: realloc(): invalid next size: 0x09052008 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6c501)[0x835501]
/lib/libc.so.6(+0x71c6d)[0x83ac6d]
/lib/libc.so.6(realloc+0xe3)[0x83af53]
./dn09.o[0x804850e]
./dn09.o[0x8048595]
/lib/libc.so.6(__libc_start_main+0xe7)[0x7dfce7]
./dn09.o[0x8048411]
======= Memory map: ========
001c9000-001e3000 r-xp 00000000 08:01 393295 /lib/libgcc_s.so.1
001e3000-001e4000 r--p 00019000 08:01 393295 /lib/libgcc_s.so.1
001e4000-001e5000 rw-p 0001a000 08:01 393295 /lib/libgcc_s.so.1
005d5000-005f1000 r-xp 00000000 08:01 393234 /lib/ld-2.12.1.so
005f1000-005f2000 r--p 0001b000 08:01 393234 /lib/ld-2.12.1.so
005f2000-005f3000 rw-p 0001c000 08:01 393234 /lib/ld-2.12.1.so
0069e000-0069f000 r-xp 00000000 00:00 0 [vdso]
007c9000-00920000 r-xp 00000000 08:01 393454 /lib/libc-2.12.1.so
00920000-00922000 r--p 00157000 08:01 393454 /lib/libc-2.12.1.so
00922000-00923000 rw-p 00159000 08:01 393454 /lib/libc-2.12.1.so
00923000-00926000 rw-p 00000000 00:00 0
08048000-08049000 r-xp 00000000 08:01 140607 /home/ragezor/dn09.o
08049000-0804a000 r--p 00000000 08:01 140607 /home/ragezor/dn09.o
0804a000-0804b000 rw-p 00001000 08:01 140607 /home/ragezor/dn09.o
09052000-09073000 rw-p 00000000 00:00 0 [heap]
b7700000-b7721000 rw-p 00000000 00:00 0
b7721000-b7800000 ---p 00000000 00:00 0
b78d9000-b78da000 rw-p 00000000 00:00 0
b78e7000-b78eb000 rw-p 00000000 00:00 0
bfc2e000-bfc4f000 rw-p 00000000 00:00 0 [stack]
Aborted
edit:
Thank you. Very good answers from all of you.
Is there any way to find out how much memory space does have vektor a allocated?
Later in the code I check with sizeof(a)/sizeof(float) for number of elements in that array which now I understand is incorect. Luckily I have counter stored in a so i know how much elements i have, but if I wouldn't have that information stored how would I know?
The realloc is incorrect. You are getting the size of a pointer on your machine, not the size of the allocated space so far.
float *a = (float *) malloc(sizeof(float));
/* .... */
a = realloc(a, (sizeof(a) + sizeof(float)));
So, suppose a float * occupies 4 bytes. You will always allocate 4 + sizeof(float) and eventually you'll step outside. You need to keep track of the number of elements and then:
a = realloc(a, sizeof(float) * (el_no + 1));
Of course, a nicer form would be:
a = realloc(a, sizeof(*a) * (el_no + 1));
If you later decide to change the type of a you'll be safe this way.
Edit
As a side note, calling realloc for each and every new element might seem like a good deal, but it's slow. You should employ a strategy like "when I run out of space I will double the current used amount" or something in that line.
Whatever you think this:
if (sizeof(a) == sizeof(float)) {
return NULL;
}
Is doing, it isn't.
When you do:
float *a = (float *) malloc(sizeof(float));
...
a = realloc(a, (sizeof(a) + sizeof(float)));
the 'sizeof(a)' is always going to return 4(on 32-bit machine, 8 on 64-bit machines). 'sizeof()' despite its appearance is NOT a function. It's an operator of sorts that gives you the size of the variable. IN this case 'a' is just a pointer. sizeof will not give you the size of what a is pointing at.
What you need to do is keep a length variable that keeps track of the number of floats you have in the block allocated by malloc/realloc.
int N_floats = 0 ;
float *a = (float *)malloc(0) ;
/* add a float */
a = (float *)realloc(a, (N_floats+1)*sizeof(float)) ;
a[N_floats] = 1.0 ;
N_floats += 1;
a = realloc(a, (sizeof(a) + sizeof(float)));
sizeof(a) and sizeof(float) are both constants (for the most part, sizeof(anything) is a constant). So you're always asking for the same amount of memory here.
Typically you need something along the lines of
a = realloc(a, counter * sizeof(float));
but
You'll need to check this for off-by-one errors: maybe you'll want (counter + 1) instead of counter, or so.
Don't ever use a = realloc(a, ...). Look up how realloc reports errors (and what it does with the original memory block in the event of errors) to see why.
See also http://c-faq.com/malloc/realloc.html
In short sizeof(a) doesn't do what you think it does. The type of a is *float so it has a very small size. You need to keep track of the length of the array and multiply that by sizeof(float) to get the current size.
The error you get means you have a buffer overflow in your heap segment. This is because at line 15 you do:
a = realloc(a, (sizeof(a) + sizeof(float)));
sizeof is a macro function it will be determent at compile time not a runtime you should use the counter to calculate the needed size for a new read. Try something like this:
a = realloc(a, (sizeof(*a) * (counter + 1))); // + one for the counter itself
Also you need to keep in mind that at line 21 you cast your integer (counter) to and float which will cause the counter to wrap and restart with negative value.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int value = 822222233;
float flt = value;
printf("equal: %s\nvalue = %d\nflt = %f\n(int)flt = %d", value == flt ? "true" : "false", value, flt, ((int)flt));
exit(0);
}
Output:
gcc -m32 -O3 -Wall -Wextra -std=c99 test.c && ./a.out
equal: true
value = 822222233
flt = 822222208.000000
(int)flt = 822222208
As you can see your counter will corrupt :)

Resources