Can incrementing a pointer cause leaked memory? - c

Does the following code contain a memory leak of the first three characters in the string?
char * str = (char*)malloc(21 * sizeof(char));
strcpy(str, "01234567890123456879");
str = str + 3;
free(str);
Thanks.

Its worse than a leak, you are not supposed to call free with a pointer not returned from malloc (or realloc/calloc). You could get a leak, or a crash, or who knows what else... What you do is undefined behavior.

Yes, It leaks.
free expects a pointer that was returned by malloc/realloc/calloc. Since, you have changed, it certainly leaks.

You might want to prove this out by testing, but I believe the answer to your question is that incrementing a pointer can cause undefined behaviour, although you are seeing a memory leak.
I am saying this, because nowhere in your example does it appear that you have preserved the original pointer to the allocated memory. It is possible free could do the wrong thing with the pointer pointing to somewhere other than the base address.
To be sure you would need to
1) Look at RAM in use on your system, with as little else running as possible
2) Run the program a few times, and
3) Then look at memory use again.
Then try all that again by altering your code as follows:
char * mem_ptr = (char*)malloc(21 * sizeof(char));
char * str = mem_ptr;
strcpy(str, "01234567890123456879");
str = str + 3;
free(mem_ptr);

Related

Understanding results with valgrind

For the following code I have the following defintion:
typedef struct string {char* data; int length;} string;
If I run the following code with valgrind, I got conditional jump or move depends on unitinialized value and seg. fault:
string* s = (string*) malloc(sizeof(string));
strcpy("Hello", s->data);
free(s);
First of all, I can't understand why I got above errors.
I thought if I add to that code free(s->data) it will freed memory but program will run ok.
How I think:
I know sizeof(string) equal to 4(pointer to char) + 4(int) = 8.
then we allocate 8 bits for s.
strcpy will copy the string into data but I got a problem here. why?
There are multiple problems:
string* s = (string*) malloc(sizeof(string));
which should better be
string* s = malloc(sizeof(*s));
allocates memory for s->data, but does not make s->data point to any valid memory location. If you want to make use of the memory location, you need to make sure that it points to a valid memory location. For example: you'd need to malloc() for s->data seperately.
That said, the syntax for strcpy() says, it's strcpy(dest, source), so in your case
strcpy("Hello", s->data);
attempts to
read from an unitilized memory location
write into a string literal
either of which invokes undefined behaviour.
You should write
strcpy(s->data, "Hello");
after ensuring s->data is a valid destination.

Is it risky to use freed memory

Suppose I have a char pointer which points to some string in memory.
and suppose I want to copy that string to some other place in memory.
void cpy(char **dst, char *src)
{
*dst = (char *) realloc(*dst, strlen(src) + 1);
memcpy(*dst, src, strlen(src) + 1);
}
(Assume memory allocation is successful, and src is not NULL)
What if I call this function like this:
char *str = malloc(14);
memcpy(str,"hello, world!", 14);
cpy(&str,str+7);
Now I would expect srt to point to the string "world!" (Which it does in my tests).
But what concerns me is that in this call to cpy, *dst and src actually point to different locations of the same string. And, when calling realloc on *dst, it's possible that this memory will be freed. But in the next line I'm trying to copy from that place with memcpy.
So the questions is: Is there something wrong with it?
Or to put it another way - is it okay to free memory, and use it immediately afterwards?
Thanks.
Note: The example was updated so that realloc is called on memory that was obtained with malloc.
Everything is wrong with this. It is outright undefined behaviour to call realloc on a pointer that was not obtained with malloc etc.
As #Daniel Fischer points out, it is also undefined behaviour to use memcpy on overlapping regions of memory (in which case you should use memmove), so you have to be careful.
Update: After your substantial edit, the question is quite different. It is now equivalent to this condensed version:
char * s = malloc(14);
strcpy(s, "hello, world!");
char * p = realloc(s, 14);
memcpy(p, s, 14);
This is also undefined behaviour, because you are not allowed to access the memory pointed to by s anymore after a successful realloc, and you're not allowed to access the memory pointed to by p after an unsuccessful realloc.
The implicit assumption in your example is that it is permitted for cpy to free memory it didn't allocate. It's kind of a dodgy assumption, but as long it's intentional, that's OK. Use malloc and free separately rather than realloc in that case:
void cpy(char **dst, char *src)
{
// obtain completely new memory (realloc might do this anyway)
char* new = malloc(strlen(src) + 1);
// duplicate the string
memcpy(new, src, strlen(src) + 1);
// release the original memory now that we know we are done with it
free(*dst);
// indicate where to find the new string
*dst = new;
}
This still isn't a great idea, because there's no way to know what other variables might be pointing at that memory that you're freeing, but if you have a way to make that guarantee, this is the kind of code you need.

pointers to structs in c

