4

I maintain a fairly large piece of legacy code that still uses strncpy a lot. I have now started the process of replacing the usage of strncpy with its safe counterpart strncpy_s. I noticed that strncpy_s is padding the destination buffer with -2 values - but only in debug builds! In release builds no padding occurs.

For instance:

char buffer[3];
// buffer becomes 00000000  00000000  00000000
memset(buffer, 0, sizeof(buffer));
// buffer becomes 01100001  00000000  11111110
//                97 ('a')  0        -2
strncpy_s(buffer, sizeof(buffer), "a", _TRUNCATE);
// i is -2
int i = buffer[2];

The MSDN docs do not mention this padding behaviour, and in my case it's really something I don't want because my legacy code relies on the fact that the zeroed parts of the buffer remain zeroed and are not overwritten during string copying.

Is there a way how I can prevent strncpy_s from padding the destination string in debug builds?

Note that I have tested this with both Visual Studio 2010 and Visual Studio 2013.

herzbube
  • 13,158
  • 9
  • 45
  • 87

2 Answers2

7

The definition of strncpy_s is that elements beyond the null terminator take unspecified values. The definition of strncpy is that those elements are set to 0. If you don't want this behaviour, don't use strncpy_s.

Also, strncpy_s has different behaviour to strncpy in the case that the input is too big for the buffer.

There are few valid use cases for strncpy or strncpy_s. It's almost always better to either use strcpy, snprintf, or memcpy. My preference would strongly be to use whichever of those three functions is best suited to the task.

Calling it a "safe counterpart" is rather an exaggeration, IMO. The "non-safe" versions are actually all perfectly safe if you pass the correct arguments to them; and if you do not pass correct arguments then neither variety is safe.

If your code that uses strncpy is actually not bugged, and you rely on the zero-padding feature, then there is no reason to change it.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • And like you explained, replacing `strncpy` with `strncpy_s` is almost always an error, and when it isn't `strcpy_s` or `strcpy` are superior alternatives. (I didn't know before that `strncpy_s` is totally borked in a completely different way from `strncpy`). – Deduplicator Sep 24 '14 at 12:38
  • I will look into using `strcpy_s`, however `strcpy_s` has the same padding behaviour as `strncpy_s`. Also, I don't agree with your statement "The definition of strncpy_s is that elements beyond the null terminator take unspecified values." Is this stated somewhere in the docs? I couldn't find such a statement, neither explicit nor implicit. – herzbube Sep 24 '14 at 13:01
  • Read the C11 standard, section K.3.7.1.4 . You can download a free draft by following links [here](http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents) – M.M Sep 24 '14 at 13:01
  • I was living under the impression that `strncpy_s` is a Microsoft specific function, but I may very well be wrong, so I downloaded the latest publicly available draft (N3797). In that draft, I could not find any mention of the function `strncpy_s`, nor of a section K.3.7.1.4. – herzbube Sep 24 '14 at 13:26
  • N3797 is a C++ document. Look for N1570 from the C group. MS invented these _s versions and the C11 committee agreed to add them, so it seems likely that their C++ versions are the same. – M.M Sep 24 '14 at 13:33
  • Ah, found it! Thanks for educating me about the standards. – herzbube Sep 24 '14 at 15:24
5

strcpy_s() will fill in the buffer with 'FE' in debug mode only.

You can turn this off explicitly by calling _CrtSetDebugFillThreshold(0)

Leo Chapiro
  • 13,678
  • 8
  • 61
  • 92
  • 1
    I only now noticed that the very last sentence of the `strncpy_s` documentation mentions this function. My bad... Anyway, I am accepting your answer because it's the one that actually solves my problem. Even if I use `strcpy_s` (as everybody else tells me to) I will have to call `_CrtSetDebugFillThreshold`. – herzbube Sep 24 '14 at 13:09