Path: utzoo!utgpu!news-server.csri.toronto.edu!mailrus!ames!rex!samsung!usc!apple!uokmax!servalan!rmtodd From: rmtodd@servalan.uucp (Richard Todd) Newsgroups: comp.unix.aux Subject: Re: Problem in sscanf with gcc-1.37 ? Keywords: sscanf gcc Message-ID: <1990Jul27.052634.3041@servalan.uucp> Date: 27 Jul 90 05:26:34 GMT References: <2204@s3.ireq.hydro.qc.ca> Organization: Ministry of Silly Walks Lines: 52 lamarche@ireq.hydro.qc.ca appears to have run afoul of the classic scanf/writable strings problem, wherein: >#include >main () >{ > char works[] = "Works 1 2"; > char* fails = "Fails 1 2"; > int d1,d2; > sscanf ( works, "Works %1d %1d", &d1, &d2 ); works ok, but > sscanf ( fails, "Fails %1d %1d", &d1, &d2 ); doesn't. The problem is the interaction of a new feature in GCC with a long- standing bug in stdio. Here goes: Sscanf, like all the scanf functions, reads a string (either from memory or a file descriptor) and parses it. Internally, the scanf functions do reading by calling fgetc() and the like; reads from the string argument passed to sscanf are done by making a "fake" FILE structure that fgetc() and the like know represents a string in memory and not an actual file. Now, when parsing, the scanf routines sometimes need to backtrack; the obvious way to back up one character is to call ungetc(). Now ungetc(), when working on a fake FILE pointing to a string, writes back into the string the character that was just read from it. Ordinarily, this is just a pointless waste of a few microseconds, but it causes problems when in a program compiled with gcc. Why? Well, gcc implements a new feature allowed by the ANSI standard, where string constants are actually constants--you can't write to them, since they are placed in text space instead of data space. Attempting to write into a string constant will cause a memory fault. Hence, when you pass the address of a string constant to scanf, it will die. Now, let's look at those sample code lines more closely: > char* fails = "Fails 1 2"; This declares a pointer to char, and initializes it to point to the string constant "Fails 1 2". Hence, when you do sscanf(fails,...), you get a memory fault. > char works[] = "Works 1 2"; This, though it looks similar to the above, is very different. This allocates an array in automatic (stack-based) storage, and initializes it with the sequence of characters 'W','o',...'2',0. Since works[] is allocated in the stack region, which is writable, sscanf() has no problem. So, what do you do to try to get these X programs going that call sscanf() with string constants? Well, for starters, change the makefiles to add "-fwritable-strings" to the options for gcc. This causes gcc to put string constants in data space, just like cc does, so that writes to string constants succeed. This will get those programs compiled and working. -- Richard Todd rmtodd@uokmax.ecn.uoknor.edu rmtodd@chinet.chi.il.us rmtodd@servalan.uucp