I have already solved the Segmentation Fault, which caused this problem, but I'd still like to know why this was happening:
I have a method which causes a segmentation fault later on in the code, but the printf statment, which is BEFORE the problematic code never gets excecuted.
element* insert_sorted(element *first, element *new_elem)
{
printf("%lld", new_elem->isbn);
// Some funny code which causes a Segmentation Fault
}
// Output: Segmentation Fault only, not even the expected first ISBN
But if I return before this code, it prints just fine
element* insert_sorted(element *first, element *new_elem)
{
printf("%lld", new_elem->isbn);
return NULL;
// Some funny code which causes a Segmentation Fault
}
// Output: Prints all the ISBN numbers just fine
And lastly, if I put a line break into the print, it prints the first two ISBNs and than it gives an Segmentation Fault.
element* insert_sorted(element *first, element *new_elem)
{
printf("%lld\n", new_elem->isbn);
// Some funny code which causes a Segmentation Fault
}
// Output: First two ISBNs and than a Segmentation Fault
Question 1:
How is it possible that a Segmentation Fault prevents printing text to the console? Is the order of execution broken??
Question 2:
How is it possible, that adding a character (\n) changes this behaviour? And why would it still only print the first two times? (This function gets called about 20 times.)
Question 3:
How can I debug my code, when errors are 'eating' my debugging information? :(
(The code is part of a homework, so I can't post the entire code.)
How is it possible that a Segmentation Fault prevents printing text to the console?
The program most probably has undefined behavior and anything could happen. In this case, if you print (without \n) the text most probably stays in the output buffer and is discarded when the program crashes. If you want to print what's in the buffer without a \n, add fflush(stdout);.
How is it possible, that adding a character (\n) changes this behaviour?
\n makes it print what's stored in the output buffer.
And why would it still only print the first two times? (This function gets called about 20 times.)
Again, the program probably has undefined behavior and it could do just about anything - at any time.
How can I debug my code, when errors are 'eating' my debugging information?
The easiest way would be to start the debugger and step through the code line by line. If you are using gcc or clang you can also get very useful information about where the problem is by compiling with
-g -fsanitize=address,undefined
and rerun the program. That usually give valuable hints.
Related
I'm trying to solve my homework.
The question is asking to implement the function count(FILE *fp) that takes as input a text file and returns the number of sentences in the file.
But the output is showing an error 'Segmentation fault (core dumped)'.
int count(FILE *fp)
{
int count=0;
char word[256];
while(fscanf(fp,"%s",word)!=EOF)
{
if(word[strlen(word)-1]=='.')
{
count+=1;
}
}
return count;
}
(If you're on Linux, compile your program with the -fsanitize=address flag. If your program runs into a segmentation fault, it will tell you in excruciating detail what went wrong).
If your file contains a "word" (sequence of characters which are not whitespace) longer than 256 characters (maybe the text is in German, or the text of Mary Poppins), fscanf will write that many characters into word, overflowing it. This can lead to segmentation faults.
You can prevent that by limiting the number of characters fscanf will try to write:
fscanf(fp,"%256s",word);
This may split a "word" into two or more parts, but only the last part with the dot will be counted (unless the word looks like "twohundred-and-fifty-five-characters.some-more").
Note that fscanf can return zero if no fields were stored, although this appears impossible when %s is used. In this case, you'll be applying strlen to uninitialized memory, which can lead to segmentation faults.
Also, if fscanf gives back an empty string (also appears impossible), strlen will return zero, and you'll try to read word[-1], that is, a buffer underrun. You should check the result of strlen before subtracting from it.
Here if strlen(word) returns a value grater than 256 (Meaning you have a sentence with more than 256 characters) you would get a segmentation fault.
You can find the solution in Bulletmagnet's answer
I am getting a segmentation fault for some reason, I wrote this program that calculates the days between two dates and wanted to get the "dd-mm-yyyy" to be represented as a string and "dd2-mm2-yyyy2"should also be represented as a string, i thought I could solve it this way, but i cam getting a segmentation fault, can someone help me? what am i doing wrong?
This seems incorrect. argv[1] is your "day" string, which is 1 or 2 characters long, and you're indexing characters 3 and 4.
char monstr[3];
monstr[0]= argv [1][3];
monstr[1]=argv [1][4];
monstr[2] = '\0';
This should probably be:
char monstr[3];
monstr[0]= argv [2][0];
monstr[1]=argv [2][1];
monstr[2] = '\0';
Same with some other strings.
But, that said, I'm basing this on how you seem to be parsing input. If you want your input to be dd-mm-yyyy, then you're not getting input right. Instead, you should do something like this:
int dd, mm, yyyy;
sscanf(argv[1], "%d-%d-%d", &dd, &mm, &yyyy);
And same with the other string. And in that case, the previous thing I corrected doesn't need to be corrected.
As a general piece of advice: the reason segmentation faults happen is because you're accessing memory that you aren't able to access. A common cause of this is going outside of array bounds, or using invalid pointers. In your case, it seems like one of those two, and it comes from misuse of argv.
Given an array with 5 elements, it is well known that if you use scanf() to read in exactly 5 elements, then scanf() will fill the array and then clobber memory by putting a null character '\0' into the 6th element without generating an error(Im calling it a 6th element but I know its memory thats not part of the array) As is described here: Null termination of char array
However when you try to read in 6 elements or more an error is generated because the OS detects that memory is being clobbered and the kernel sends a signal. Can someone clear up why an error is not generated in the first case of memory clobbering above?
Example code:
// ex1.c
#include <stdio.h>
int main(void){
char arr[5];
scanf("%s", arr);
printf("%s\n", arr);
return 0;
}
Compile, run and enter four characters: 1234. This stores them in the array correctly and doesn't clobber memory. No error here.
$ ./ex1
1234
1234
Run again and enter five characters. This will clobber memory because scanf() stored an extra '\0' null character in memory after the 5th element. No error is generated.
$ ./ex1
12345
12345
Now enter six characters which we expect to clobber memory. The error that is generated looks like(ie. Im guessing) its the result of a signal sent by the kernel saying that we just clobbered the stack(local memory) somehow....Why is an error being generated for this memory clobbering but not for the previous one above?
$ ./ex1
123456
123456
*** stack smashing detected ***: ./ex1 terminated
Aborted (core dumped)
This seems to happen no matter what size I make the array.
The behaviour is undefined if in both the cases where you input more than characters than the buffer can hold.
The stack smashing detection mechanism works by using canaries. When the canary value gets overwritten SIGABRT is generated. The reason why it doesn't get generated is probably because there's at least one extra byte of memory after the array (typically one-past-the-end of an object is required to be a valid pointer. But it can't be used to store to values -- legally).
In essence, the canary wasn't overwritten when you input 1 extra char but it does get overwritten when you input 2 bytes for one reason or another, triggering SIGABRT.
If you have some other variables after arr such as:
#include <stdio.h>
int main(void){
char arr[5];
char var[128];
scanf("%s", arr);
printf("%s\n", arr);
return 0;
}
Then the canary may not be overwritten when you input few more bytes as it might be simply overwriting var. Thus prolonging the buffer overflow detection by the compiler. This is a plausible explanation. But in any case, your program is invalid if it overruns buffer and you should not rely the stack smashing detection by the compiler to save you.
.Why is an error being generated for this memory clobbering but not for the previous one above?
Because for the 1st test it seemed to work just because of (bad) luck.
In both cases arr was accessed out-of-bounds and by doing so the code invoked undefined behaviour. This means the code might do what you expect or not or what ever, like booting the machine, formatting the disk ...
C does not test for memory access, but leaves this to the programmer. Who could have made the call to scanf() save by doing:
char arr[5];
scanf("%4s", arr); /* Stop scanning after 4th character. */
Stack Smashing here is actually caused due to a protection mechanism used by compiler to detect buffer overflow errors.The compiler adds protection variables (known as canaries) which have known values.
In your case when an input string of size greater than 5 causes corruption of this variable resulting in SIGABRT to terminate the program.
You can read more about buffer overflow protection. But as #alk answered you are invoking Undefined Behavior
Actually
If we declare a array of size 5, then also rather we can put and access data from this array as memory beyond this array is empty and we can do the same till this memory is free but once it assigned to another program now even we are unable to acces a data present there
Scenario 1:
Code:
int main(){
int a = 12345678;
if(isdigit(a)){
printf("ok: foo\n");
}
else{
printf("false: bar\n");
}
printf("test\n");
return EXIT_SUCCESS;
}
Output:
Segmentation fault
Scenario 2:
Code:
...
if(isdigit(a)){
//printf("ok: foo\n");
}
else{
//printf("false: bar\n");
}
printf("test\n");
...
Output:
test
and now the last, Code:
...
int a = 1234567;
...
Output:
ok: foo
test
What's wrong with isdigit()? I do not understand!
Probably because the compiler optimizes the isdigit function call from the code. That is it doesn't run it.
Also note that isdigit expects a character, not a number. http://www.cplusplus.com/reference/clibrary/cctype/isdigit/
This is because isdigit can be defined as macro like this
#define isdigit(c) ((map[c] & FLAG_DIGIT)==FLAG_DIGIT)
You call isdigit with integer value, but map array size is 256 elements. In this case you try to read value outside of array bounds -> segmentation fault. This segmentation fault can occurs randomly. Depending on your program or data size.
This was probably optimized by the compiler. As neither the if or the else does something, it was removed and the isdigit ends up not called. Be sure to
#include <ctype.h>
The segmentation fault is coming probably from the fact that you're passing a (not so small) number, when a character was expected. When you remove the printf statements and the compiler optimizes it, the call won't happen thus not failing.
Note that the headers can be in fact omitted since the program will be linked with the standard C library by default, so it works. But it's not a good idea, and you should see a warning at least.
First of all, isdigit(3) checks whether a character is a digit.
The segmentation fault probably (I'm positive) happens because you haven't included stdio.h.
Then you're calling printf which uses variable arguments without knowing its prototype (undefined behavior).
Why does the following have the effect it does - it prints a terminal full of random characters and then exits leaving a command prompt that produces garbage when you type in it. (I tried it because I thought it would produce a seg fault).
#include <stdio.h>
int main(){
char* s = "lololololololol";
while(1){
printf("%c", *s);
s++;
}
}
it was compiled with:
gcc -std=c99 hello.c
It will eventually seg fault, but before that it'll print out whatever bytes are in the same page. That's why you see random chars on the screen.
Those may well include escape sequences to change (say) the character encoding of the console. That's why you end up with gibberish when you type on the console after it's exited, too.
Because you have an infinite loop (while(1)), and you keep getting the current value of pointer (*s), and then moving the pointer one char forward (s++). This has the effect of marching well past the end of the string into "garbage" (uninitialized memory), which gets printed to the console as a result.
In addition to what everyone else said in regards to you ignoring the string terminal character and just printing willy-nilly what's in memory past the string, the reason why your command prompt is also "garbage" is that by printing a particular "unprintable" character, your terminal session was left in a strange character mode. (I don't know which character it is or what mode change it does, but maybe someone else can pipe in about it that knows better than I.)
You are just printing out what is in memory because your loop doesn't stop at the end of the string. Each random byte is interpreted as a character. It will seg fault when you reach the end of the memory page (and get into unreadable territory).
Expanding ever so slightly on the answers given here (which are all excellent) ... I ran into this more than once myself when I was just beginning with C, and it's an easy mistake to make.
A quick tweak to your while loop will fix it. Everyone else has given you the why, I'll hook you up with the how:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (*s != '\0') {
printf("%c", *s);
s++;
}
}
Note that instead of an infinite loop (while(1)), we're doing a loop check to ensure that the pointer we're pulling isn't the null-terminator for the string, thus avoiding the overrun you're encountering.
If you're stuck absolutely needing while(1) (for example, if this is homework and the instructor wants you to use it), use the break keyword to exit the loop. The following code smells, at least to me, but it works:
#include <stdio.h>
int main() {
char *s = "lolololololololol";
while (1) {
if (*s == '\0')
break;
printf("%c", *s);
s++;
}
}
Both produce the same console output, with no line break at the end:
lolololololololol
Your loop doesn't terminate, so println prints whatever is in the memory after the text you write; eventually it will access memory it is not allowed to read, causing it to segfault.
You can change the loop as the others suggested, or you can take advantage of fact that in c, zero is false and null (which terminates all strings) is also zero, so you can construct the loop as:
while (*s) {
Rather than:
while (*s != '\0')
The first one may be more difficult to understand, but it does have the advantage of brevity so it is often used to save a bit of typing.
Also, you can usually get back to your command prompt by using the 'reset' command, typing blindly of course. (type Enter, reset, Enter)