Microsoft strncat reads bytes outside the boundaries of the source buffer

I am observing an interesting problem with Microsoft strncat implementation. It touches 1 byte behind 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 a 112-byte block. Therefore, if you are unlucky to get highlighted on an invalid page border, your application will crash. Large applications may intermittently interrupt in such places. (Note that this condition can be modeled using the gflags PageHeap parameter, the block size must be divided by the size of the pointer for proper alignment.)

Is this the expected behavior or error? Any links confirming this? (I read several strncat descriptions, but they can be interpreted in both directions depending on your initial mindset ...)

Refresh (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 the application at strncat read address src + srcBufSize. In this small example, it starts with gflags. PageHeap fails to play sequentially (100%). Therefore, as far as I can tell, the evidence is very strong.

Update2 (information about the compiler) MS Visual Studio 2005 Version 8.0.50727.867. Build Platform: 64-bit (no 32 bit playback). OS used to reproduce the failure: Windows Server 2008 R2.

Update 3 The problem is also reproduced using the binary code built into MS Visual Studio 2012 11.0.50727.1

Update 4 Link to a question in Microsoft Connect ; link to discussion on MSDN forums

Update 5 The problem will be fixed in the next version of VS. No fixes are planned for older versions. See the "Microsoft Connect" link above.

+6
c pageheap
Aug 30 '13 at 3:36 on
source share
3 answers

The documentation for strncat states:

src - pointer to a string with a zero-terminated byte to copy from

Therefore, the implementation may assume that the input parameter src is actually NUL terminated, even if it is longer than the count characters.

For further confirmation, Microsoft Documentation reports:

strSource

The source line is null terminated.

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

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

As indicated in the comments below, this identifies the second parameter s2 as an array, not a null-terminated string. However, this is still ambiguous with respect to the original question, since this documentation describes the final effect on s1 , and not on the behavior of the function when reading from s2 .

Of course, this could be resolved in relation to a specific implementation of Microsoft, referring to the source code of the C Runtime Library.

+3
Aug 30 '13 at 3:48 on
source share
— -

s2 not a "string" in strncat(s1, s2, n) .

So, if Microsoft reads pass n bytes, it does not match C11.

C11 7.24.2.3.1 strcat() mentioned
"adds a copy of the string "pointed to by s2 (including the terminating null character) to the end of the line pointed to by s1".

C11 7.24.2.3.2 strncat says
"Strncat function adds no more than n characters (zero character and subsequent characters are not added) from the array pointed to by s2 to the end of the line pointed to by s1 .. The trailing null character is always added to the result "

Obviously, in the case of strncat s2 treated as an "array" with string restrictions on how much is added to s1 . Thus, during concatenation, there is no need to check s2 more than is absolutely necessary. The final text \0 comes from the code, not s2 .

I do not know about the old standard C99.

+2
Sep 16 '13 at 4:35 on
source share

English is an imperfect language, more than C.

The documentation says "at most n characters" (my emphasis). There is no evidence that strncat is copying more than 112 characters. What makes you believe it?

The strncat code may index for offset 112, but not actually refer to offset 113, which may cause a storage error. This ptr behavior is defined as acceptable in K & R.

Finally, again this is an English / reasoning issue, the documentation probably talks about ending the zero line. But in fact, is it superfluous to say that the line is terminated by zero? They are by definition, otherwise they will be an array of characters. Therefore, the documentation is vague and non-specific. The programmer has to read between the lines. The software documentation is not legal; they are descriptions that should be understood by someone practicing in the art.

+1
Aug 30 '13 at 4:40
source share



All Articles