0

I already don't know what to think or what to do. Next code compiles fine in both IDEs, but in VC++ case it causes weird heap corruptions messages like:
"Windows has triggered a breakpoint in Lab4.exe.

This may be due to a corruption of the heap, which indicates a bug in Lab4.exe or any of the DLLs it has loaded.

This may also be due to the user pressing F12 while Lab4.exe has focus.

The output window may have more diagnostic information."

It happens when executing Task1_DeleteMaxElement function and i leave comments there.
Nothing like that happens if compiled in Borland C++ 3.1 and everything work as expected.

So... what's wrong with my code or VC++?

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <memory.h>

void PrintArray(int *arr, int arr_length);
int Task1_DeleteMaxElement(int *arr, int arr_length);

int main()
{
    int *arr = NULL;
    int arr_length = 0;

    printf("Input the array size: ");
    scanf("%i", &arr_length);

    arr = (int*)realloc(NULL, arr_length * sizeof(int));

    srand(time(NULL));

    for (int i = 0; i < arr_length; i++)
        arr[i] = rand() % 100 - 50;

    PrintArray(arr, arr_length);

    arr_length = Task1_DeleteMaxElement(arr, arr_length);

    PrintArray(arr, arr_length);

    getch();

    return 0;
}

void PrintArray(int *arr, int arr_length)
{
    printf("Printing array elements\n");

    for (int i = 0; i < arr_length; i++)
        printf("%i\t", arr[i]);

    printf("\n");
}

int Task1_DeleteMaxElement(int *arr, int arr_length)
{
    printf("Looking for max element for deletion...");

    int current_max = arr[0];

    for (int i = 0; i < arr_length; i++)
        if (arr[i] > current_max)
            current_max = arr[i];

    int *temp_arr = NULL;
    int temp_arr_length = 0;

    for (int j = 0; j < arr_length; j++)
        if (arr[j] < current_max)
        {
            temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int)); //if initial array size more then 4, breakpoint activates here
            temp_arr[temp_arr_length] = arr[j];
            temp_arr_length++;
        }


    arr = (int*)realloc(arr, temp_arr_length * sizeof(int));
    memcpy(arr, temp_arr, temp_arr_length);
    realloc(temp_arr, 0); //if initial array size is less or 4, breakpoint activates at this line execution

    return temp_arr_length;
}
Johan
  • 74,508
  • 24
  • 191
  • 319
Kosmo零
  • 4,001
  • 9
  • 45
  • 88
  • 1
    It is *Windows* that reminds you that you have heap corruption bugs, not VS. BC3 uses its own heap allocator so Windows can't see your code mis-behaving. Not noticing these bugs before is pretty remarkable but not entirely impossible. – Hans Passant May 18 '12 at 09:42
  • @Hans Passant: Are you sure about Windows? I thought it was the C/C++ runtime that detected those errors... Mhmm... I guess you're right, but then, it means that upgrading Windows' version could well lead to a crash that didn't happen before in an application... In the other hand (I'll need to verify that), I throught `malloc` and `new` had their own allocators, and this was the reason why when compiling with /MT, you couldn't deallocate a pointer in a DLL when it had been allocated in another DLL. – paercebal May 18 '12 at 09:54

3 Answers3

3

My guess is VC++2010 is rightly detecting memory corruption, which is ignored by Borland C++ 3.1.

How does it work?

For example, when allocating memory for you, VC++2010's realloc could well "mark" the memory around it with some special value. If you write over those values, realloc detects the corruption, and then crashes.

The fact it works with Borland C++ 3.1 is pure luck. This is a very very old compiler (20 years!), and thus, would be more tolerant/ignorant of this kind of memory corruption (until some random, apparently unrelated crash occurred in your app).

What's the problem with your code?

The source of your error:

temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int))

For the following temp_arr_length values, in 32-bit, the allocation will be of:

  • 0 : 4 bytes = 1 int when you expect 1 (Ok)
  • 1 : 5 bytes = 1.25 int when you expect 2 (Error!)
  • 2 : 6 bytes = 1.5 int when you expect 3 (Error!)

You got your priotities wrong. As you can see:

temp_arr_length + 1 * sizeof(int)

should be instead

(temp_arr_length + 1) * sizeof(int)

You allocated too little memory,and thus wrote well beyond what was allocated for you.

Edit (2012-05-18)

Hans Passant commented on allocator diagnostics. I took the liberty of copying them here until he writes his own answer (I've already seen coments disappear on SO):

It is Windows that reminds you that you have heap corruption bugs, not VS. BC3 uses its own heap allocator so Windows can't see your code mis-behaving. Not noticing these bugs before is pretty remarkable but not entirely impossible.

[...] The feature is not available on XP and earlier. And sure, one of the reasons everybody bitched about Vista. Blaming the OS for what actually were bugs in the program. Win7 is perceived as a 'better' OS in no small part because Vista forced programmers to fix their bugs. And no, the Microsoft CRT has implemented malloc/new with HeapAlloc for a long time. Borland had a history of writing their own, beating Microsoft for a while until Windows caught up.

[...] the CRT uses a debug allocator like you describe, but it generates different diagnostics. Roughly, the debug allocator catches small mistakes, Windows catches gross ones.

I found the following links explaining what is done to memory by Windows/CRT allocators before and after allocation/deallocation:

The last link contains a table I printed and always have near me at work (this was this table I was searching for when finding the first two links... :- ...).

Community
  • 1
  • 1
paercebal
  • 81,378
  • 38
  • 130
  • 159
  • 1
    Yes, the CRT uses a debug allocator like you describe, but it generates different diagnostics. Roughly, the debug allocator catches small mistakes, Windows catches gross ones. – Hans Passant May 18 '12 at 10:11
  • @Hans Passant: Please, could you provide a full answer containing your comments? I'll copy-paste them in my answer for info purposes, but it does feel wrong, as **you** should reap the benefits of that knowledge, not me. For now, I'll copy paste your answers in my comment, and as soon as I'll see you answer, I'll replace the comments I copy/pasted by a link to your answer. Thanks! – paercebal May 18 '12 at 17:14
1

If it is crashing in realloc, then you are over stepping, the book keeping memory of malloc & free.

The incorrect code is as below:

temp_arr = (int*)realloc(temp_arr, temp_arr_length + 1 * sizeof(int));

should be

temp_arr = (int*)realloc(temp_arr, (temp_arr_length + 1) * sizeof(int));

Due to operator precedence of * over +, in the next run of the loop when you are expecting realloc to passed 8 bytes, it might be passing only 5 bytes. So, in your second iteration, you will be writing into 3 bytes someone else's memory, which leads to memory corruption and eventual crash.

Jay
  • 24,173
  • 25
  • 93
  • 141
1

Also

memcpy(arr, temp_arr, temp_arr_length);

should be

memcpy(arr, temp_arr, temp_arr_length * sizeof(int) );
tomato
  • 747
  • 5
  • 11