Why are there two heaps in a newly created windows process? - c

I discovered this when playing with the standard malloc function and calling HeapWalk to see the size of the allocated block. Found out that malloc does not create blocks in the default process heap but rather in a second heap that I did not create.
Why are there two heaps? Even without calling malloc the process still has two heaps and the second one is not empty. This is the result of HeapWalk on the second heap without any call to malloc or HeapAlloc.
Also because of this behaviour of malloc another question crossed my mind. Is it correct to allocate memory on the default process heap? I never created a new heap for casual programs and did HeapAlloc(GetProcessHeap(), ...) but is this practice harmful or bad in any way?
This is the code i used for testing:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#define MAX_HEAP_COUNT 10
INT APIENTRY WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
HANDLE hHeaps[MAX_HEAP_COUNT];
DWORD dwHeaps;
dwHeaps = GetProcessHeaps(MAX_HEAP_COUNT, hHeaps);
LPVOID lpDummyBlocks[20];
for(DWORD i = 0; i < 20; i++)
lpDummyBlocks[i] = malloc(rand()%1000+1);
for(DWORD i = 0; i < dwHeaps; i++)
{
SIZE_T cbSize = HeapCompact(hHeaps[i], IGNORE);
printf("Largest free block in heap %lu is %lu bytes.\n", i, cbSize);
PROCESS_HEAP_ENTRY phe;
phe.lpData = NULL;
DWORD dwTotalBlocks = 0;
while(HeapWalk(hHeaps[i], &phe))
{
printf("Found a block at address [%p]", phe.lpData);
printf(" Block size: %lu", phe.cbData);
for(DWORD i = 0; i < 20; i++)
if (phe.lpData == lpDummyBlocks[i])
{
printf(" This is DummyBlock%lu", i);
break;
}
dwTotalBlocks++;
printf("\n");
}
printf("Total blocks: %lu. \n\n", dwTotalBlocks);
}
for(DWORD i = 0; i < 20; i++)
free(lpDummyBlocks[i]);
return 0;
}
UPDATE
I played with the second heap a little bit more and noticed a strange behaviour. I am not sure if my GetHeapInfo function is correct but i think thats what MSDN said about the .cbData field of the PROCESS_HEAP_ENTRY structure.
struct tagHEAP_INFO
{
DWORD dwBlockCount;
DWORD dwTotalOverhead;
DWORD dwTotalBlockSize;
};
typedef struct tagHEAP_INFO HEAP_INFO, *LPHEAP_INFO;
WINBOOL APIENTRY GetHeapInfo(HANDLE hHeap, LPHEAP_INFO lpHeapInfo)
{
// error checking ...
// ...
// return FALSE;
PROCESS_HEAP_ENTRY phe;
phe.lpData = NULL;
lpHeapInfo->dwBlockCount = 0;
lpHeapInfo->dwTotalBlockSize = 0;
lpHeapInfo->dwTotalOverhead = 0;
while(HeapWalk(hHeap, &phe))
{
lpHeapInfo->dwBlockCount++;
lpHeapInfo->dwTotalBlockSize += phe.cbData;
lpHeapInfo->dwTotalOverhead += phe.cbOverhead;
}
DWORD dwLastError = GetLastError();
if (dwLastError == ERROR_NO_MORE_ITEMS)
return TRUE;
Beep(1000, 1000); // well, its easier this way :)
return FALSE;
}
With this function i counted the total bytes allocated at the beginning of the process, after allocating some blocks and after freeing them. This is the strange result (and i checked it and its not an overflow):
Adding to this, i made the same test with the default process heap. I got strange results here too, this time also the block count did not match (and i checked that all the blocks were allocated).
Am i misinterpreting this? I am using HeapWalk the way this example (enumerating a heap) is showing. This time i only used HeapAlloc for allocation.

Related

Error in ./thrash: free(): invalid pointer

