Realloc on NULL-valued (or undefined) pointer - c

I was reading about realloc and got confused about a point mentioned there. Consider the code below:
#include <stdio.h>
#include <stdlib.h>
int main () {
int* ptr = NULL;
ptr = realloc(ptr, 10*sizeof(int));
return 0;
}
Is there any danger in allocating memory with realloc using the initially NULL-valued ptr? If instead of:
int* ptr = NULL;
I had this:
int* ptr; // no value given to ptr
would it be a problem to call realloc using ptr?

Is there any danger in allocating memory with realloc using the
initially NULL-valued ptr
None
7.22.3.5
If ptr is a null pointer, the realloc function behaves like the malloc
function for the specified size.
For the second part:
int* ptr; // no value given to ptr
would it be a problem to call realloc using ptr?
If you're using uninitialized pointers then that is a very serious problem indeed since you can't predict what their value will be. The function realloc only works correctly for NULL or values obtained from malloc / realloc.
Otherwise, if ptr does not match a pointer earlier returned by a
memory management function [...] the behavior is undefined

With the specific code shown, there is no problem with using the null pointer initially.
If the variable ptr is uninitialized — not set to 0 or NULL — then any call to realloc() using it is dangerous; the behaviour is undefined and if you are lucky, the program will crash, but if you're unlucky, it will appear to work for a while, until something goes wrong later in the program where it will be hard to spot that the trouble is in code executed a long time ago.
There are those who argue it is better to use malloc() for the initial allocation and realloc() thereafter. There is some justice to the suggestion, not least because you probably wouldn't use ptr = realloc(ptr, 0); to free the memory, even though you could do so (so you don't really need malloc() or free() because realloc() can do all three operations). But the C90 standard requires realloc(0, new_size) to work equivalently to malloc(new_size), and I know of no C library that behaves differently (but there might be some; I've only used a few C libraries, albeit mostly the most widely used ones).
However, in a more general case such as the following code, then there is a subtle problem with the code (but it is not to do with the initial null pointer):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
if ((ptr = realloc(ptr, buflen)) == 0) // Danger!
// ... handle memory allocation failure ...
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
What is the danger? The danger is that if the second or a subsequent memory allocation fails and ptr is the only pointer to the allocated memory, you just overwrote its previous value with null. That means you cannot free the allocated memory using ptr any more — you've leaked memory. (For the first allocation, the initial value was 0, the overwritten value was zero, and nothing has changed; there is no memory leak. That's why the loop was added to the code.)
Rule of Thumb
Do not write ptr = realloc(ptr, newsize);
Save the new value into a separate variable until you've tested it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *ptr = NULL;
size_t len = 0;
char buffer[256];
while (fgets(buffer, sizeof(buffer), stdin))
{
size_t buflen = strlen(buffer) + 1;
if (buflen > len)
{
char *new_ptr = realloc(ptr, buflen);
if (new_ptr == 0)
// ... handle memory allocation failure ...
ptr = new_ptr;
len = buflen;
}
strcpy(ptr, buffer);
// ... do something with ptr
}
free(ptr);
return 0;
}
This code does not leak memory on an allocation failure.
Auxilliary recommendation: do not use a variable called new; it will make it difficult to compile with a C++ compiler. Even if you have no intention now of converting to C++ (and even though you would probably end up rewriting the memory management if you do), there's no virtue in using the C++ keyword new as a C variable name...unless you explicitly want to prevent compilation with a C++ compiler.

Is there any danger in allocating memory using realloc using the initially NULL-valued ptr?
No, that would exactly be like a malloc.
If instead of:
int* ptr = NULL;
I had this:
int* ptr; // no value given to ptr
would it be a problem to call realloc using ptr?
Yes, there would be a problem. If realloc doesn't get a NULL, it will try to expand memory starting from that location, or may try to free and malloc another part of memory. Since uninitialized variables can have any value, chances are very high, they are not a value realloc likes. If you are lucky, your program would immediately crash.

