Ticket #39512

v/snprintf don't null-terminate when truncating

Open Date: 2019-08-27 04:45 Last Update: 2019-09-06 06:57

Reporter:
Owner:
(None)
Type:
Status:
Closed
Component:
MileStone:
(None)
Priority:
5 - Medium
Severity:
5 - Medium
Resolution:
Invalid
File:
None
Vote
Score: 0
No votes
0.0% (0/0)
0.0% (0/0)

Details

Using MSYS2 on Windows 7, snprintf and vsnprintf are not C99+ standard compliant because they do not null-terminate when truncating.

Relevant excerpt from the C99 standard:

The snprintf function is equivalent to fprintf, except that the output is written into an array (specified by argument s) rather than to a stream. If n is zero, nothing is written, and s may be a null pointer. Otherwise, output characters beyond the n-1st are discarded rather than being written to the array, and a null character is written at the end of the characters actually written into the array.

The vsnprintf function is equivalent to snprintf, with the variable argument list replaced by arg

The output of the following code:

  1. #include <stdio.h>
  2. #include <errno.h>
  3. int main(void)
  4. {
  5. char buffer[3] = {0};
  6. int ret = snprintf(buffer, sizeof(buffer), "%s", "abcd");
  7. for (int i = 0; i < 3; i++)
  8. printf("%c", buffer[i]); /* should print "ab", does print "abc" */
  9. printf("ret = %d, errno = %d\n", ret, errno);
  10. return 0;
  11. }
is
abc
ret = -1, errno = 34
This was independently confirmed on another Windows 7 machine.

errno is ERANGE and this seems to indicate it is using _vsnprintf (from msvcrt.dll?), at least it is similar in behavior to _vsnprintf_s, minus the null-termination: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/snprintf-s-snprintf-s-l-snwprintf-s-snwprintf-s-l

If __USE_MINGW_ANSI_STDIO is defined as 1 before the stdio.h include, this example does null-terminate, but I neither know what else that does entail, nor does it help the case of non-conformity.

Out of curiosity, I installed an old mingw32 version from Sourceforge (which seems to be from 2013?) and it did not have this issue.

A very simple but also very exhausting workaround is to always do:

  1. int ret = snprintf(buffer, sizeof(buffer), "%s", "abcd");
  2. if (ret < 0)
  3. buffer[sizeof(buffer)-1] = '\0';

Ticket History (3/3 Histories)

2019-08-27 04:45 Updated by: lazybumhorse
  • New Ticket "v/snprintf don't null-terminate when truncating" created
2019-09-05 23:09 Updated by: keith
  • Resolution Update from None to Invalid
  • Status Update from Open to Closed
Comment

Reply To lazybumhorse

Using MSYS2 on Windows 7, snprintf and vsnprintf are not C99+ standard compliant because they do not null-terminate when truncating.

Who cares? MSYS2 is not a product of this project; we do not support it.

errno is ERANGE and this seems to indicate it is using _vsnprintf (from msvcrt.dll?), at least it is similar in behavior to _vsnprintf_s, minus the null-termination: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/snprintf-s-snprintf-s-l-snwprintf-s-snwprintf-s-l

Be that as it may, genuine MinGW implementations of snprintf() and vsnprintf() exhibit correct C99 behaviour; if that's what your source calls out, that's what you will get. If you want the weird Microsoft behaviour, then you must explicitly use their functions.

If __USE_MINGW_ANSI_STDIO is defined as 1 before the stdio.h include, this example does null-terminate, but I neither know what else that does entail, nor does it help the case of non-conformity.

Well, that's misuse of an internally reserved symbolic constant name, but it's irrelevant in the case of genuine MinGW snprintf() and vsnprintf() anyway; if you call out the C99 functions, you get C99 behaviour. However, if you aren't using genuine MinGW products, it's anybody's guess what might happen.

2019-09-06 06:57 Updated by: lazybumhorse
Comment

Reply To keith

Who cares? MSYS2 is not a product of this project; we do not support it.

Oh! This (and some more research) finally cleared my confusion!

I was under the impression MSYS2 had genuine MinGW packages, but the packages are actually of MinGW-w64, which is a fork of this project and that is using the MSVC printf family by default for whatever reason.

Attachment File List

No attachments

Edit

Please login to add comment to this ticket » Login