Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Microsoft's strncat reads bytes beyond source buffer boundaries

Tags:

c

pageheap

I observe an interesting problem with the Microsoft implementation of strncat. It touches 1 byte beyond the source buffer. Consider the following code:

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>

void main()
{
    char dstBuf[1024];
    char* src = malloc(112);
    memset(src, 'a', 112);
    dstBuf[0] = 0;
    strncat(dstBuf, src, 112);
}

strncat reads 1 byte after 112 byte block. So if you are unlucky enough to get allocation on an invalid page boundary, your application crashes. Large applications can crash intermittently in such places. (Note that such condition can be simulated with gflags PageHeap setting; block size has to be divisible by pointer size for proper alignment.)

Is this the expected behavior or a bug? Any links confirming that? (I read several descriptions of strncat but they can be interpreted both ways depending on your initial set of mind...)

Update (to answer questions about evidence): I apologize if it is not clear from the text above, but this is an experimental fact. I observe intermittent crashes in an application at strncat reading address src+srcBufSize. In this small example run with gflags PageHeap on crash reproduces consistently (100%). So as far as I can see the evidence is very solid.

Update2 (info on compiler) MS Visual Studio 2005 Version 8.0.50727.867. Build platform: 64 bit release (no repro for 32 bit). OS used to repro the crash: Windows Server 2008 R2.

Update 3 The problem also reproduces with a binary built in MS Visual Studio 2012 11.0.50727.1

Update 4 Link to issue on Microsoft Connect; link to discussion on MSDN Forums

Update 5 The problem will be fixed in the next VS release. No fix is planned for old versions. See the "Microsoft Connect" link above.

like image 529
glagolig Avatar asked Aug 30 '13 03:08

glagolig


People also ask

How does strncat work in C?

In the C Programming Language, the strncat function appends a copy of the string pointed to by s2 to the end of the string pointed to by s1. It returns a pointer to s1 where the resulting concatenated string resides.

What can I use instead of strcpy?

The strcpy_s() and strcat_s() functions are defined in C11 Annex K as close replacement functions for strcpy() and strcat().

Which functions guarantee null terminated strings?

Use strlcpy() function. strlcpy() takes the full size of the destination buffer and guarantee NULL-termination if there is room.


1 Answers

The documentation for strncat states:

src - pointer to the null-terminated byte string to copy from

Therefore, the implementation can assume that the src input parameter is in fact NUL-terminated, even if it is longer than count characters.

For further confirmation, Microsoft's own documentation states:

strSource

Null-terminated source string.

On the other hand, the actual C standard states something like:

The strncat function appends not more than n characters (a null character and characters that follow it are not appended) from the array pointed to by s2 to the end of the string pointed to by s1.

As pointed out in the comments below, this identifies the second parameter s2 as an array and not a NUL-terminated string. However, this is still ambiguous with respect to the original question, because this documentation describes the ultimate effect on s1, rather than the behaviour of the function when reading from s2.

This could of course be settled with respect to the specific Microsoft implementation by consulting the C Runtime Library source code.

like image 67
Greg Hewgill Avatar answered Oct 28 '22 02:10

Greg Hewgill