Related

What is the right way to define buffer, pass to a function for a dynamic load?

please look at my code below. I was wondering if this the proper way to pass the buffer to a function, fill it, and get it back as a return. Maybe there are some techniques, which I missed as some programmers fill in buffer with zeroes before adding data into it. Apart from that, please do let me know if I have some minor mistakes or issues. Thanks a lot!
#define BUFFER_SIZE 256
void get_data(char *ptr, size_t len)
{
char* temp = (char*)malloc(len * 1);
char sample_data[] = "data";
strcpy(temp, sample_data, sizeof(sample_data));
memcpy_s(ptr, len, temp, len);
free(temp);
}
int main(void)
{
int status = EXIT_SUCCESS;
char* data = (char*)malloc(BUFFER_SIZE * 1);
status = get_data(data, BUFFER_SIZE);
if(status != 0)
return EXIT_FAILURE;
free(data);
return EXIT_SUCCESS;
}
There seems to be quite a few problems.
I guess get_data and fill_data are supposed to be the same function? (But then why is one a void while the other returns status?)
First of all, malloc() can fail and return NULL. Always check the return value of malloc() and ensure the allocation has not failed.
Second, in get_data(), you allocate some memory with char* temp = (char*)malloc(len * 1); and use char *temp to point to it. But then, you effectively throw away that memory and make temp point to the string "fill_data_with_something" instead. In this particular case, the memory allocation within get_data() was completely unnecessary. And the memory that was malloc'd is irrecoverably lost and becomes a memory leak!
Third, you copy 256 bytes from a buffer than contains only "fill_data_with_something" which is definitely smaller than 256. So you are reading beyond the end of the buffer. You should only copy strlen(temp) bytes.
Worst yet, you then try to free() a pointer that is not coming from malloc(). This invokes undefined behaviour.

Implementation improvement on a case switch programme

I can tell that there will be a memory leak on this and am looking for improvements / the standard way of doing things as far as these kind of problems go.
(e.g. how an experienced / pro use on C would implement this)
This is a simple case switch programme. Its purpose is to give it PizZa and give you back pIZza.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char changeCase(char ch){
if ( (int)ch < 65 || (int)ch > 122){
return ch;
}else if ((int)ch < 91){
return (char)(ch + 32);
}
else{
return (char)(ch - 32);
}
}
char* toUpper(char* string){
size_t size=strlen(string);
char* temp = (char*) malloc(size);
while (*string != '\0'){
*temp = changeCase(*string);
temp++;
string++;
}
return (temp - size);
}
int main() {
char* string = toUpper("PIZa");
printf("%s",string);
return 0;
}
This results in a memory leak since the memory from malloc is not freed. What would be better? Allocating memory outside the function and giving the pointer to that memory to the toUpper function? Other idea?
The de facto standard rule is that the part of the code that did the dynamic allocation is also responsible for freeing it. So if your function was in some file "toupper.c", then there should have been some manner of clean-up function available in that same C file.
However, the best solutions separates memory allocation and algorithms. This means that a better way to write this function is this:
void toUpper (char* dst, const char* src)
{
while (*src!= '\0')
{
*dst= ...
...
dst++;
src++;
}
}
Here, the caller can allocate space for dst as it pleases, it's no business of the algorithm. For example:
char str1[] = "hello world";
char* str2 = malloc(strlen(str1) + 1);
toUpper(str2, str1);
...
free(str2);
Just make sure to document the function so that the caller knows that they have to allocate space for dst - to be at least as large as src.
As a side-note, char* temp = (char*) malloc(size); is wrong, you didn't allocate room for the null terminator. Also your algorithm must make sure to copy the null terminator into the destination buffer.
This results in a memory leak since the memory from malloc is not freed.
Actually there is no memory leak in your code. All allocated memory will be freed when the program terminates.
A memory leak occurs in a running program when the program no longer holds a pointer to the allocated memory.
Example:
int main() {
char* string = toUpper("PIZa");
printf("%s",string);
string = toUpper("BRead"); // This causes a memory leak because after this
// line there is no longer any pointer to the
// memory allocated in the first call of toUpper
string = NULL; // Again this causes a memory leak because after this
// line there is no longer any pointer to the
// memory allocated in the second call of toUpper
return 0;
}
Note: Even leaked memory will be freed when the program terminates. Memory leaks are (mainly) a problem in "long" running programs.
What would be better? Allocating memory outside the function ...
Well, it's a matter of taste.
As an example: The widely used (but non-standard) strdup function handles allocation inside the function and requires the caller to free the memory later on.
For a function that reads an unknown amount of characters as user input it can also be nice to do malloc (and realloc as needed) inside the function.
There is really no right or wrong here. You are the designer so you decide. It's all about the "function contract", i.e. the documentation of the function - how to call it and what it will do.

