Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am simply testing what would be the output if I try to dereference a pointer, which points to out of range of dynamically created memory using calloc() and expecting memory fault or some garbage value instead. It is giving 0 as output, which is basic feature of calloc() that it intializes allocated memory with '0', or is it just due to undefined behavior?
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = NULL;
p = (int *)calloc(10, 8);
if(p != NULL)
{
printf("\n successfully allocated memory ");
}
else
EXIT_FAILURE;
printf("\n Thirty first element of memory is %d \n",p[30]);
}
Result :
successfully allocated memory
Thirty first element of memory is 0
You are trying to access p + 30 * sizeof(int) which is p + 120 while you have allocated only 8 * 10 = 80 bytes, so max address you can access is p[19]
From a language perspective, accessing out of bounds memory is undefined behavior, meaning that anything can happen.
One possible explanation for that particular behavior is that most operating systems will zero out any memory before they give it to your process, independently of what function you where using internally (this is a security measure, so you can't read data that was used by other processes).
To get garbage data, you usually have to have used and freed the same memory before inside your program (in which case it retains its old value). Or of course, if your index is so far off that you are indexing into a neighboring data structure.
The reason your program didn't just crash is that malloc (and similar functions) usually request much more memory from the os, than what you are requiring and use the surplus memory the next time you call malloc. So from the OS perspective you are accessing valid memory, and there is no reason to terminate your program.
Accessing out of range memory is Undefined Behaviour. Hence the value which you get can be 0 or 1 or Batman
The point is, you cannot ask any explanation or reason for things that are undefined. Anything can happen in such a scenario.
Also, you would get a seg fault if you try to access a memory location which your program is not allowed to access. That may not be the case always when you access out of bounds memory. It can lie well inside the user memory area of the program.
I think windows zeroes a freed page before making available for allocation. Have fun with the code below.
#include<stdio.h>
#include<stdlib.h>
#include <windows.h>
#include <signal.h>
int g = 0;
unsigned long long* p=NULL;
void signal_handler(int ssc)
{
printf("Error %d \n", ssc);
printf("segfault after %llu bytes",g*8);
printf("should i go backwards? press enter");
getch();
g=0;
do
{
printf("Virtual Adress:%llu is %llu\n",p+g,*(p+g) );
Sleep(1);
g--;
}
while(1);
}
int main ()
{
if(SIG_ERR == signal(SIGSEGV, signal_handler) ) {printf("error seting signal handler %d\n",SIGSEGV);}
p = (unsigned long long*)calloc(10,8);
if( p!= NULL)
{
printf("successfully allocated memory\n");
}
else
{
EXIT_FAILURE;
}
do
{
printf("Virtual Adress:%llu is %llu\n",p+g,*(p+g) );
Sleep(2);
g++;
}
while(1);
return 0;
}
Related
I know that on your hard drive, if you delete a file, the data is not (instantly) gone. The data is still there until it is overwritten. I was wondering if a similar concept existed in memory. Say I allocate 256 bytes for a string, is that string still floating in memory somewhere after I free() it until it is overwritten?
Your analogy is correct. The data in memory doesn't disappear or anything like that; the values may indeed still be there after a free(), though attempting to read from freed memory is undefined behaviour.
Generally, it does stay around, unless you explicitly overwrite the string before freeing it (like people sometimes do with passwords). Some library implementations automatically overwrite deallocated memory to catch accesses to it, but that is not done in release mode.
The answer depends highly on the implementation. On a good implementation, it's likely that at least the beginning (or the end?) of the memory will be overwritten with bookkeeping information for tracking free chunks of memory that could later be reused. However the details will vary. If your program has any level of concurrency/threads (even in the library implementation you might not see), then such memory could be clobbered asynchronously, perhaps even in such a way that even reading it is dangerous. And of course the implementation of free might completely unmap the address range from the program's virtual address space, in which case attempting to do anything with it will crash your program.
From a standpoint of an application author, you should simply treat free according to the specification and never access freed memory. But from the standpoint of a systems implementor or integrator, it might be useful to know (or design) the implementation, in which case your question is then interesting.
If you want to verify the behaviour for your implementation, the simple program below will do that for you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The number of memory bytes to test */
#define MEM_TEST_SIZE 256
void outputMem(unsigned char *mem, int length)
{
int i;
for (i = 0; i < length; i++) {
printf("[%02d]", mem[i] );
}
}
int bytesChanged(unsigned char *mem, int length)
{
int i;
int count = 0;
for (i = 0; i < MEM_TEST_SIZE; i++) {
if (mem[i] != i % 256)
count++;
}
return count;
}
main(void)
{
int i;
unsigned char *mem = (unsigned char *)malloc(MEM_TEST_SIZE);
/* Fill memory with bytes */
for (i = 0; i < MEM_TEST_SIZE; i++) {
mem[i] = i % 256;
}
printf("After malloc and copy to new mem location\n");
printf("mem = %ld\n", mem );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
free(mem);
printf("\n\nAfter free()\n");
printf("mem = %ld\n", mem );
printf("Bytes changed in memory = %d\n", bytesChanged(mem, MEM_TEST_SIZE) );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
}
This question already has answers here:
Initially mallocate 0 elements to later reallocate and measure size
(2 answers)
Closed 6 years ago.
Below code is just an example which I use to come to the point later:
/* Extract digits from an integer and store in an array in reverse order*/
#include<stdio.h>
#include<stdlib.h>
int main(void)
{
int oct=316;
int* array=malloc(0*sizeof(int*)); //Step 1
int* temp;
size_t size=0;
while(oct/10>0 || oct%10>0){
temp=realloc(array,++size*sizeof(int)); // Step2 requires Step1
if(temp==NULL){
printf("Can't reallocate memory");
exit(-1);
}
else{
array=temp;
}
array[size-1]=oct%10;
oct/=10;
}
for(int i=0;i<size;i++)
printf("%d\n",array[i]);
return 0;
}
The realloc reference [1] states :
Reallocates the given area of memory. It must be previously allocated
by malloc(), calloc(), realloc()...
Initially I compiled the code without step1 and on running it I got a segmentation fault. Then I included step1, now the code compiles fine. I don't want to allocate some space without finding an integer to store so I have used a size of zero with malloc. However malloc reference [2] states :
If size is zero, the return value depends on the particular library
implementation (it may or may not be a null pointer), but the returned
pointer shall not be dereferenced.
Now, I doubt my implementation is portable. How can I work around this issue?
I tried doing int* array=NULL; but I got a segmentation fault.
You can initiate array to NULL. In the man page for realloc(void *ptr, size_t size) you can read:
If ptr is NULL, then the call is equivalent to malloc(size)
Moreover realloc does not change its parameter. It returns pointer to newly allocated/reallocated space. So, for reallocating you shall use a code like:
array = realloc(array,(++size)*sizeof(int));
if (array == NULL) { some error; }
I'm creating a source files containing buffer functionality that I want to use for my other library that I'm creating.
It is working correctly but I'm having trouble getting rid of the buffer structure that I'm creating in one of the functions. The following snippets should help illustrate my problem:
C header:
//dbuffer.h
...
typedef struct{
char *pStorage;
int *pPosition;
int next_position;
int number_of_strings;
int total_size;
}DBUFF;
...
C source:
//dbuffer.c
...
DBUFF* dbuffer_init(char *init_pArray)
{
//Find out how many elements the array contains
int size = sizeof_pArray(init_pArray);
//Initialize buffer structure
DBUFF *buffer = malloc(sizeof(DBUFF));
//Initialize the storage
buffer->pStorage = malloc( (sizeof(char)) * (size) );
strncpy( &(buffer->pStorage)[0] , &init_pArray[0] , size);
buffer->number_of_strings = 1;
buffer->total_size = size;
buffer->next_position = size; //size is the next position because array allocates elements from 0 to (size-1)
//Initialize the position tracker which keeps record of starting position for each string
buffer->pPosition = malloc(sizeof(int) * buffer->number_of_strings );
*(buffer->pPosition + (buffer->number_of_strings -1) ) = 0;
return buffer;
}
void dbuffer_destroy(DBUFF *buffer)
{
free(buffer->pStorage);
free(buffer);
}
...
Main:
#include <stdio.h>
#include <stdlib.h>
#include "dbuffer.h"
int main(int argc, char** argv)
{
DBUFF *buff;
buff = dbuffer_init("Bring the action");
dbuffer_add(buff, "Bring the apostles");
printf("BUFFER CONTENTS: ");
dbuffer_print(buff);
dbuffer_destroy(buff);
// Looks like it has been succesfully freed because output is garbage
printf("%s\n", buff->pStorage);
//Why am I still able to access struct contents after the pointer has been freed ?
printf("buff total size: %d\n", buff->total_size);
return (EXIT_SUCCESS);
}
Output:
BUFFER CONTENTS: Bring the action/0Bring the apostles/0
��/�
buff total size: 36
RUN SUCCESSFUL (total time: 94ms)
Question:
Why am I still able to access struct contents using the line below after the pointer to the struct has been freed ?
printf("buff total size: %d\n", buff->total_size);
Once you've called free() on the allocated pointer, attempt to make use of the pointer invokes undefined behavior. You should not be doing that.
To quote C11 standard, chapter §7.22.3.4, free() function
The free() function causes the space pointed to by ptr to be deallocated, that is, made
available for further allocation. [..]
It never say's anything about a cleanup, which you might be (wrongly) expecting.
Just to add clarity, calling free() does not always actually free up the allocated physical memory. It just enables that pointer (memory space) to be allocated again (returning the same pointer, for example) for successive calls to malloc() and family. After calling free(), that pointer is not supposed to be used from your program anymore but C standard does not guarantee of a cleanup of the allocated memory.
If any attempt is made to read memory that has been freed can crash your program. Or they might not. As far as the language is concerned, its undefined behaviour.
Your compiler won't warn you about it(or stop you from accessing it). But clearly don't do this after calling free -
printf("buff total size: %d\n", buff->total_size);
As a good practice you can set the freed pointer to NULL .
free() call will just mark the memory in heap as available for use. So you still have the pointer pointing to this memory location but it's not available anymore for you. Thus, the next call to malloc() is likely to assign this memory to the new reservation.
To void this situations normally once you free() the memory allocated to a pointer you should set it to NULL. De-referencing NULL is UB also but at least when debugging you can see tha pointer should not be used because it's not pointing to a valid memory address.
[too long for a comment]
To allow your "destructor" to set the pointer passed to NULL modify your code like this:
void dbuffer_destroy(DBUFF ** buffer)
{
if ((NULL == buffer) || (NULL == *buffer))
{
return;
}
free((*buffer)->pPosition);
free((*buffer)->pStorage);
free(*buffer);
*buffer = NULL;
}
and call it like this:
...
dbuffer_destroy(&buff);
...
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
We assume that there are 200 bytes of memory in our processor.
Here's the code:
#include <stdlib.h>
char * p;
char data;
void test1()
{
p = (char *)malloc(sizeof(char) * 300);
p[0] = 1;
}
void test2()
{
p = (char *)malloc(sizeof(char) * 300);
data = p[5];
}
When I run the "test1()", obviously there will be a memory overflow. However "test2()" will not. Does the compiler optimized the memory in "test2()" ? How?
And there's another strange problem:
void test3()
{
char ele[1000]={0};
}
void test4()
{
char ele[1000];
ele[999] = 10;
}
The "test3()" will cause memory overflow, and "test4()" will not.
Sorry for my bad English,and thank you for your answer.
======================================================
Finally,I figure that out. I checked the assembly code, in “test3” it allocated memory indeed.But in "test4" ,the compiler optimized the array, does not allocated memory for it.
Thanks #Philipp,Thanks all.
When malloc fails because it can't allocate enough memory, it won't crash. It will return the memory address 0 instead.
When you neglect checking the return-value and treat that value as an array, you can still read from it. The reason is that the operator [5] means basically as much as "start from that address, move 5 steps ahead in memory, and read from there". So when p is 0, and you do data = p[5];, you read whatever is at memory address 5. This isn't the memory you allocated - it's whatever is in memory at that location.
But when you try to write something to p[0], you are trying to write to memory address 0 which is not allowed and will lead to a runtime error.
Bottom-line: Whenever you do malloc, check the return value. When it's 0, the memory allocation has failed and you have to deal with that.
When you request a memory allocation which is greater than available memory, malloc() simply returns NULL. For checking this just add error checking to your code like,
#include <stdlib.h>
char * p;
char data;
void test1()
{
p = (char *)malloc(sizeof(char) * 300);
if(p == NULL)
{
printf("Failed to allocate memory\n");
return -1;
}
p[0] = 1;
}
void test2()
{
p = (char *)malloc(sizeof(char) * 300);
if(p == NULL)
{
printf("Failed to allocate memory\n");
return -1;
}
p[0] = 1;
data = p[5];
}
The above calls simply returns error in your case.
I know that on your hard drive, if you delete a file, the data is not (instantly) gone. The data is still there until it is overwritten. I was wondering if a similar concept existed in memory. Say I allocate 256 bytes for a string, is that string still floating in memory somewhere after I free() it until it is overwritten?
Your analogy is correct. The data in memory doesn't disappear or anything like that; the values may indeed still be there after a free(), though attempting to read from freed memory is undefined behaviour.
Generally, it does stay around, unless you explicitly overwrite the string before freeing it (like people sometimes do with passwords). Some library implementations automatically overwrite deallocated memory to catch accesses to it, but that is not done in release mode.
The answer depends highly on the implementation. On a good implementation, it's likely that at least the beginning (or the end?) of the memory will be overwritten with bookkeeping information for tracking free chunks of memory that could later be reused. However the details will vary. If your program has any level of concurrency/threads (even in the library implementation you might not see), then such memory could be clobbered asynchronously, perhaps even in such a way that even reading it is dangerous. And of course the implementation of free might completely unmap the address range from the program's virtual address space, in which case attempting to do anything with it will crash your program.
From a standpoint of an application author, you should simply treat free according to the specification and never access freed memory. But from the standpoint of a systems implementor or integrator, it might be useful to know (or design) the implementation, in which case your question is then interesting.
If you want to verify the behaviour for your implementation, the simple program below will do that for you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* The number of memory bytes to test */
#define MEM_TEST_SIZE 256
void outputMem(unsigned char *mem, int length)
{
int i;
for (i = 0; i < length; i++) {
printf("[%02d]", mem[i] );
}
}
int bytesChanged(unsigned char *mem, int length)
{
int i;
int count = 0;
for (i = 0; i < MEM_TEST_SIZE; i++) {
if (mem[i] != i % 256)
count++;
}
return count;
}
main(void)
{
int i;
unsigned char *mem = (unsigned char *)malloc(MEM_TEST_SIZE);
/* Fill memory with bytes */
for (i = 0; i < MEM_TEST_SIZE; i++) {
mem[i] = i % 256;
}
printf("After malloc and copy to new mem location\n");
printf("mem = %ld\n", mem );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
free(mem);
printf("\n\nAfter free()\n");
printf("mem = %ld\n", mem );
printf("Bytes changed in memory = %d\n", bytesChanged(mem, MEM_TEST_SIZE) );
printf("Contents of mem: ");
outputMem(mem, MEM_TEST_SIZE);
}