Printing char* resulting in segmentation fault? - c

The following program results in segmentation fault [I have used gcc as compiler], How to print str in the character pointer and why segmentation fault?
#include <stdio.h>
#define LOW 0x40000000
#define HIGH 0x0
int main()
{
volatile char* str = (char*) (HIGH + LOW);
printf ( "Character Str:%s",str);
}

You are assigning the pointer str to point to an absolute memory address, memory address 0x40000000. The (char*) cast is why your compiler isn't complaining. There is almost certainly nothing useful at that address because you haven't declared anything besides that pointer. Don't use absolute memory addressing unless you're writing an operating system or are coding for a legacy system without virtual memory for each program. Even then it's a bad idea if you don't know what you're doing.
printf is failing because you're telling it look for a valid string starting at the memory pointed to by ptr and print it out to stdout (e.g. your console). In the highly unlikely event that address 0x40000000 is readable by your process at the time of execution and it contains a valid, null-terminated string, it would print something out without the segfault. It would still be gibberish.
Based on the number you chose for HIGH, it looks like you were trying to null-terminate a string. If you wanted to create a string that printf could print you might try something like this:
char str[12] = "Hello World";
printf ( "Character Str:%s",str);
Once that was properly allocated, you could could create a pointer and work with that if you so desired.
char *strptr = str;
printf ( "Character StrPtr:%s",strptr);
I may be way off base on what you were actually trying to do. But what you are doing is not valid, and what you are trying to do is not obvious.

Related

Confusion in "strcat function in C assumes the destination string is large enough to hold contents of source string and its own."