how to free the dynamically allocated memory for a local variable?

Sample program:
#include <stdio.h>
#include <malloc.h>
void f(int n) {
char *val = (char *) malloc(12*sizeof(char));
val = "feels....";
printf("%s", val);
// free val; // if enable, compile time error: expected ';' before 'val' free val;
}
int main()
{
f(1);
return 0;
}
Is it required to free the memory which is dynamically allocated ? if yes, how to.
Yes, you need to free the memory. But when you allocate memory for a string, the way to populate the string is not to assign a string to it as that replaces the memory you've allocated. Instead you're meant to use the function strcpy like this...
char *val = malloc(12*sizeof(char));
strcpy(val,"feels....");
printf("%s", val);
free(val);
Instead of this:
char *val = (char *) malloc(12*sizeof(char));
val = "feels...."; // val points now to the string literal ""feels...."
// discarding the value returned by malloc
...
free(val); // attempt to free the string literal which will
// result in undefined behaviour (most likely a crash)
you probably want this:
char *val = malloc(12*sizeof(char)); // in C you don't cast the return value of malloc
strcpy(val, "feels...."); // the string "feels...." will be copied into
// the allocated buffer
...
free(val); // free memory returned previously by malloc
The compilation problem is because free is a function, you need to put its argument in parentheses.
free(val);
The other problem is a memory leak.
Strings in C are really just pointers to (hopefully) blocks of memory containing char data. The end of the string is denoted by a char with value 0. The thing to remember is that your variable is simply a pointer like any other pointer. So...
char *val = (char *) malloc(12*sizeof(char));
The above line dynamically allocates a block of memory and assigns a pointer to it to val.
val = "feels....";
The above line assigns a pointer to a string literal to val overwriting the previous pointer that was in val. It has not touched, in any way, the block of memory that was malloced in the first line. Furthermore, you have lost any reference you had to the malloced block so it has leaked. There's no way to free it.
String literals are usually created at compile time and the memory they occupy will be part of the program. This means they haven't come from the heap (where malloc gets its memory from. This means, in turn, when you try to free a string literal, bad things happen. On modern architectures, the program text is protected from writes at the OS level so trying to free part of it will almost certainly crash your program.
As long as you do not want to change the content of the string, you do not need to malloc space to it. You can omit the malloc line (and the corresponding free) and your program will still work.
f you do want to change the string, the easiest way to get a mutable copy of a string literal is to use strdup:
char *val = strdup("feels....");
// Do stuff with the string
free(val); // strdup strings need to be freed
strdup is a Posix function but not a C standard function so your platform might not have it. It's pretty simple to implement your own, though.
char* myStrDup(const char* thingToDup)
{
char* ret = malloc(strlen(thingToDup) + 1); // strlen returns the length without the terminating nul. Hence add 1 to it to allocate
strcpy(ret, thingToDup); // Copies the entire string including the terminating nul.
return ret;
}

Pointers and malloc.... Wrong in this code snippet

