0

As I know that malloc allocate a specific number of bytes in the memory. However I am trying to use it and I allocate 4 bytes but it gives me NO error when I try to store more than 4 (up to 200 integers) elements in the array!! So in my code I don't need to use realloc!! I'm using Linux by the way. Finally I will pleased to hear any advice from you ... thanks in advance.

tmp.h :

 #ifndef TMP_H
 #define TMP_H

 #define MAXLENGTH 4
 #define GROWFACTOR 1.5

 typedef struct stVector
 {
    int *vec;
    int length;
        int maxLength;
 }Vector; 

 Vector newEmptyVector();
 void addElement(Vector *vec, int elt);

 #endif

tmp.c :

#include "stdio.h"
    #include "stdlib.h"
    #include "tmp.h"


    Vector newEmptyVector()
    {
        Vector vec;
        vec.vec = (int*) malloc(0);
        printf("Allocating %d bytes\n", sizeof(int)*MAXLENGTH );
        vec.length = 0;
        vec.maxLength = MAXLENGTH;
        return vec;
    }


    void addElement(Vector *vec, int elt)
    {
        /*if(vec->length == vec->maxLength)
        {
            vec->vec = (int*)realloc(vec->vec,sizeof(int)* vec->maxLength * GROWFACTOR);
            vec->maxLength = vec->maxLength * GROWFACTOR;
        }*/
        vec->vec[vec->length++] = elt;
    }

main.c :

            #include"tmp.h"
    int main(int argc, char const *argv[])
    {

        Vector vector = newEmptyVector();
        printf("The length is %i and maxlength is                                    `                   `%i\n",vector.length,vector.maxLength);
        addElement(&vector,5);
        addElement(&vector,3);
        addElement(&vector,1);
        addElement(&vector,7);
        printf("The length is %i and maxlength is                                            `                       `%i\n",vector.length,vector.maxLength);
        addElement(&vector,51);
 printf("The length is %i and maxlength is %i\n",vector.length,vector.maxLength);      
        for (int i = 0; i < 200; ++i)
        {
            addElement(&vector,i);
 printf("The length is %i and maxlength is %i\n" ,vector.length, vector.maxLength);                                           
        }
        return 0;
    }
PersianGulf
  • 2,845
  • 6
  • 47
  • 67
