我在网站上看到了这段代码.
main(i)
{
gets(&i);
puts();
}
Run Code Online (Sandbox Code Playgroud)
这段代码编译并运行良好!
它从用户获取一个字符串作为输入并打印它!
但是,我的问题是,怎么样?
(注意puts()函数不包含任何参数!)
旧版本的C具有变量和函数的隐式类型,并且此代码使用了该函数和其他一些东西.实际上返回值也非常松懈.
main(i) // i is implicitly an integer (the default type for old C), and normally named argc
// int main(int i) or void main(int i)
{ // The stack (which lives in high memory but grows downward) has any arguments and
// probably the environmental variables and maybe even other (possibly blank/filler)
// stuff on it in addition to the return address for whatever called main and possibly
// the argument i, but at this point that could either be on the stack just under the
// return address or in a register, depending on the ABI (application binary interface)
// extern int gets(int) or extern void gets(int)
// and sizeof(int) is probably sizeof(char *)
gets(&i); // By taking the address of i even if it wasn't on the stack it will be pushed to
// it so that it will have an address (some processors have addressable registers
// but they are rarely used by C for many reasons that I won't go into).
// The address of i is either also pushed onto the stack or put into a register
// that the ABI says should be used for the first argument of a function, and
// and then a call is made to gets (push next address to stack; jump to gets)
// The function gets does what it does, but according to the ABI there are
// some registers that it can do whatever it wants to and some that it must
// make sure are the same as they were before it was called and possibly one
// or more where it is supposed to store a return value.
// If the address of i was passed to it on the stack then it probably would be
// restricted from changing that, but if it was passed in a register it may
// have just been luckily left unchanged.
// Another possiblity is that since gets returns the string address it was
// passed is that it returns that in the same location as the first argument
// to functions is passed.
puts(); // Since, like gets, puts takes one pointer argument it will be passed this
// this argument in the same way as gets was passed it's argument. Since we
// were somehow lucky enough for gets to not overwrite the argument that we
// passed to it and since the C compiler doesn't think it has anything new to
// pass to puts it doesn't change any registers' values or do too much to the
// stack. This leaves us in the situation where puts is called with the stack
// and registers set up in the same way as they would be if it were passed the
// address of i, just the same as gets.
// The gets call with the stack variable's address (so an address high on the stack)
// could have left main's return address intact, but also could have overwritten it
// with garbage. Garbage as main's return address would likely result in a jump to
// a random location (probably not part of your program) and cause the OS to kill the
// program (possibly with an unhandled SIGSEGV) which may have looked to you like a
// normal exit. Since puts appended a '\n' to the string it wrote and stdout is
// line buffered by default it would have been flushed before returning from puts
// even if the program did not terminate properly.
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1413 次 |
| 最近记录: |