#include <stdio.h>
#include <stdlib.h>
int main()
{
int *ptr = NULL;
ptr = (int*)malloc(2*sizeof(int*));//memory allocation dynamically
return 0;
}// What is the error in this type of allocation
I guess you want allocate the space for 2 ints (not 2 pointers to int):
int *ptr = malloc(2*sizeof(int));//memory allocation dynamically
You would have understood that if you read the compilation error carefully.
int *ptr = NULL;
ptr = (int*)malloc(2*sizeof(int*)); //wrong
The above code is wrong. It should be:
ptr = malloc(2*sizeof(*ptr));
No need to cast the return value of malloc. void * will be safely casted. Additionally, using sizeof(*ptr) is easier to maintain in case ptr's data type needs to be modified.
Also, free dynamically allocated memory when its no longer needed or you will have memory leak.
free(ptr);
The problem lies at sizeof(int*)) and it should be sizeof(int))
Dynamic allocation requires you to tell what size of bytes you want it to allocate, and for that reason in this example you should use sizeof(int).

I have debug it for 4 hours,but I still can't find the BUG

This is program is input some string from a file, then, push strings into LineBuf one by one, after we push one string into LineBuf, print LineBuf,then, make LineBuf empty.
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *LineBuf = NULL;
int BufLen = 0;
void PushToBuf(char c)
{
LineBuf = (char *)realloc(LineBuf, (BufLen+2)*sizeof(char));
LineBuf[BufLen] = c;
BufLen++;
LineBuf[BufLen] = '\0';
}
int main()
{
char temp[20];
int i;
FILE *fp;
fp = fopen("input", "r");
while (fgets(temp, 20, fp) > 0)
{
/*Push temp into buf*/
for (i = 0; i < strlen(temp); i++)
PushToBuf(temp[i]);
/*print buf*/
printf("%s\n", LineBuf);
printf("%d\n", BufLen);
/*make buf empty*/
free(LineBuf);
BufLen = 0;
}
return 0;
}
This is my input stream:
This is a test. Good evening
bye~
This is run result:
This is a test file
19
. Good evening
15
glibc detected ./a.out: double free or corruption (fasttop): 0x00000000023fa250
======= Backtrace: =========
/lib/libc.so.6(+0x775b6)[0x7f2ad01bf5b6]
/lib/libc.so.6(cfree+0x73)[0x7f2ad01c5e83]
./a.out[0x400868]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f2ad0166c4d]
./a.out[0x400699]
How realloc ( void * ptr, size_t size ) works:
The size of the memory block pointed to by the ptr parameter is
changed to the size bytes, expanding or reducing the amount of memory
available in the block. The function may move the memory block to a new location, in which
case the new location is returned.
In case that ptr is NULL, the function behaves exactly as malloc,
assigning a new block of size bytes and returning a pointer to the
beginning of it.
In your case the pointer is already freed, but still isn't NULL, so when the program tries to move this memory block, it causes memory corruption.
To solve it, you should do one of the following:
Remove free().
Use malloc instead of realloc.
Set LineBuf to NULL after free().
This does not make LineBuf empty. It free the storage space for LineBuf. When you later realloc LineBuff it attemps to realloc freed space.
/*make buf empty*/
free(LineBuf);
to solve the provlem move the free out of the while loop. and empty free buff byt setting all of the data it stores to null.
for(int i =0; i < BuffLen)
LineBuf[i]='\0';
You're trying to realloc a free'd pointer; you can't do that!
free(LineBuf) is freeing the memory, but you are using LineBuf again later when calling realloc. You should set LineBuf to NULL after freeing it, then the realloc will do malloc and not reallocate. Keep in mind, it is always good practice to set pointers to NULL after freeing them. This helps detect if you are using pointers to freed memory.
BTW, looking at your code I am not quite sure what you intend to do. Depending on what you want to do you might get rid of LineBuf or of fgets. Also: calling strlen for every i is not very performant, you might better check for temp[i] != '\0'.

Resources