struct TokenizerT_ {
char* separators;
char* tks;
char* cur_pos;
char* next;
};
typedef struct TokenizerT_ TokenizerT;
TokenizerT *TKCreate(char *separators, char *ts)
{
TokenizerT *tokenizer;
tokenizer = (TokenizerT*)malloc(sizeof(TokenizerT));
//some manipulation here
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks=str;
printf("size of tokenizer->tks is %zu\n", strlen(tokenizer->tks)); //this prints out the correct number (e.g. 7)
return tokenizer;
}
int main(int argc, char **argv)
{
TokenizerT *tk = TKCreate(argv[1], argv[2]);
printf("tk->tks: %zu\n", strlen(tk->tks)); //HOWEVER, this prints out the wrong number (e.g. 1)
}
As seen from the above code, I'm working with pointers to structs. For some reason I am not receiving back the correct length for tk->tks. I cannot understand this because it should be the same size as tks in my TKCreate function. Can someone explain this please?
I suspect str, the definition of which is not shown in your code snippet, is a local variable defined in TKCreate(). If so, you're assigning tokenizer->tks to have the value of str, which points to a proper string inside the scope of TKCreate() but upon exiting TKCreate(), the stack contents (including parameters and local variables) are freed and wiped out so when you try to reference that pointer outside the scope of TKCreate() all bets are off.
One plausible fix is to allocate the storage for tokenizer->tks dynamically, so it persists after you exit TKCreate(). I see you do that with a call to malloc but then you overwrite that with an explicit assignment from str. Instead you should copy the contents of str (using strcpy) into the dynamically allocated memory via: strcpy(tokenizer->tks, str);
You should strcpy the contents of str to tokenizer->tks, because when you use the assign operator, you're losing the pointer malloc gave you, creating a memory leak and pointing tokenizer->tks to a local variable, which will be destroyed after the function's return.
So, the approach would be something like this:
tokenizer->tks = (char *)malloc ((strlen(str) + 1) * sizeof(char));
strcpy(tokenizer->tks, str);
Another thing:
Don't forget to free ->tks before you free tk itself.
So, after the printf, you should use:
free(tk->tks);
free(tk);
There's no problem in not freeing the structure and the string (which is in another memory location and not inside the structure's memory space, that's why you have to free they both), if your program is that small, because after it's executed, the program's memory will be wiped out anyways. But if you intend to implement this function on a fully-working and big program, freeing the memory is a good action.
It is not clear where str is defined, but if it is a local variable in the function, your problem is likely that it goes out of scope, so the data gets overwritten.
You're leaking memory because you've forgotten to use strcpy() or memcpy() or memmove() to copy the value in str over the allocated space, and you overwrite the only pointer to the newly allocated memory with the pointer str. If you copied, you would be writing out of bounds because you forgot to allocate enough space for the trailing null as well as the string. You should also check that the allocation succeeds.
Bogus code:
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks = str;
Fixed code:
size_t len = strlen(str) + 1;
tokenizer->tks = (char *)malloc(len);
if (tokenizer->tks == 0)
...error handling...
memmove(tokenizer->tks, str, len);
Using memmove() or memcpy() can outperform strcpy() handily (see Why is Python faster than C for some illustrations and timing). There are those who would excoriate you (and me) for using the cast on malloc(); I understand why they argue as they do, but I don't fully agree with them (and usually use the cast myself). Since sizeof(char) is 1 by definition, there's no particular need to multiply by it, though there's no harm done in doing so, either.

I am still confused with free() and malloc()

In the below program, as far as in my knowledge once we allocate some memory then if we are chaging the address from
ptr to ptr++, then when we are calling free with ptr i.e free(ptr).
Then the program should crash.
But in this program works fine.
How it works?
I am using Code::Bocks in Windows XP.
Please help me.
int main()
{
int *ptr;
ptr = malloc(1);
*ptr = 6;
printf("The value at *ptr = %d \n", *ptr);
ptr++; //Now ptr is address has been changed
free(ptr); // Program should crash here
ptr = NULL;
/* *ptr = 5;*/ // This statement is crashing
return 0;
}
The behavior of this program is undefined from the very moment that you store a value through an int* pointing to a single byte. There's no guarantee of a crash.
Specifically, it seems like your free doesn't (maybe can't) check its argument properly. Try running this program with a malloc debugging library.
Absence of a crash does not necessarily mean your code is fine. On another platform, it will probably crash.
BTW: you should rather malloc(sizeof(int))
The program should not necessarily crash, the behavior is undefined.
It works only due to luck; the code is still wrong.
To understand why, one first needs to be familiar with the implementation of the malloc library itself. malloc not only allocates the space it returned for you to use, it also allocates space for its own metadata that it uses to manage the heap (what we call the region of memory managed by malloc). By changing ptr and passing the wrong value to free, the metadata is no longer where free expected it, so the data it's using now is essentially garbage and the heap is corrupted.
This doesn't necessarily mean it'll crash due to say, a segfault, because it doesn't necessarily dereference a bad pointer. The bug still exists and will likely manifest itself in a longer program with more heap usage.

c debug problem, free method

I have the problem in C program:
char *str = (char *) malloc(20);
strcpy_s(str, 10, "abcdefghij");
//here I change one byte before str and one byte after
*((int*)str-1) = 10;
*((int*)(str+20)) = 10;
//and it stops on the..
free(str);
line during the debug
what's wrong?
The part with overwriting not allocated memory is the part of the task. I know that usually it's not correct, but in this context it is the part of the task.
Why on earth would you think that you have the right to change anything located at str-1? You don't :)
It appears you have yet another problem, which, because of the vividness of the first one went past my attention. the addresses you may acces vary from str + 0 to str + 19. str + 20 is out of your realm :)
Both these things result in what's called undefined behavior. Which means you can't get surprised at any behavior! Including failing free, debugger crash, or whatever else
You're not allowed to write to str+20 because you only requested 20 bytes, so str+19 is the last byte you own. And the same goes for str-1.
Writing to memory outside what you allocated gives undefined behavior.
In this particular case, we can guess that the heap manager probably has some book-keeping information about each block of memory stored just before the memory that it hands to you. When you write to the byte before your allocated block, you're overwriting some part of that, so it can no longer free the block correctly.
*((int*)str-1) is often used to store the length of the allocated space, so that free knows how much byte to free...

Resources