So I read that strcat function is to be used carefully as the destination string should be large enough to hold contents of its own and source string. And it was true for the following program that I wrote:
#include <stdio.h>
#include <string.h>
int main(){
char *src, *dest;
printf("Enter Source String : ");
fgets(src, 10, stdin);
printf("Enter destination String : ");
fgets(dest, 20, stdin);
strcat(dest, src);
printf("Concatenated string is %s", dest);
return 0;
}
But not true for the one that I wrote here:
#include <stdio.h>
#include <string.h>
int main(){
char src[11] = "Hello ABC";
char dest[15] = "Hello DEFGIJK";
strcat(dest, src);
printf("concatenated string %s", dest);
getchar();
return 0;
}
This program ends up adding both without considering that destination string is not large enough. Why is it so?
The strcat function has no way of knowing exactly how long the destination buffer is, so it assumes that the buffer passed to it is large enough. If it's not, you invoke undefined behavior by writing past the end of the buffer. That's what's happening in the second piece of code.
The first piece of code is also invalid because both src and dest are uninitialized pointers. When you pass them to fgets, it reads whatever garbage value they contain, treats it as a valid address, then tries to write values to that invalid address. This is also undefined behavior.
One of the things that makes C fast is that it doesn't check to make sure you follow the rules. It just tells you the rules and assumes that you follow them, and if you don't bad things may or may not happen. In your particular case it appeared to work but there's no guarantee of that.
For example, when I ran your second piece of code it also appeared to work. But if I changed it to this:
#include <stdio.h>
#include <string.h>
int main(){
char dest[15] = "Hello DEFGIJK";
strcat(dest, "Hello ABC XXXXXXXXXX");
printf("concatenated string %s", dest);
return 0;
}
The program crashes.
I think your confusion is not actually about the definition of strcat. Your real confusion is that you assumed that the C compiler would enforce all the "rules". That assumption is quite false.
Yes, the first argument to strcat must be a pointer to memory sufficient to store the concatenated result. In both of your programs, that requirement is violated. You may be getting the impression, from the lack of error messages in either program, that perhaps the rule isn't what you thought it was, that somehow it's valid to call strcat even when the first argument is not a pointer to enough memory. But no, that's not the case: calling strcat when there's not enough memory is definitely wrong. The fact that there were no error messages, or that one or both programs appeared to "work", proves nothing.
Here's an analogy. (You may even have had this experience when you were a child.) Suppose your mother tells you not to run across the street, because you might get hit by a car. Suppose you run across the street anyway, and do not get hit by a car. Do you conclude that your mother's advice was incorrect? Is this a valid conclusion?
In summary, what you read was correct: strcat must be used carefully. But let's rephrase that: you must be careful when calling strcat. If you're not careful, all sorts of things can go wrong, without any warning. In fact, many style guides recommend not using functions such as strcat at all, because they're so easy to misuse if you're careless. (Functions such as strcat can be used perfectly safely as long as you're careful -- but of course not all programmers are sufficiently careful.)
The strcat() function is indeed to be used carefully because it doesn't protect you from anything. If the source string isn't NULL-terminated, the destination string isn't NULL-terminated, or the destination string doesn't have enough space, strcat will still copy data. Therefore, it is easy to overwrite data you didn't mean to overwrite. It is your responsibility to make sure you have enough space. Using strncat() instead of strcat will also give you some extra safety.
Edit Here's an example:
#include <stdio.h>
#include <string.h>
int main()
{
char s1[16] = {0};
char s2[16] = {0};
strcpy(s2, "0123456789abcdefOOPS WAY TOO LONG");
/* ^^^ purposefully copy too much data into s2 */
printf("-%s-\n",s1);
return 0;
}
I never assigned to s1, so the output should ideally be --. However, because of how the compiler happened to arrange s1 and s2 in memory, the output I actually got was -OOPS WAY TOO LONG-. The strcpy(s2,...) overwrote the contents of s1 as well.
On gcc, -Wall or -Wstringop-overflow will help you detect situations like this one, where the compiler knows the size of the source string. However, in general, the compiler can't know how big your data will be. Therefore, you have to write code that makes sure you don't copy more than you have room for.
Both snippets invoke undefined behavior - the first because src and dest are not initialized to point anywhere meaningful, and the second because you are writing past the end of the array.
C does not enforce any kind of bounds checking on array accesses - you won't get an "Index out of range" exception if you try to write past the end of an array. You may get a runtime error if you try to access past a page boundary or clobber something important like the frame pointer, but otherwise you just risk corrupting data in your program.
Yes, you are responsible for making sure the target buffer is large enough for the final string. Otherwise the results are unpredictable.
I'd like to point out what is actually happening in the 2nd program in order to illustrate the problem.
It allocates 15 bytes at the memory location starting at dest and copies 14 bytes into it (including the null terminator):
char dest[15] = "Hello DEFGIJK";
...and 11 bytes at src with 10 bytes copied into it:
char src[11] = "Hello ABC";
The strcat() call then copies 10 bytes (9 chars plus the null terminator) from src into dest, starting right after the 'K' in dest. The resulting string at dest will be 23 bytes long including the null terminator. The problem is, you allocated only 15 bytes at dest, and the memory adjacent to that memory will be overwritten, i.e. corrupted, leading to program instability, wrong results, data corruption, etc.
Note that the strcat() function knows nothing about the amount of memory you've allocated at dest (or src, for that matter). It is up to you to make sure you've allocated enough memory at dest to prevent memory corruption.
By the way, the first program doesn't allocate memory at dest or src at all, so your calls to fgets() are corrupting memory starting at those locations.

Segmentation fault of strcpy()

I was just going through C library functions to see what I can do with them. When I came across the strcpy function the code I wrote resulted in a segmentation fault and I would like to know why. The code I wrote should be printing WorldWorld. If I understood correctly, strcpy(x,y) will copy the contents of y into x.
main() {
char *x = "Hello";
char *y = "World";
printf(strcpy(x,y));
}
If it worked, the code you wrote would print "World", not "WorldWorld". Nothing is appended, strcpy overwrites data only.
Your program crashes because "Hello" and "World" are string constants. It's undefined behavior to attempt to write to a constant, and in your case this manifests as a segmentation fault. You should use char x[] = "Hello"; and char y[] = "World"; instead, which reserve memory on the stack to hold the strings, where they can be overwritten.
There are more problems with your program, though:
First, you should never pass a variable string as the first argument to printf: either use puts, or use printf("%s", string). Passing a variable as a format string prevents compilers that support type-checking printf arguments from doing that verification, and it can transform into a serious vulnerability if users can control it.
Second, you should never use strcpy. Strcpy will happily overrun buffers, which is another major security vulnerability. For instance, if you wrote:
char foo[] = "foo";
strcpy(foo, "this string is waaaaaay too long");
return;
you will cause undefined behavior, your program would crash again, and you're opening the door to other serious vulnerabilities that you can avoid by specifying the size of the destination buffer.
AFAIK, there is actually no standard C function that will decently copy strings, but the least bad one would be strlcpy, which additionally requires a size argument.

Why does my program throw a segmentation fault while using heap-allocated memory?

After writing a program to reverse a string, I am having trouble understanding why I got a seg fault while trying to reverse the string. I have listed my program below.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void reverse(char *);
int main() {
char *str = calloc(1,'\0');
strcpy(str,"mystring0123456789");
reverse(str);
printf("Reverse String is: %s\n",str);
return 0;
}
void reverse(char *string) {
char ch, *start, *end;
int c=0;
int length = strlen(string);
start = string;
end = string;
while (c < length-1){
end++;
c++;
}
c=0;
while(c < length/2){
ch = *end;
*end = *start;
*start = ch;
start++;
end--;
c++;
}
}
1st Question:
Even though I have allocated only 1 byte of memory to the char pointer
str (calloc(1,'\0')), and I copied a 18 bytes string mystring0123456789 into it, and it didn't throw any error and the program worked fine without any SEGFAULT.
Why did my program not throw an error? Ideally it should throw some error as it don't have any memory to store that big string. Can someone throw light on this?
The program ran perfectly and gives me output Reverse String is: 9876543210gnirtsym.
2nd Question:
If the replace the statement
strcpy(str,"mystring0123456789");
with
str="mystring0123456789\0";
the program gives segmentation fault even though I have allocated enough memory for str (malloc(100)).
Why the program throwing segmentation fault?
Even though i have allocated only 1 byte of memory to the char pointer str(calloc(1,'\0')), and i copied a 18 bytes string "mystring0123456789" into it, and it didn't throw any error and the program worked fine without any SEGFAULT.
Your code had a bug -- of course it's not going to do what you expect. Fix the bug and the mystery will go away.
If the replace the statement
strcpy(str,"mystring0123456789");
with
str="mystring0123456789\0";
the program gives segmentation fault even though i have allocated enough memory for str (malloc(100)).
Because when you finish this, str points to a constant. This throws away the previous value of str, a pointer to memory you allocated, and replaces it with a pointer to that constant.
You cannot modify a constant, that's what makes it a constant. The strcpy function copies the constant into a variable which you can then modify.
Imagine if you could do this:
int* h = &2;
Now, if you did *h = 1; you'd be trying to change that constant 2 in your code, which of course you can't do.
That's effectively what you're doing with str="mystring0123456789\0";. It makes str point to that constant in your source code which, of course, you can't modify.
There's no requirement that it throw a segmentation fault. All that happens is that your broken code invokes undefined behavior. If that behavior has no visible effect, that's fine. If it formats the hard drive and paints the screen blue, that's fine too. It's undefined.
You're overwriting the pointer value with the address of a string literal, which totally doesn't use the allocated memory. Then you try to reverse the string literal which is in read-only memory, which causes the segmentation fault.
Your program did not throw an error because, even though you did the wrong thing, ncaught you (more below). You wrote data were you were not supposed to, but you got “lucky” and did not break anything by doing this.
strcpy(str,"mystring0123456789"); copies data into the place where str points. It so happens that, at that place, you are able to write data without causing a trap (this time). In contrast, str="mystring0123456789\0"; changes str to point to a new place. The place it points to is the place where "mystring0123456789\0" is stored. That place is likely read-only memory, so, when you try to write to it in the reverse routine, you get a trap.
More about 1:
When calloc allocates memory, it merely arranges for there to be some space that you are allowed to use. Physically, there is other memory present. You can write to that other memory, but you should not. This is exactly the way things work in the real world: If you rent a hotel room, you are allowed to use that hotel room, but it is wrong for you to use other rooms even if they happen to be open.
Sometimes when you trespass where you are not supposed to, in the real world or in a program, nobody will see, and you will get away with it. Sometimes you will get caught. The fact that you do not get caught does not mean it was okay.
One more note about calloc: You asked it to allocate space for one thing of zero size (the source code '\0' evaluates to zero). So you are asking for zero bytes. Various standards (such as C and Open Unix) may say different things about this, so it may be that, when you ask for zero bytes, calloc gives you one byte. However, it certainly does not give you as many bytes as you wrote with strcpy.
It sounds like you are writing C programs having come from a dynamic language or at least a language that does automatic string handling. For lack of a more formal definition, I find C to be a language very close to the architecture of the machine. That is, you make a lot of the programming decisions. A lot of your program problems are the result of your code causing undefined behavior.You got a segfault with strcpy, because you copied memory into a protected location; the behavior was undefined. Whereas, assigning your fixed string "mystring0123456789\0" was just assigning that pointer to str.
When you implement in C, you decide whether you want to define your storage areas at compile or run-time, or decide to have storage allocated from the heap (malloc/calloc). In either case, you have to write housekeeping routines to make sure you do not exceed the storage you have defined.
Assigning a string to a pointer merely assigns the string's address in memory; it does not copy the string, and a fixed string inside quotes "test-string" is read-only, and you cannot modify it. Your program may have worked just fine, having done that assignment, even though it would not be considered good C coding practice.
There are advantages to handling storage allocations this way, which is why C is a popular language.
Another case is that you can have a segfault when you use memory correct AND your heap became so big that your physical memory cannot manage it (without overlap with stack|text|data|bss -> link)
Proof: link, section Possible Cause #2

Invalid read/write sometimes creates segmentation fault and sometimes does not

Example code:
int main ()
{
char b[] = {"abcd"};
char *c = NULL;
printf("\nsize: %d\n",sizeof(b));
c = (char *)malloc(sizeof(char) * 3);
memcpy(c,b,10); // here invalid read and invalid write
printf("\nb: %s\n",b);
printf("\nc: %s\n",c);
return 0;
}
See in code I have done some invalid reads and invalid writes, but this small program works fine and does not create a core dump.
But once in my big library, whenever I make 1 byte of invalid read or invalid write, it was always creating core dump.
Question:
Why do I sometimes get a core dump from an invalid read/write and sometimes do not get a core dump?
It entirely depends on what you're overwriting or dereferencing when you do an invalid read/write. Specifically, if you're overwriting some pointer that gets dereferenced for example, let's say, the most significant byte of one, you could end up having something get dereferenced to a completely different (and completely invalid) area of memory.
So, for example, if the stack were arranged such that memcpy past the end of c would overwrite part of b, when you attempt to call printf() with b as an argument, it tries to take that pointer and dereference it to print a string. Since it's no longer a valid pointer, that'll cause a segfault. But since things like stack arrangement are platform (and perhaps compiler?) dependent, you may not see the same behavior with similar examples in different programs.
What you are trying to do is basically buffer overflow & in your code sample more specifically heap overflow. The reason you see the crash only at times depends on which memory area you are accessing & if or not you have permission to access/write it (which has been well explained by Dan Fego). I think the example provided by Dan Fego is more about stack overflow (correction welcome!). gcc has protection related to buffer overflow on the stack (stack smashing). You can see this (stack based overflow) in the following example:
#include <stdio.h>
#include <string.h>
int main (void)
{
char b[] = { "abcdefghijk"};
char c [8];
memcpy (c, b, sizeof c + 1); // here invalid read and invalid write
printf ("\nsize: %d\n", sizeof b);
printf ("\nc: %s\n", c);
return 0;
}
Sample output:
$ ./a.out
size: 12
c: abcdefghi���
*** stack smashing detected ***: ./a.out terminated
This protection can be disabled using -fno-stack-protector option in gcc.
Buffer overflow are one of major cause of security vulnerability. Unfortunately function like memcpy do not check for these kinds of problems, but there are ways to protect against these kinds of problems.
Hope this helps!
you create a 3 char string c, but you copy on it 10 chars. it is an error.
it is called a bufferoverflow : you write in a memory that doesnot belong to you. so the behavior is undefined. it could be a crash, it could works fine or it could modify another variable you created.
so the goo thing to do is to allocate enough memory for c to contain the content of b :
c = (char *)malloc(sizeof(char) * (sizeof(b)+1)); // +1 is for the '\0' char that ends every string in c.
2 - when you copy b in c dont forget to put the end of string char : '\0'. it is mandatory in the c standard.
so printf("%s",c); knows where to string finish.
3 - you copied 10 chars from b to c but b containd only 5 chars (a,b,c,d and '\0'), so the behavior of memcpy is undefined (e.g. : memcpy can try to read memory that cant be read,...).
you can copy only the memory you own : the 5 chars of b.
4 - i think the good instruction for defining b is : char b="abcd"; or char b={'a','b','c','d',0};

Memory assignment in C through pointers

I am learning how to use pointers, so i wrote the below program to assign integer values in the interval [1,100] to some random locations in the memory.
When i read those memory locations, printf displays all the values and then gives me a segmentation fault. This seems an odd behavior, because i was hoping to see either all the values OR a seg fault, but not both at the same time.
Can someone please explain why i got to see both?
Thanks. Here is the code
#include <stdio.h>
#include <stdlib.h>
int main()
{
char first = 'f';
char *ptr_first = &first;
int i=1;
for(i=1;i<101;i++)
*(ptr_first+i) = i;
for(i=1;i<101;i++)
printf("%d\n", *(ptr_first+i));
return EXIT_SUCCESS;
}
Not odd at all. You are using your variable first, which is on the stack. What you essentially do is happily overwriting the stack (otherwise known from buffer overflows on the stack) and thus probably destroying any return address and so on.
Since main is called by the libc, the return to libc would cause the crash.
You're accessing memory past beyond that assigned to first. It is just one character, and, through the ptr_first pointer, you're accessing 100 positions past this character to unreserved memory. This may lead to segfaults.
You have to ensure the original variable has enough memory reserved for the pointer accesses. For example:
char first[100];
This will convert first in an array of 100 chars (basically a memory space of 100 bytes that you can access via pointer).
Note also that you're inserting int into the char pointer. This will work, but the value of the int will be truncated. You should be using char as the type of i.
since ptr_first pointer is pointing to a char variable first. Now when you are incrementing ptr_first, so incremented memory address location can be out of process memory address space, thats why kernel is sending segmentation fault to this process.

Resources