3 ms·
> -10. It's impossible to get right. char * gets(char * s) ?
by hcs 10y ago
> -10. It's impossible to get right.
char * gets(char * s) ?
- JoshTriplett 10y agoAbsolutely. Also any interface in C or POSIX specified to return a pointer to local static memory, such as "char * basename(char * path)" (and dirname), or "char * ptsname(int fd)", or "char * asctime(const struct tm * tm);".
- wyldfire 10y agoDon't most implementations at least use TLS for their implementations to preserve a modicum of sanity there?
- JoshTriplett 10y agoSome of them do, though not all. And that also doesn't fix problems with signals and similar. But for all of those functions, glibc and some other C libraries provide reentrant variants like "basename_r" and "ptsname_r".
- Someone 10y agoThere's also the write call that succeeds as soon as it can write a single byte, regardless of the byte count passed in. For example, https://en.m.wikipedia.org/wiki/Write_(system_call)#POSIX_usage https://en.m.wikipedia.org/wiki/Write_(system_call)#POSIX_us... warns "The write function returns the number of bytes successfully written into the array, which may at times be less than the specified nbytes" Yet, the example following it (https://en.m.wikipedia.org/wiki/Write_(system_call)#Usage_Example https://en.m.wikipedia.org/wiki/Write_(system_call)#Usage_Ex...) doesn't handle that case or error codes such as EINTR. I remember reading a text describing how to properly use that call, but cannot find it anymore. Faulty examples like the one above are easy to find, though. For example, http://stackoverflow.com/questions/14417806/are-posix-read-and-write-system-calls-atomic http://stackoverflow.com/questions/14417806/are-posix-read-a... and http://stackoverflow.com/questions/10650861/atomicity-of-write2-to-a-local-filesystem http://stackoverflow.com/questions/10650861/atomicity-of-wri... are good questions, but no answer points out that, even if write were atomic, it would not do you any good, as you may have to call it multiple times. It probably is not that difficult, but I think it would take me a day to wrap this function in something that doesn't explode in your face, and be confident that I did it correctly, and even then, I would wake up in bed wondering whether I handled all edge cases correctly.
- pdkl95 10y agognulib has a decent set of safety wrappers around read(2)/write(2). safe_rw() http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/safe-read.c;h=3dde5b513471876d97dba86da5270bd3b2c801b3;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=li... This handles a single read/write, handles EINTER, and returns the amount that was successfully read/written. full_rw() http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=lib/full-write.c;h=08248ad5baf86117ab90b648b4d2ce855a86a011;hb=HEAD http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob;f=li... A wrapper around safe_rw() that handles advancing the pointer through the buffer, calling safe_rw() until the requested COUNT bytes have been sent/received. -- In most cases, I recommend avoiding all of this and using the existing fopen/fread/fwrite/etc buffered I/O interface.
- ArkyBeagle 10y agoI can't say this is true in all cases, but I believe that fopen()/fread()/frwrite()/fclose() all cover this for you. You can get the file number for an opened FILE * block thru something like fileno() or filenum() or something. The f() calls all buffer for you. The problem is that write() is entangled in the ioctl() universe in many implementations of 'C' and that gets funky fast. Beyond* that, reading and writing may involve making your own furniture to hide the ugly from dealing with peripherals.
- JoshTriplett 10y agoYou can also use fdopen to get a FILE* from a file descriptor, and then use the buffering and read/write logic of the C library, rather than having to write your own write_in_full function.
- kazinator 10y agogets can be fixed by specifying some constant like GETS_MAX in some header file such as <limits.h>, along with the promise that gets doesn't write any more than GETS_MAX characters, including the null terminator, to its target buffer, and that the null terminator is always included. Then programs can just include the header and declare arrays of at least that size if they pass them to gets. Presto; no overflow. I heard this idea was toyed with by the ISO C committee. Evidently, D. Gwyn proposed BUFSIZ to be re-used for this purpose.
- JoshTriplett 10y agoIf you're going to modify the code anyway, to include the header and set the buffer size, why not just use fgets, which takes a buffer size? Current versions of glibc actually mark gets as deprecated (so you'll get a warning if you use it), and don't provide it at all if building for C11 or newer.
- kazinator 10y agoGood questions. Since I don't use gets, I have to imagine myself fixing some legacy code. Firstly, I imagine that this code already defines the arrays, so all I have to do is edit the definition to use this use this fictitious GETS_MAX constant, for which I have to include one simple header (which might already be included for something else). No actual logic has changed. (On the other hand, the adjustment to the size of the array to GETS_MAX could be a problematic issue; it is not without risk of something breaking.) To use fgets, I have to edit the calls to add the size parameter. Moreover, I have to scan the buffer for the presence of a newline character and overwrite it with a null. gets does that and the code may be relying on it (using "relying" ironically, with regard to gets).
- slededit 10y agoNot completely impossible (on machines with MMUs). You could intentionally allocate a guard page to signal a buffer overrun, but then you are getting outside things defined by the C standard.