6 ms·
I'm a little bit slow with the low level stuff. Could someone explain what's so horrific about this code?
by j_baker 16y ago
I'm a little bit slow with the low level stuff. Could someone explain what's so horrific about this code?
- chipsy 16y agoC's function call mechanism requires internal maintenance of a call stack, which the programmer ordinarily never has to touch. The broken code author claims that he needs to manipulate said stack to write his Scheme interpreter. He does it wrong in a way that might pass the trivial "hello" test case under Linux, and blames Cygwin when it doesn't even pass that.
- ww520 16y agoFor one thing, he's using assembly of one type of machine and expects it to work on different type of machine. He confuses Linux as a machine abstraction and demands that Cygwin running on Windows to be the same. For the low level mess, he sets the stack frame pointer to a uninitialized heap-allocated buffer which contains God-know-what garbage. When main() returns, it pops its return address from the stack frame pointer, which contains garbage and crashes. The printf() might sometime work depending on how the compiler emits code to set up the stack frame. It just shows how dangerous some ignorant programmers can be.
- mrfu 16y agoFor further information http://insecure.org/stf/smashstack.html http://insecure.org/stf/smashstack.html is an interesting read.
- rntz 16y agoUh, actually, his original program (http://www.cygwin.com/ml/cygwin/2005-08/msg00542.html http://www.cygwin.com/ml/cygwin/2005-08/msg00542.html) did restore the stack pointer before returning from main. He "wanted to cut [the example's size] down for the sake of the mailing list", so he left that bit out.
- phaedrus 16y agoStill a terrible thing to do. I think it's possible just calling printf() itself could do wacky things if printf is depending on the stack being set up a certain way by the C runtime startup code prior to main. But the real issue is that what he's doing is completely unnecessary, because you could manage multiple stacks yourself using ordinary C data structures and ordinary C code. Evidently he thinks he's gaining some kind of speed advantage by doing things this way, but the risk is very high versus the gain. This kind of optimization may have worked OK on a DOS machine, but it's neither safe nor obviously faster to do things like this on a modern CPU and OS.
- Confusion 16y agoWell, doing terrible things is sometimes necessary to perform magic or to get a better understanding about how things work. From the less flamey parts of the discussion, I gather his ideas weren't all that unsound, just extremely hard to pull off.
- InclinedPlane 16y agoGenerally speaking if you have to do terrible things then you need to a: know exactly what you are doing before hand and b: have the fortitude to be able to withstand harsh criticism until you can prove your code. In this case I think the harsh criticism was fully justified. People should be warned away from doing this sort of thing, precisely because it's hard to get right. As the thread makes abundantly clear the original programmer was fairly clueless, otherwise he wouldn't have gone off half-cocked thinking that the fault was with cygwin or somesuch. He was making his own dynamite and was too clueless to realize what he was doing wrong.
- Confusion 16y agoI don't agree: we have no reason to doubt his claim that he wrote a task switcher for DOS. That means he's reasonably clueful. It's easy to dismiss someone as a complete loony, because he's wrong/confused about some things and is getting burned to the ground for that. Remove the flaming and there is criticism and the pointing out of mistakes, but nothing to indicate the guy has no clue whatsoever. If that were the case, it would be hard to even being criticising the idea. The fact that people could succinctly point out the problems means the ideas were stated in reasonably clear language.
- tptacek 16y agoSay what? Nothing you've said here makes sense. First, he's writing a nonportable language runtime. For Cywgin. It's not a fair critique to say "he's making the mistake of writing x86-specific code". Second, you don't have to initialize a stack before you use it. The stack isn't magically cleared before it gets used. In fact, that's rather the point of having the stack implemented with a single pointer, and is also the reason that in C you have to explicitly initialize (say) integers before using them. Third, there's nothing "dangerous" about what he's doing, in that what he's doing can't ever work. He created a temp stack, write code that attempts to switch into it, and never wrote the code to switch out of it. That's not going to slip into production. But that's also not a fundamental critique of the approach. What he's trying to do works fine, including under Cygwin, when completely implemented. Despite much peanut gallery whining that it can't possibly work, or that this guy should give up on doing inline/threaded/coroutine stacks and instead implement some CS101 interpreter instead.
- ww520 16y agoThen let me make some senses for you. He said his code works on Linux but not Cygwin. Linux is not a hardware architecture. The code generated for Linux Arm is very different from Linux i386. I merely pointed out he's confused about different machine abstractions and his claim of "working on Linux" is not a good basis to expect it would work on Cygwin. Does that make sense for you? Second, re-read what I wrote. I talked about returning from main(). I wasn't talking about sub-function calls within main(). Returning from main() will take the garbage content from the uninitialized buffer as return address and crash. And if you initialize the buffer with the correct stack frame for the function you want to jump to, you can "return" to it. That's how co-routine work, or buffer overflow attack. Does that make sense for you? Second (b) a stack is not necessarily implemented as a single pointer. On i386, it's a double-indirect pointer EBP:ESP. He only set up ESP and forgot about EBP. Depending on how the generated code sets up the runtime environment, EBP is not necessary (most likely not) the same as the heap. Third, whatever, it's your pure speculation. He's jumping wildly to whatever location. It's lucky it crashes rather than silently executes whatever code and format his drive. The fact remains that what he's doing doesn't work, despite what you insist. No one says he should give up doing thread/coroutine stacks. Just his approach is wrong and non-portable. There are better ways to do coroutine.
- dedward 16y agogcc relies on the stack to handle function calls. In this case he's using in-line assembly to modify the stack pointer. That's bound to end in bad results.....
- lallysingh 16y agoThe asm statement puts the pointer (the malloc(5000)+5000's result) into the stack pointer. When the arguments are passed into fprintf(), they're pushed on top of that frame (presumably back into the malloc'd block). In my book, a worthy attempt to grow your stack on the heap, but you've really got to be ready to hit the asm debugger when things go awry. Edit: as mentioned in other comments, the mistake was (at least) in not restoring the stack pointer before main returned.
- amalcon 16y agoThe short answer is that he's doing low-level stack-twiddly stuff using inline assembler in C. It's one of the standard perils of mixing languages: the C compiler assumes (and attempts to ensure) that it's the only thing manipulating the stack pointer, and the inline assembler violates that assumption.
- llaxsll 16y agoIf you actually read further along in the thread, it looks like this guy is trying to implement coroutines. However, he cut some essential part of a sample code that he was initially looking at and then assumed that the problem is with cygwin. And then came some silly flame war. I personally haven't done anything with coroutines but looks like from a low level perspective, ultimately what he is trying to do is not insane… aka do some form of task switching. Arguably, he shouldn't be doing this by himself and he should've resorted to something that is already available. Just a quick look at (http://en.wikipedia.org/wiki/Coroutine#Coroutine_alternatives_and_implementations http://en.wikipedia.org/wiki/Coroutine#Coroutine_alternative...) should've been sufficient. Yet.., maybe he had some reason to try and do it himself. Looks like at the end he managed to figure out what he wanted to do.