Reputation: 13
Somewhere on github I saw the following piece of code
char *p=malloc(1);
gets(p);
printf(p);
I tried the same and found out it works. No matter how long string I type it gets stored and doesn't give segmentation fault. How it works? I only gave it 1 byte.
Plus when I type free(p);
it gives strange output.
Upvotes: 0
Views: 1004
Reputation: 47925
Suppose you have a friend who is an absent-minded real estate agent. One day you say to him, "I want to build a house." He asks, "How big a house do you want?" You say, "Oh, 1,000 square feet should be fine." He says, "As a matter of fact, there's a 1,000 square foot vacant lot right next to my house. You can have it." Then he goes off on a vacation.
Suppose you have another friend who is a careless builder. You say, "I just bought a lot. Can you build a house for me on it?" "No problem," he says, and he goes off and starts digging and building. In fact, since you didn't tell him how big a house to build, he builds you a 10,000 square foot mansion. In the process he inadvertently demolishes the real estate agent's house next door, while excavating for the west wing of the new mansion.
Later you realize you don't want the mansion after all, so you decide to sell the lot back to the real estate agent. When he returns from his vacation, you call him on his cell phone to tell him this. You expect him to say, "Okay, great, now I can sell the lot to someone else." Instead he yells, "You bastard, I'm going to sue you!" You consider this a strange thing to say.
If it isn't obvious, the real estate agent in this little story plays the part of malloc
and free
, and the builder plays the part of gets
.
There's one more problem with your code. The analogy for this one is even less realistic, but let's give it a try. Suppose that, after the builder finishes building your mansion, but before you try to get rid of it, you decide you'd like a picture of it. So you ask your friend, the very literal-minded photographer, to take a picture of it for you. "You know my rules," he says. "Please make a list of the items you'd like me to photograph, and put it in my mailbox." You can't find a scrap of paper, and you think it's silly to write a list with just one item on it, so instead of putting a list saying "my house" in his mailbox, you pick up your whole house and try to put it in his mailbox instead. It won't fit, of course, so you leave it on his front porch. When he gets home, he sees your house, and is momentarily confused, but there on your house is your mailbox, so now he's back on firm ground, he knows what to do, he opens the mailbox to find his next assignment. Inside your mailbox is your new copy of National Geographic, with the cover story on "The ten most beautiful (but deadly) places in the world." So off he goes to photograph those for you, and you never hear from him again.
So when you hear that printf
requires as its first argument a list of things you'd like it to print, please always give it that list, even if there's only one thing you want it to print. That is, please say printf("%s", p)
instead. (To see why, suppose that the string you type to the gets
call is not "A", not "Hello", but "The string is %s.". Then think carefully about what printf
is going to do, remembering that printf
is just about as literal-minded as your photographer friend.)
Upvotes: 0
Reputation: 47925
As others have pointed out, it's undefined behavior.
Undefined behavior can be tricky to think about. Here is a question similar to yours, that might make it easier to think about.
"Somewhere I heard this rule, 'When the light is red, you must not go through the interesection'. I tried the same and found out it works. No matter how many times I drive my car through the red light, nothing bad happens. How does it work? I live in a very small town, and we had to fire our policeman a while ago due to budget cuts."
Upvotes: 0
Reputation: 123458
That code is a textbook example of why gets
has been removed from the standard library as of the 2011 standard. It is a malware exploit.
gets
reads a sequence of characters from standard input until it sees a newline character, and stores that sequence to the buffer starting at the address p
. gets
has no idea how large the target buffer is, and if the input sequence is longer than what the buffer is sized to hold, then gets
will happily store those excess characters to the memory immediately following the buffer, potentially causing all kinds of mayhem.
You allocate a buffer that's all of 1 byte wide. When you call gets
, it writes the first character of input to that buffer, and then any additional input (plus a zero-valued terminator) to the unallocated heap memory immediately following your buffer.
In this specific case, nothing important is being overwritten, so your code appears to function normally. In another context, however, this code may cause other data to be corrupted or cause a runtime error.
The behavior on writing past the end of a buffer is undefined; the compiler doesn't have to warn you of anything, and the compiled code can do anything from crash outright to execute a virus to work as expected.
So,
NEVER NEVER NEVER NEVER NEVER use gets
. Ever. Under any circumstances. Not even in toy code. Like I said, it is no longer part of the standard library.
C puts all the burden of resource management on you, the programmer - buffers will not automatically grow to accommodate additional input, nor is there any automatic garbage collection to clean up dynamic memory that's no longer being referenced.
C will not protect you from doing something stupid - the language assumes you know what you are doing at all times.
Upvotes: 1