Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!ukma!xanth!lll-winken!lll-crg.llnl.gov!casey From: casey@lll-crg.llnl.gov (Casey Leedom) Newsgroups: comp.bugs.4bsd Subject: ungetc will put characters back into an _IOSTRG input stream Summary: Shared strings are not writable Keywords: writable strings, shared strings (text segment), sscanf, ungetc Message-ID: <20282@lll-winken.LLNL.GOV> Date: 12 Feb 89 22:23:00 GMT Sender: usenet@lll-winken.LLNL.GOV Reply-To: casey@lll-crg.llnl.gov (Casey Leedom) Organization: Lawrence Livermore National Laboratory Lines: 71 Description: Ungetc will put characters back into an _IOSTRG input stream. This will cause a segmentation violation if the string is in read only memory (shared text segment). For example: if (!some_option) { opt = getenv(...); some_option = opt ? opt : "some_string"; } ... sscanf(some_option, "some_format", ...); In some cases, some_option will refer to the constant string "some_string". Since sscanf uses ungetc to back up over input it decides it hadn't wanted to look at yet, we write into the constant string "some_string". Repeat-By: Use gcc to compile the following program without the -fwritable-strings option: main() { int i, j; sscanf("4x4", "%dx%d", &i, &j); printf("%d %d\n", i, j); } Fix: Debatable. I fixed ungetc, but who knows? Maybe we do want to be able to do ungetc's on a string argument. Currently _IOSTRG is only used internally for sscanf and sprintf, so changing ungetc doesn't break anything now. Another option would be to replace all uses of ungetc in doscan with fseek(iop, -1L, 1) but I don't think fseek works on _IOSTRG arguments and I think it's a lot more expensive to call. Another option is to separate out the IO stream backup function from putting a [possibly different] character back on the stream. But this involves either defining a new interface, or extending the definition of ungetc's interface to accept something like ungetc(__IOS_BACKUP); And Finally, we could have read only streams and simply have sscanf set that flag in addition to _IOSTRG. But this would add extra processing for every putc, etc. *** lib/libc/stdio/ungetc.c-dist Wed Mar 26 18:08:43 1986 --- lib/libc/stdio/ungetc.c Sun Feb 12 13:45:30 1989 *************** *** 18,24 **** return (EOF); iop->_cnt++; ! *--iop->_ptr = c; return (c); } --- 18,27 ---- return (EOF); iop->_cnt++; ! if (iop->_flag & _IOSTRG) ! --iop->_ptr; ! else ! *--iop->_ptr = c; return (c); }