4 ms·
So Unix people had this function called `gets` that was defined like this: char *gets(char *at); In the early days, if someone wanted a string you could d
by geocar 9y ago
So Unix people had this function called `gets` that was defined like this:
char *gets(char *at);
In the early days, if someone wanted a string you could do:
x = gets(sbrk(0));brk(x + strlen(x) + 1);
And this is perfectly safe, but it is perhaps the only safe way to use `gets`. See, most people wanted to write:
char buf[99];
x = gets(buf);
And is this not safe because `gets` doesn't know that `buf` only has room for 99 bytes.
The API has a choice:
a) They can make it harder to do the wrong thing; make `gets` generate errors, warnings, crash if you use it, etc. This requires people fix their programs. That's what GNU did for `gets` and it's what Apple is doing here.
b) They can change the rules: It's possible to modify the ABI and require markers or a mechanism to detect where the edge of the buffer is. This requires people recompile their programs. I think Zeta-C had "fat pointers" so gets should be safe there[1]
c) They can work around: If you have enough resources, you can look at the programs using this API and figure out what their buffer sizes are and hardcode that into the API provider. Microsoft has famously done this for SimCity[2]
That's it. They can't really do anything else: The function is difficult to use right and programmers do the easiest most-obvious thing they can. oh i need to get a string, so i'll use gets... but i need two strings so....
Anyway, I'm not aware of any good rules for choosing which way to go: Less total effort seems like a good metric, but this is very hard to estimate when you live on an island and don't know how other people use your software.
Memory corruption is serious though: It's often very easy to turn into a security hole, so I generally advocate doing something. All of the people just disabling this security feature make me nervous. I wonder how many of them run websites that I use...
[1]: http://www.bitsavers.org/bits/TI/Explorer/zeta-c/ http://www.bitsavers.org/bits/TI/Explorer/zeta-c/
[2]: https://news.ycombinator.com/item?id=2281932 https://news.ycombinator.com/item?id=2281932
- fanf2 9y agoSurely that gets(sbrk(0)) will not work since sbrk(0) returns a pointer to unmapped memory. Maybe you wanted sbrk(BUFSIZ)?
- geocar 9y agoWell, no actually: That still limits you to a gets of BUFSIZ. Just as we often grow the stack with page faults, you could grow the heap with page faults: Modern UNIX doesn't because this is another one of those "almost certainly a mistake", but: signal(SIGSEGV, grow); void grow(int _) { sbrk(PAGESZ); } should work.
- throwme211345 9y agofork() is not gets and you don't f*ck with process creation. If a programmer commits an error that deadlocks or corrupts data by using fork() unsafely they really should have known what they were doing in the first place.
- jjnoakes 9y agoModern brk() can return -1 to indicate there's insufficient space above the current break address to allocate the requested additional space. I assume "in the early days" brk() could also fail to allocate space (after all the space available is not infinite) so "perfectly safe" comes with caveats.
- ScottBurson 9y agoWow, somebody remembers Zeta-C! Yes, you're right, 'gets' was safe in Zeta-C. (I'm the author.)