RE: OT: snprintf() null termination

From: Michael Wojcik (Michael.Wojcikat_private)
Date: Thu May 30 2002 - 13:01:00 PDT

  • Next message: Steve Mickeler: "Re: Wireless MAC Addy question"

    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