#inlcude <stdio.h>
#inlcude <stdlib.h>
#inlcude <string.h>
int main() {
char *buff = (char*)malloc(sizeof(char) * 5);
char *str = "abcdefghijklmnopqrstuvwxyz";
memcpy (buff, str, strlen(str));
while(*buff) {
printf("%c" , *buff++);
}
printf("\n");
return 0;
}
this code prints the whole string "abc...xyz". but "buff" has no enough memory to hold that string. how memcpy() works? does it use realloc() ?
Your code has Undefined Behavior. To answer your question, NO, memcpy doesn't use realloc.
sizeof(buf) should be adequate to accomodate strlen(str). Anything less is a crash.
The output might be printed as it's a small program, but in real big code it will cause hard to debug errors. Change your code to,
const char* const str = "abcdefghijklmnopqrstuvwxyz";
char* const buff = (char*)malloc(strlen(str) + 1);
Also, don't do *buff++ because you will loose the memory record (what you allocated). After malloc() one should do free(buff) once the memory usage is over, else it's a memory leak.
You might be getting the whole string printed out, but it is not safe and you are writing to and reading from unallocated memory. This produces Undefined Behavior.
memcpy does not do any memory allocation. It simply reads from and writes to the locations you provide. It doesn't check that it is alright to do so, and in this case you're lucky if your program doesn't crash.
how memcpy() works?
Because you've invoked undefined behavior. Undefined behavior may work exactly as you expect, and it may do something completely different. It may even differ between different runs of the same program. It could also format your hard disk and still be compliant with the standard (Though of course that's unlikely :P )
Undefined behavior means that the behavior is literally not defined to do anything. Anything is valid, including the behavior you're seeing. Note that if you try to free that memory the C runtime of your target platform will probably complain. ;)
No memcpy does not use malloc. As you suspected, you are writing off the end of of buff. In your simple example, that does no apparent harm, but it is bad. Here are some of the things that could go wrong in a "real" program:
You might scribble on something allocated in the memory following your buff leading to subtle (or not so subtle) bugs later on.
You might scribble on headers used internally by malloc and free, leading to crashes or other problems on your next call to those functions.
You might end up writing to an address that has not been allocated to your process, in which case your program will immediately crash. (I suspect this is what you were expecting.)
There are malloc implementations that put unmapped guard pages around allocated memory to (usually) cause the program to crash in cases like this. Other implementations will detect this, but only on your next call to malloc or free (or when you call a special function to check the heap).
Related
If I am correct, doing something like:
char *line;
Then I must allocate some memory and assign it to line, is that right? If I am right, the question is the following:
In a line like
while (fscanf(fp,"%[^\n]", line) == 1) { ... }
without assigning any memory to line I am still getting the correct lines and the correct strlen counts on such lines.
So, does fscanf assign that memory for me and it also places the '\0'?
I saw no mention about these 2 things on the spec for fscanf.
The POSIX scanf() family of functions will allocate memory if you use the m (a on some older pre-POSIX versions) format modifier. Note: when fscanf allocates, it expects a char ** pointer. (see man scanf) E.g.:
while(fscanf(fp,"%m[^\n]", &line) == 1) { ... }
I would also suggest consuming the newline with "%m[^\n]%*c". I agree with the other answers that suggest using line-oriented input instead of fscanf. (e.g. getline -- see: Basile's answer)
See the C FAQ:
Q: I just tried the code
char *p;
strcpy(p, "abc");
and it worked. How? Why didn't it crash?
A: You got lucky, I guess. The memory randomly pointed to by the uninitialized pointer p happened to be writable by you, and apparently was not already in use for anything vital. See also question 11.35.
And, here is a longer explanation, and another longer explanation.
To read entire lines with a recent C library on POSIX systems, you should use getline(3). It allocates (and reallocates) the buffer holding the line as needed. See the example on the man page.
If you have a non-POSIX system without getline you might use fgets(3) but then you have to take the pain to allocate the line itself, test that you did not read a full newline terminated line, and repeat. Then you need to pre-allocate some line buffer (using e.g. malloc) before calling fgets (and you might realloc it if a line does not fit and call fgets again). Something like:
//// UNTESTED CODE
size_t linsiz=64;
char* linbuf= malloc(linsiz);
if (!linbuf) { perror("malloc"); exit(EXIT_FAILURE); };
memset(linbuf, 0, sizeof(linbuf));
bool gotentireline= false;
char* linptr= linbuf;
do {
if (!fgets(linptr, linbuf+linsiz-linptr-1, stdin))
break;
if (strchr(linptr, '\n'))
gotentireline= true;
else {
size_t newlinsiz= 3*linsiz/2+16;
char* newlinbuf= malloc(newlinsiz);
int oldlen= strlen(linbuf);
if (!newlinbuf) { perror("malloc"); exit(EXIT_FAILURE); };
memset (newlinbuf, 0, newlinsiz); // might be not needed
strncpy(newlinbuf, linbuf, linsiz);
free (linbuf);
linbuf= newlinbuf;
linsiz= newlinsiz;
linptr= newlinbuf+oldlen;
);
} while(!gotentireline);
/// here, use the linbuf, and free it later
A general rule would be to always initialize pointers (e.g. declare char *line=NULL; in your case), and always test for failure of malloc, calloc, realloc). Also, compile with all warnings and debug info (gcc -Wall -Wextra -g). It could have give a useful warning to you.
BTW, I love to clear every dynamically allocated memory, even when it is not very useful (because the behavior is then more deterministic, making programs easier to debug).
Some systems also have valgrind to help detecting memory leaks, buffer overflows, etc..
line is uninitialized and doen't point to any valid memory location so what you see is undefined behavior.
You need to allocate memory for your pointer before writing something to it.
PS: If you are trying to read the whole line then fgets() is a better option.Note that fgets() comes with a newline character .
Nope. You're just getting lucky undefined behavior. It's completely possible that an hour from now, the program will segfault instead of run as expected or that a different compiler or even the same compiler on a different machine will produce a program that behaves differently. You can't expect things that aren't specified to happen, and if you do, you can't expect it to be any form of reliable.
I'm a bit confused about malloc() function.
if sizeof(char) is 1 byte and the malloc() function accepts N bytes in argument to allocate, then if I do:
char* buffer = malloc(3);
I allocate a buffer that can to store 3 characters, right?
char* s = malloc(3);
int i = 0;
while(i < 1024) { s[i] = 'b'; i++; }
s[i++] = '$';
s[i] = '\0';
printf("%s\n",s);
it works fine. and stores 1024 b's in s.
bbbb[...]$
why doesn't the code above cause a buffer overflow? Can anyone explain?
malloc(size) returns a location in memory where at least size bytes are available for you to use. You are likely to be able to write to the bytes immediately after s[size], but:
Those bytes may belong to other bits of your program, which will cause problems later in the execution.
Or, the bytes might be fine for you to write to - they might belong to a page your program uses, but aren't used for anything.
Or, they might belong to the structures that malloc() has used to keep track of what your program has used. Corrupting this is very bad!
Or, they might NOT belong to your program, which will result in an immediate segmentation fault. This is likely if you access say s[size + large_number]
It's difficult to say which one of these will happen because accessing outside the space you asked malloc() for will result in undefined behaviour.
In your example, you are overflowing the buffer, but not in a way that causes an immediate crash. Keep in mind that C does no bounds checking on array/pointer accesses.
Also, malloc() creates memory on the heap, but buffer overflows are usually about memory on the stack. If you want to create one as an exercise, use
char s[3];
instead. This will create an array of 3 chars on the stack. On most systems, there won't be any free space after the array, and so the space after s[2] will belong to the stack. Writing to that space can overwrite other variables on the stack, and ultimately cause segmentation faults by (say) overwriting the current stack frame's return pointer.
One other thing:
if sizeof(char) is 1 byte
sizeof(char) is actually defined by the standard to always be 1 byte. However, the size of that 1 byte might not be 8 bits on exotic systems. Of course, most of the time you don't have to worry about this.
It is Undefined Behavior(UB) to write beyond the bounds of allocated memory.
Any behavior is possible, no diagnostic is needed for UB & any behavior can be encountered.
An UB does not necessarily warrant a segmentation fault.
In a way, you did overflow your 3 character buffer. However, you did not overflow your program's address space (yet). So you are well out of the bounds of s*, but you are overwriting random other data in your program. Because your program owns this data, the program doesn't crash, but still does very very wrong things, and the future behaviour is undefined.
In practice what this is doing is corrupting the heap. The effects may not appear immediately (in fact, that's part of what makes such errors a PITA to debug). However, you may trash anything else that happens to be in the heap, or in that part of your program's address space for that matter. It's likely that you have also trashed malloc() internal data structures, and so it's likely that subsequent malloc() or free() calls may crash your program, leading many programmers to (falsely) believe they've found a bug in malloc().
You're overflowing the buffer. It depends what memory you're overflowing into to get an error msg.
Did you try executing your code in release mode or did you try to free up the memory you of s? It is an undefined behavior.
It's a bit of a language hack, and a bit dubious about it's use.
I have a problem with memory allocation using malloc.
Here is a fragment from my code:
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
It outputs "DEBUG 3",and then a error msgbox appears with this message:
The instruction at 0x7c9369aa referenced memory at "0x0000000". The
memory could not be read
For me such behavior is very strange.
What can be wrong here?
The application is single threaded.
I'm using mingw C compiler that is built in code::blocks 10.05
I can provide all the code if it is needed.
Thanks.
UPD1:
There is more code:
char *concat3(char *str1,char *str2,char *str3)
{
/*concatenate three strings and frees the memory allocated for substrings before*/
/* returns a pointer to the new string*/
int L=strlen(str1)+strlen(str2)+strlen(str3);
printf("DEBUG %d\n",L);
char *s=(char*)malloc(L+2);
if(s==0)
{
printf("DEBUGO1");
}
printf("DEBUGO2\n");
sprintf(s,"%s%s%s",str1,str2,str3);
free(str1);
free(str2);
free(str3);
return s;
}
UPD2:
It seems the problem is more complicated than i thought. Just if somebody has enough time for helping me out:
Here is all the code
Proj
(it is code::blocks 10.05 project,but you may compile the sources without an ide ,it is pure C without any libraries):
call the program as
"cbproj.exe s.pl" (the s.pl file is in the root of the arhive)
and you may see it crashes when it calls the function "malloc" that is on the 113th line of "parser.tab.c"(where the function concat3 is written).
I do the project in educational purpouses,you may use the source code without any restrictions.
UPD3:
The problem was that it was allocated not enough memory for one of the strings in program ,but the it seemed to work until the next malloc.. Oh,I hate C now:)
I agree with the comments about bad coding style,need to improve myself in this.
The problem with this exact code is that when malloc fails, you don't return from the function but use this NULL-pointer further in sprintf call as a buffer.
I'd also suggest you to free memory allocated for str1, str2 and str3 outside this function, or else you might put yourself into trouble somewhere else.
EDIT: after running your program under valgrind, two real problems revealed (in parser.tab.c):
In yyuserAction,
char *applR=(char*)malloc(strlen(ruleName)+7);
sprintf(applR,"appl(%s).",ruleName);
+7 is insufficient since you also need space for \0 char at the end of string. Making it +8 helped.
In SplitList,
char *curstr=(char*)malloc(leng);
there's a possibility of allocating zero bytes. leng + 1 helps.
After aforementioned changes, everything runs fine (if one could say so, since I'm not going to count memory leaks).
From the error message it actually looks like your if statement is not quite what you have posted here. It suggests that your if statement might be something like this:
if(s=0) {
}
Note the single = (assignment) instead of == (equality).
You cannot use free on pointers that were not created by malloc, calloc or realloc. From the Manpage:
free() frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
Why does the below C code using strcpy work just fine for me? I tried to make it fail in two ways:
1) I tried strcpy from a string literal into allocated memory that was too small to contain it. It copied the whole thing and didn't complain.
2) I tried strcpy from an array that was not NUL-terminated. The strcpy and the printf worked just fine. I had thought that strcpy copied chars until a NUL was found, but none was present and it still stopped.
Why don't these fail? Am I just getting "lucky" in some way, or am I misunderstanding how this function works? Is it specific to my platform (OS X Lion), or do most modern platforms work this way?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *src1 = "123456789";
char *dst1 = (char *)malloc( 5 );
char src2[5] = {'h','e','l','l','o'};
char *dst2 = (char *)malloc( 6 );
printf("src1: %s\n", src1);
strcpy(dst1, src1);
printf("dst1: %s\n", dst1);
strcpy(dst2, src2);
printf("src2: %s\n", src2);
dst2[5] = '\0';
printf("dst2: %s\n", dst2);
return 0;
}
The output from running this code is:
$ ./a.out
src1: 123456789
dst1: 123456789
src2: hello
dst2: hello
First, copying into an array that is too small:
C has no protection for going past array bounds, so if there is nothing sensitive at dst1[5..9], then you get lucky, and the copy goes into memory that you don't rightfully own, but it doesn't crash either. However, that memory is not safe, because it has not been allocated to your variable. Another variable may well have that memory allocated to it, and later overwrite the data you put in there, corrupting your string later on.
Secondly, copying from an array that is not null-terminated:
Even though we're usually taught that memory is full of arbitrary data, huge chunks of it are zero'd out. Even though you didn't put a null-terminator in src2, chances are good that src[5] happens to be \0 anyway. This makes the copy succeed. Note that this is NOT guaranteed, and could fail on any run, on any platform, at anytime. But you got lucky this time (and probably most of the time), and it worked.
Overwriting beyond the bounds of allocated memory causes Undefined Behavior.
So in a way yes you got lucky.
Undefined behavior means anything can happen and the behavior cannot be explained as the Standard, which defines the rules of the language, does not define any behavior.
EDIT:
On Second thoughts, I would say you are really Unlucky here that the program works fine and does not crash. It works now does not mean it will work always, In fact it is a bomb ticking to blow off.
As per Murphy's Law:
"Anything that can go wrong will go wrong"["and most likely at the most inconvenient possible moment"]
[ ]- Is my edit to the Law :)
Yes, you're quite simply getting lucky.
Typically, the heap is contiguous. This means that when you write past the malloced memory, you could be corrupting the following memory block, or some internal data structures that may exist between user memory blocks. Such corruption often manifests itself long after the offending code, which makes debugging this type of bugs difficult.
You're probably getting the NULs because the memory happens to be zero-filled (which isn't guaranteed).
As #Als said, this is undefined behaviour. This may crash, but it doesn't have to.
Many memory managers allocate in larger chunks of memory and then hand it to the "user" in smaller chunks, probably a mutliple of 4 or 8 bytes. So your write over the boundary probably simply writes into the extra bytes allocated. Or it overwrites one of the other variables you have.
You're not malloc-ing enough bytes there. The first string, "123456789" is 10 bytes (the null terminator is present), and {'h','e','l','l','o'} is 6 bytes (again, making room for the null terminator). You're currently clobbering the memory with that code, which leads to undefined (i.e. odd) behavior.
I have a global structure:
struct thread_data{
char *incall[10];
int syscall arg_no;
int client_socket;
};
and in main()
char buffer[256];
char *incall[10];
struct thread_data arg_to_thread;
strcpy(incall[0],buffer); /*works fine*/
strcpy(arg_to_thread.incall[0],buffer); /*causes segmentation fault*/
Why does this happen and Please suggest a way out.
thanks
A segfault means that something is wrong. But no segfault does not mean that something isn't wrong. If two situations are basically the same, and one segfaults and the other does not, it usually means that they are both wrong, but only one of them happens to be triggering the segfault.
Looking at the line char* incall[10], what that means is you have an array of 10 pointers to a char. By default, these pointers will be pointing at random places. Therefore, strcpying into incall[0] will be copying the string to a random location. This is most likely going to segfault! You need to initialise incall[0] first (using malloc).
So a bigger question is why doesn't the first line segfault? I would imagine the reason is that it just so happens that whatever was in memory before was a valid pointer. Therefore, the strcpy doesn't segfault, it just overwrites something else which will later cause completely unexpected behaviour. So you must fix both lines of code.
Another issue (once you have fixed that) is that strcpy itself is highly dangerous -- since it copies strings until it finds a 0 byte and then stops, you can never be sure exactly how much it's going to copy (unless you use strlen to allocate the destination memory). So you should use strncpy instead, to limit the number of bytes copied to the size of the buffer.
You've not initialized the pointer incall[0], so goodness only knows where the first strcpy() writes to. You are unlucky that your program does not crash immediately.
You've not initialized the pointer arg_to_thread.incall[0], so goodness only knows where the second strcpy() writes to. You are lucky that your program crashes now, rather than later.
In neither case is it the compiler's fault; you must always ensure you initialize your pointers.
Make sure you have enough memory allocated for your string buffers.
Stay away from strcpy. Use strncpy instead. strcpy is a notorious source of buffer overflow vulnerabilities - a security and maintenance nightmare for which there really isn't an excuse.