strcat+strcat+strcat == baaad

Shachar Shemesh winehebhaim at sun.consumer.org.il
Mon Dec 2 03:55:28 CST 2002


David Laight wrote:

>>probably that
>>you were underestimating the time required to parse the format string,
>>which is probably greater than anything else. Everything else is simple
>>searching and copying whereas the parsing is probably at least a
>>quadratic-order function.
>>    
>>
>
>No it will be linear (on the length of the format string).
>But just rather more expensive than you probably expect.
>
That's the reason that I thought it will be faster. However, since the 
test program copied 40 bytes 10 times, which is a rather extreme case, 
and still was not faster, we can only conclude that sprinf is not 
practical for almost all standard cases.

>There is a lot of red tape lurking.
>
>	David
>  
>
This, however, does not answer the usability issue. Obviously, we won't 
put in patches that convert to anything else just because someone didn't 
like it (yes, I agree with Alexander on this point). There is, however, 
the question of buffer overruns.

I suggest implementing strlcat and strlcpy, as in OpenBSD. I can write 
them, but I'm not sure where to place them. They should either be 
inlined (as in - implemented in an include file as a static func), or in 
some library that will be linked (statically, I hope). Ideas?

For those who don't know strl* functions - they are just like strn* 
functions, except that the parameters are sane:
In strn*:

    * Resulting string is not always NULL terminated.
    * In strncat, the terminating null is always written, but is not
      counted in the size!!!
    * The size parameter is sometimes the total size of the buffer, and
      sometimes the size of the unused portion of the buffer.
    * On strncpy, the entire buffer is written into, even if very little
      of it is needed (performance)

All of the above make for awkward and error prone coding. In order to 
use strncat properly, you have to keep subtracting the number of 
characters already copied, and 1 for the terminating nul. As a result of 
these subtractions, a negative overflow (i.e. - from 0 to maxint) may 
happen, which in turn causes buffer overruns itself.
Unlike it, in the strl* functions:

    * Resulting string is ALWAYS NULL terminated, whether there was
      enough room or not.
    * The buffer is not padded with NULLs beyond the terminating one
      (performance).
    * The number is ALWAYS the total buffer size. No arithmetics are
      necessary.

                Shachar





More information about the wine-devel mailing list