Omar Muhtaseb
  • 117
  • 1
  • 3
  • Where does it specify it will crash immediately when you corrupt the heap? – StoryTeller - Unslander Monica Feb 24 '14 at 15:13
  • That's what we call **undefined behavior**. Anything can happen. – user123 Feb 24 '14 at 15:13
  • When you do `malloc(0)` you allocate *zero* bytes. You will get *either* `NULL` or a valid pointer (that you can pass to `free`) in return. If you do get a non-null pointer in return, it points to that zero-sized memory area you allocated, and which you can't use (since it's of size zero). – Some programmer dude Feb 24 '14 at 15:25
  • Also, in C [don't cast the result of `malloc`](http://stackoverflow.com/a/605858/440558). – Some programmer dude Feb 24 '14 at 15:27
  • You should also check the return value of `malloc` and `realloc` to make sure they succeeded. This hilignts a problem with the way you call `realloc` since, if it fails, it will have wiped out your only pointer to the memory. – pat Feb 24 '14 at 15:46

3 Answers3

4

Using memory you haven't allocated invokes undefined behavior. Don't do that. In all likelyhood, Linux has give your program a page of memory, and you haven't overrun that yet. If you touch memory not allocated to your program the OS should cause your program to segfault. But it's possible that any other mallocing you do will also use parts of that page, and you'll end up corrupting your data.

Not having runtime checks for overrunning buffers is part of what makes C fast, but it puts more on the programmer not to do dumb things.

Collin
  • 11,977
  • 2
  • 46
  • 60
4

"I allocate 4 bytes but it gives me NO error when I try to store more than 4".

It is not uncommon, when writing to memory that is not owned by the process for it to quietly happen, with no apparent consequences. But there are consequences lurking. And according to this, anything can happen, and eventually does.

Using an array, created on the heap for simple illustration of UB:

int *anyVar = malloc(10 * sizeof(*anyVar));//create space for 10 int
anyVar[10] = 12; //writing to one memory location beyond space allocated 
                 //immediately invoking undefined behavior  

Writing to memory you do not own invokes undefined behavior.. The bad thing is that your results can seem good, and even repeatable for many runs of the code. But at some point, your code will fail.

Example of memory allocation: (note:cast for malloc() has been removed.)

int numIntsInArray = 100;
int *anyVar = malloc(sizeof(int)*numIntsInArray);
if(anyVar)//test pointers to memory before using 
{
    //zero memory before using
    memset(anyVar, 0, sizeof(int)*numIntsInArray);
    anyVar[0] = 1;//first element of anyVar
    anyVar[numIntsInArray-1] = 1000;//last element of anyVar  

    //Free memory when no longer needed:  
    free(anyVar);
}

The examples of bad code below may result in no compiler warnings, and may seem to run normally, but using them will result in problematic, unpredictable behavior.

char * p = "string"; // Badly formed C++11, deprecated C++98/C++03
p[0] = 'X'; // undefined behavior

Create an array instead:

char p[] = "string"; // Good
p[0] = 'X';

C++, you can create/use a standard string like this:

std::string s = "string"; // Good
s[0] = 'X';

Division by zero results in undefined behavior:

int x = 1;
return x / 0; // undefined behavior

Some pointer operations may lead to undefined behavior:

int arr[4] = {0, 1, 2, 3};
int* p = arr + 5;  // undefined behavior

Leaving a non-void function without returning a value

int func(void)
{
    //undefined behavior    
}

Unspecified or implementation-defined behavior:

printf("%d %d\n", ++n, power(2, n));    //Bad

i = ++i + 1; //Bad

i = i + 1; // Okay
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • In production code avoid magic number indexes like `anyvar[99]` in the 2nd example when referencing allocated memory. Best to use something like `anyvar[numIntsInArray-1]`. – Firstrock Jul 19 '23 at 12:13
  • @Firstrock - Thanks, not sure why I did not do that at first writing. – ryyker Jul 19 '23 at 12:58
  • 1
    Note that the behavior of `malloc(0)` is implementation-defined: it may return a null pointer, or it may return a pointer which may not be used to access an object. Either way the subsequent `anyVar[0] = 12` is undefined behavior. – ad absurdum Jul 19 '23 at 13:06
  • 1
    @adabsurdum - I noticed that poor example when I edited the post a few minutes prior, and almost changed it at that point. Thanks for pushing me over the edge. – ryyker Jul 19 '23 at 13:38
2

The fact that (simply because there is no bound checking in C) no error is raised does not mean that you can safely use memory outside requested bounds. You were lucky not to cause a segmentation fault, you have just fallen into a memory region that is not claimed by your malloc (let's say, it's not yours).

You can write there, but there is no guarantee that you won't be overwriting memory assigned to another malloc or, conversely, that the "extra" part will not be allocated to some other malloc. In your case, the memory region you are writing into appears not to be claimed (yet).

Stefano Sanfilippo
  • 32,265
  • 7
  • 79
  • 80
  • Is the way that I'm using realloc right to avoid any memory problems that would happen?? – Omar Muhtaseb Feb 24 '14 at 15:28
  • @Stepfano can u help me – Omar Muhtaseb Feb 24 '14 at 15:46
  • @OmarMuhtaseb - The way you are using realloc above _ vec->vec = (int*)realloc(vec->vec,sizeof(int)* vec->maxLength * GROWFACTOR);_ looks correct. (except you should not cast the output of malloc, calloc or realloc) But the problem is with your initial call of malloc: vec.vec = (int*) malloc(0); Put a value other than 0 there, at least `sizeof(int)*numOfDesiredInts` – ryyker Feb 24 '14 at 16:33