I realize this has been asked several times but none of the solutions offer any help for me. I am writing a lab program that allocates a large amount of memory in C specifically an array of char pointers, each of which have allocated the size of a page in memory which is 4096 bytes.
char** pgs =(char**) malloc(sizeof(char *) * pages);
if(pgs == NULL){
printf("Failed to allocate memory");
exit(0);
}
int i;
for(i = 0; i < pages; i++){
pgs[i] = malloc(4096);
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
*pgs[i] = "\0";
/*if(pgs[i] == NULL){
printf("Failed to allocate memory");
exit(0);
}*/
}
In the middle of the program elements of this array are accessed and modified at random so as to induce thrashing (as part of the lab):
while(time(NULL) - startTime < seconds){
long rando = rand() % pages;
if(modify > 0){
*pgs[rando]++;
}
else{
long temp = *pgs[rando];
}
At the end of the program I attempt to free this memory:
for(i = 0; i < pages; i++){
free(pgs[i]);
}
free(pgs);
I am however getting the dread "invalid pointer" error. If anyone has any advice or knowledge on how this might be fixable, please share.
The program fragments you show exhibit numerous problems, some of which were identified in comments:
Programs should report errors on standard error, not standard output.
Programs should exit with a non-zero status if they fail.
Programs should compile without warnings.
Messages in general and error messages in particular should end with a newline.
The program only attempts to modify one byte of each page.
However, the primary problem is that the code in the question uses *pgs[rando]++ which is intended to modify the memory that's allocated. This is equivalent to *(pgs[rando]++) which increments the pointer and then reads the value and discards it — rather than being equivalent to (*pgs[rando])++ which would modify the byte pgs[rando][0]. The code in the question should generate a warning about value computed is not used (or an error if you make sure you compile with all warnings are treated as errors). Because your code is incrementing the pointers, the values returned to to the memory allocation system with free() are not, in general, the same as the ones that the memory allocation system returned to you, so you are indeed passing invalid pointers to free().
This code avoids the problems described above. It does a fix number of iterations and doesn't use time(). It prints the sum so that the optimizer cannot optimize away the read accesses to the memory.
/* SO 4971-2352 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { PAGESIZE = 4096 };
int main(void)
{
int pages = PAGESIZE;
char **pgs = (char **)malloc(sizeof(char *) * pages);
if (pgs == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < pages; i++)
{
pgs[i] = malloc(PAGESIZE);
if (pgs[i] == NULL)
{
fprintf(stderr, "Failed to allocate memory\n");
exit(EXIT_FAILURE);
}
memset(pgs[i], '\0', PAGESIZE); // Or use calloc()!
}
size_t sum = 0;
for (int i = 0; i < PAGESIZE * PAGESIZE; i++)
{
int pagenum = rand() % pages;
int offset = rand() % PAGESIZE;
int modify = i & 2;
if (modify != 0)
{
pgs[pagenum][offset]++;
}
else
{
sum += pgs[pagenum][offset];
}
}
printf("Sum: 0x%.8zX\n", sum);
for (int i = 0; i < pages; i++)
free(pgs[i]);
free(pgs);
return 0;
}
I called that code thrash31.c and compiled it into thrash31 using:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror thrash31.c -o thrash31
$
When run with a timing program, I got the output:
$ timecmd -u -- thrash31
2018-04-07 15:48:58.546809 [PID 9178] thrash31
Sum: 0x001FE976
2018-04-07 15:48:59.355508 [PID 9178; status 0x0000] - 0.808699s
$
So, it took about 0.8 seconds to run. The sum it generates is the same each time because the code doesn't seed the random number generator.

How do I properly allocate memory in my C program?

I am writing a Windows program in C for a homework assignment and I am running into a problem that causes my program to crash with program.exe has stopped working. I believe that this is due to the memory not being allocated correctly.
The program is supposed to start multiple threads to perform a task, I have found an example on MSDN on creating threads. I have added parts of the code into my program.
My program:
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <Windows.h>
#define MAX_THREADS 4
#define BUFFER_SIZE 65000
DWORD WINAPI SomeFunction( LPVOID lpParam );
char fileBuffer[BUFFER_SIZE];
typedef struct MyData {
int val1;
int val2;
} MYDATA, *PMYDATA;
int main(int argc, char *argv[])
{
int i = 0;
int j = 0;
PMYDATA pDataArray[MAX_THREADS];
DWORD dwThreadIdArray[MAX_THREADS];
HANDLE hThreadArray[MAX_THREADS];
for (i; i < MAX_THREADS; i++)
{
pDataArray[i] = (PMYDATA) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
sizeof(MYDATA));
if( pDataArray[i] == NULL )
{
// If the array allocation fails, the system is out of memory
// so there is no point in trying to print an error message.
// Just terminate execution.
ExitProcess(2);
}
// Create the thread to begin execution on its own.
hThreadArray[i] = CreateThread(NULL, 0, SomeFunction, pDataArray[i], 0, &dwThreadIdArray[i]);
if (hThreadArray[i] == NULL)
{
printf("%s\n", "Error creating thread!");
ExitProcess(3);
}
}
for (j; j < MAX_THREADS; j++)
{
printf("%s%d\n", "j=", j);
WaitForSingleObject(hThreadArray[j], INFINITE);
}
//WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
i = 0;
for(i; i<MAX_THREADS; i++)
{
CloseHandle(hThreadArray[i]);
if(pDataArray[i] != NULL)
{
HeapFree(GetProcessHeap(), 0, pDataArray[i]);
pDataArray[i] = NULL; // Ensure address is not reused.
}
}
printf("%s\n", "DONE!");
return 0;
}
DWORD WINAPI SomeFunction( LPVOID lpParam)
{
PMYDATA pDataArray;
int anotherInt;
anotherInt = pDataArray->val1; // PROBLEM OCCURS HERE!
printf("%s%d\n", "Printing int ", anotherInt);
return 0;
}
The program above should be able to start multiple threads which execute SomeFunction(). I have isolated bug to this function, specifically the line anotherInt = pDataArray->val1;. pdataArray is an array of MyData defined in a struct and each element is passed into a thread.
Did I not allocate the memory for the array correctly? If not, how would I access the members of the struct that was passed in as the parameter to SomeFunction()? I have gone over my code a couple of times and could not find anything wrong that I know of. The example I followed on MSDN is here.
In MyFunction, PMYDATA pDataArray; doesn't magically become equal to the pDataArray in main. It's an uninitialized pointer, and pDataArray->val1; tries to write to a random memory location.
Hint: you also have a LPVOID lparam which you ignore.

Change a dynamic 2D char array through a function in C?

I'm creating this sample run so I can better understand how I can edit dynamic arrays through other functions, but I started running into segfaults once I added the secondary function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void other_side(char ***funk);
int main()
{
int i;
char *argv[11] = {"fish", "dish", "lags", "fags", "shag", "cool", "bean", "rekt", "noon", "coon", "lolz"};
char **yep, **nop;
yep = malloc(10 * sizeof *yep);
if(!yep) { // <-----------------added check for malloc error
printf("Error: failure to allocate memory\n");
exit(1);
}
printf("10 times %lu\n\n", sizeof *yep);
for(i = 0; i<10; i++) {
yep[i] = strdup(argv[i]);
printf("%s is in yep.\n", *(yep+i));
}
nop = realloc(yep, 11 * sizeof *yep); //you reallocate to the new total size.
if(nop == NULL) {
printf("Error: failure to allocate memory\n")
exit(1);
}
yep = nop;
*(yep+10) = strdup(argv[10]);
printf("Last but certainly not least, %s is in yep.\n", *(yep+10));
printf("Now to send yep over to the other side and have its values changed.\n");
other_side(&yep);
printf("Did it change?\n\n");
for(i=0; i<11; i++)
printf("%s is in yep.\n", *(yep+i));
for(i=0; i<11; i++) { //issue fixed when added strdup() above, previously static
free(*(yep+i));
}
free(yep);
return 0;
}
void other_side(char ***funk)
{
char *arr[11] = {"dude","yeah","gnar","nice","epic","need","more", "word","four","this","test"};
int i;
for(i=0; i<11; i++) {
**(funk+i) = strdup(arr[i]); //added strdup() here as well
printf("%s is currently in yep.\n", **(funk+i));
}
printf("\n");
}
A couple things I noticed with this is that Valgrind notices an unnecessary free when I try to free the 11th block of memory to my array in main(). I'm not sure if that's my issue, but I also noticed that the function will only change two words before it leads to a segmentation fault.
Edit Notes: Since the edit I still get segfaults, but valgrind has been a bit more clear with what is happening. (Bad permissions for mapped region at address 0x400B18)
Your order of precedence regarding operators is important, and you missed a pair of parens to ensure it is done correctly. This: **(funk+i) means this: *(funk[i]), not (*funk)[i] which is what you want.
This:
**(funk+i) = strdup(arr[i]);
printf("%s is currently in yep.\n", **(funk+i));
Should be this:
*((*funk)+i) = strdup(arr[i]);
printf("%s is currently in yep.\n", *((*funk)+i));
and frankly, it is considerably easier to read as:
(*funk)[i] = strdup(arr[i]);
printf("%s is currently in yep.\n", (*funk)[i]);
I leave the rest of the memory management to you to fix. (i.e. the leaks from the dynamic memory pointed to by all the pointers you're overwriting in the above loop code).

Find a memory leak in C

I'm trying to find a memory leak in the folowing code. valgrind gives me this:
==14160== 1,850 (592 direct, 1,258 indirect) bytes in 9 blocks are definitely lost in loss record 2 of 5
==14160== at 0x4904A06: malloc (vg_replace_malloc.c:149)
==14160== by 0x405B1F: tsCreate (ticket_set.c:55)
==14160== by 0x401ECA: test1TS (main.c:62)
==14160== by 0x40557C: main (main.c:424)
and here's the function:
TicketSetStatus tsCreate(TicketSet* t, int n, int c) {
if(t==NULL){
return TS_CANNOT_CREATE;
}
if (n <= 0){
return TS_ILLEGAL_PARAMETER;
}
t->usedTravels = 0;
t->originalTravels = n;
t->cost = c;
t->moneyLeft = n * c;
//Date time is array of travels:
t->dates = malloc(sizeof(DateTime *)* (n)); //todo maybe c99 allows dynamic arrays?
for (int i = 0; i < n; i++) {
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1);
if (t->dates[i] == NULL) {
free( t->dates);
return TS_CANNOT_CREATE;
}
}
return TS_SUCCESS;
}
TicketSetStatus tsDestroy(TicketSet* t, int* moneyLeft) {
if (t == NULL) {
return TS_FAIL;
}
*moneyLeft = (t->cost) * (t->originalTravels-t->usedTravels);
for (int i = 0; i < t->originalTravels; i++){
free(t->dates[i]);
}
free(t->dates);
t=NULL;
return TS_SUCCESS;
}
when the struct is:
struct TS_element {
int usedTravels;
int originalTravels;
int cost;
DateTime* dates;
int moneyLeft;
};
and
typedef char* DateType
actually playing with free crashes the program more often than not so i'm inclined to live with the memory leak as long as the program functions correctly.
How are you using this array of DateTime? If you are stomping on the values later you will get leaks. Perhaps a confusion about string assignment? ie
char someDateValue[] = "2012-08-15";
t->dates[0] = someDateValue; // Leak -- your allocated string is lost
Instead:
strcpy( t->dates[0], someDateValue );
There is a definite leak in your error condition in tsCreate:
for (int i = 0; i < n; i++) {
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1);
if (t->dates[i] == NULL) {
free(t->dates); // Leak -- every element up to i-1 is lost
return TS_CANNOT_CREATE;
}
}
Are you calling tsDestroy after you've finished with data initialised by tsCreate? Perhaps you're returning from main without cleaning up.
If none of this helps, you should post additional code to show how you are using your data structure.
For at least one error you can focus solely on
...
t->dates = malloc(sizeof(DateTime*) * (n)); /* first malloc */
for (int i = 0; i < n; i++) { /* call this loop 1 */
t->dates[i] = malloc(sizeof(char)*GOOD_LENGTH+1); /* second malloc */
if (t->dates[i] == NULL) { /* test for malloc error */
free( t->dates); /* free the base array/list */
return TS_CANNOT_CREATE; /* exit function */
}
}
...
The problem is if the second malloc fails, the free only frees the base (first) malloc. It does not free any other memory allocations created by the second malloc
in loop 1, on a previous loop 1 iteration. I.e. if t->dates[i] = malloc(... fails when i is equal to 5 then the memory blocks allocated in the iterations 0 to 4 are not freed before exiting the function.
Hopefully that makes sense.
Update #paddy is correct in noting the error of t->dates[0] = someDateValue
which in this case what that is saying is:
char someDateValue[] = "2012-08-15";
could also be written in this case as
char *someDateValue = "2012-08-15";
so that
t->dates[0] = someDateValue;
simply assigns the pointer of the string, replacing the pointer to the freshly allocated block in the preceding malloc.
Ref: If you are still confused you can read the C FAQ question 6.3 So what is meant by the ``equivalence of pointers and arrays'' in C? as well as the rest of the C FAQ.
And is correct to suggest str[n]cpy (or similar replacements) to copy the array contents (rather than its pointer) to the freshly allocated memory block.

Expanding an array of ints using realloc crashes!

I'm trying to expand an array of ints on the heap using realloc but the programme is crashing when I use my custom function "ExpandArrayOfInts" but works fine when I write the expander code within main.
Here is the code (file: main.c) with #defines for both approaches.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int ExpandArrayOfInts(int* arrayToExpand, int expandBy, int inArraySize, int* outArraySize);
int main (int argc, char** argv)
{
#if 1//CODE THAT WORKS
int arraySize = 10;
int* arrayDnmc = NULL;
int* arrayDnmcExpndd;
for (int i = 0; i< 10; ++i)
{
arrayDnmcExpndd = (int*)realloc(arrayDnmc, (arraySize + (i * 10)) * sizeof(int));
if (arrayDnmcExpndd != NULL)
{
arrayDnmc = arrayDnmcExpndd;
memset(arrayDnmc, 0, (arraySize + (i * 10)) * sizeof(int));
}
else
{
printf("Failed to (re)alloc memory for arrayDnmc!\n");
free(arrayDnmc);
return -1;
}
}
free(arrayDnmc);
#else //CODE THAT DOESN'T WORK (Which I'm trying to make it work)
int maxSize = 100;
int arraySize = 10;
int* arrayDnmc = NULL;
arrayDnmc = (int*)malloc(arraySize * sizeof(int));
if (arrayDnmc != NULL)
{
memset(arrayDnmc, 0, arraySize * sizeof(int));
}
else
{
printf("malloc failure!\n");
return -1;
}
while (arraySize < maxSize)
{
if (0 != ExpandArrayOfInts(arrayDnmc, 5, arraySize, &arraySize))
{
printf("Something went wrong.\n");
break;
}
//do something with the new array
printf("new size: %i\n", arraySize);
}
free(arrayDnmc);
#endif
return 0;
}
int ExpandArrayOfInts(int* arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
{
int newSize = inArraySize + expandBy;
int* arrayTemp = (int*)realloc(arrayToExpand, newSize * sizeof(int));
if (arrayTemp != NULL)
{
arrayToExpand = arrayTemp;
*outArraySize = newSize;
return 0;
}
return -1;
}
The part that doesn't work gives the following output:
new size: 15
new size: 20
and then I get the crash message:
"Windows has triggered a breakpoint in c_cplusplus_mixing.exe.
This may be due to a corruption of the heap, which indicates a bug in c_cplusplus_mixing.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while c_cplusplus_mixing.exe has focus.
The output window may have more diagnostic information."
The call stack doesn't seem very meaningful (at least for a novice like myself).
Call Stack:
ntdll.dll!775c542c()
[Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
ntdll.dll!7758fdd0()
ntdll.dll!7755b3fc()
Note, I'm using visual studio 2008 and running Debug build. (Release doesn't work either).
Could anyone please point me to where I'm going wrong! and please let me know if more details are needed.
Many thanks in advance,
Hasan.
The problem is that ExpandArrayOfInts is receiving a pointer to an int instead of a pointer to the pointer that has to reallocate. It should look like this:
int ExpandArrayOfInts(int** arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
and then you would call it like this:
ExpandArrayOfInts(&arrayDnmc, 5, arraySize, &arraySize))
I'd recommend you to look for questions related to pointers in stackoverflow so that you get a better understanding of them.
From the realloc() documentation on my system:
realloc() returns a pointer to the
newly allocated memory, which is
suitably aligned for any kind of
variable and may be different from
ptr, or NULL if the request fails.
Your ExpandArrayOfInts() declaration and implementation does not allow realloc to modify the actual pointer in main() - it implicitly assumes that its value cannot change. When realloc() moves the memory area and does return a different pointer, it calls free() on the pointer it was called with. The rest of your program, though, goes on using the original value which is now invalid, hence the crash.
You should use a pointer-to-a-pointer to pass the memory area pointer by reference, instead:
int ExpandArrayOfInts(int** arrayToExpand, int expandBy, int inArraySize, int* outArraySize)
.
.
.
*arrayToExpand = (int*)realloc(*arrayToExpand, newSize * sizeof(int));

Resources