Last I checked, Microsoft's snprintf (actually _snprintf, thereby allowing them to dodge the spec) also didn't follow the return-value convention used by most Unix variants and enshrined by C99. Those "good" snprintf implementations return -1 for a formatting error, or the number of characters that *would have been written* (not counting the terminating nul) given a sufficiently large buffer. That lets the caller determine whether the buffer needs to be larger. Microsoft's _snprintf returns -1 for a formatting error or buffer overrun. Not very useful. SUSv2's definition of snprintf says that the return value (in the absence of a formatting error, and with a buffer size of at least 1) will be "the number of characters transmitted", which is a bit ambiguous but sounds to me like they're requiring the Wrong Thing - returning the number of characters actually written into the buffer, and not the length the fully-formatted string would have been. If the return value is the buffer size, then there may have been an overrun, and the only way to detect it is to try again with a larger buffer. Unless and until it's possible to target only C99, the safest thing to do would be to assume you have to nul-terminate the buffer yourself, and if you need to handle snprintf buffer overruns gracefully, wrap snprintf (or rather vsnprintf) with a function that has conditionally-compiled code to handle the various return value conventions. On Windows, I'd use a heuristic: if I get a -1 from vsnprintf, try enlarging the buffer, but don't let it grow beyond a predefined maximum, so that formatting errors don't just eat up all the available malloc space. On SUSv2-compliant platforms, enlarge in the boundary case where the return value matches the buffer size (possibly fudged by one, since SUSv2 also isn't clear about whether the nul is counted). Pity K&R didn't just define snprintf right off the bat; in retrospect it certainly seems like an obvious candidate, and sprintf clearly makes an unreasonable assumption about the caller's ability to judge the output of the formatter. They gave us fgets as well as gets... Or use a third-party [v]snprintf implementation. I've seen a few, and there's always GNU libc (which I believe does the right thing). Michael Wojcik Principal Software Systems Developer, Micro Focus Department of English, Miami University > -----Original Message----- > From: Gerardo Richarte [mailto:core.lists.exploit-dev@core-sdi.com] > Sent: Thursday, May 30, 2002 1:21 PM > To: vuln-devat_private > Subject: Re: OT: snprintf() null termination > > > Vanja Hrustic wrote: > > > So - do all platforms properly null-terminate string (on > overflow) when > > snprintf() is used, or one should still use > "sizeof(string)-1" for the > > size of the snprintf()-ed string? > > regarding snprintf(): > > -Linux, Solaris and OpenBSD do terminate with NUL when > not enough space is available > -Windows does not (Microsoft's libraries, at least up to > Visual Studio 6) > > the other OSes where not tested, but I guess most unixes > will (just guessing) > > gera > > > --- for a personal reply use: Gerardo Richarte <geraat_private> >
This archive was generated by hypermail 2b30 : Thu May 30 2002 - 13:24:09 PDT