0

When I am trying to use the strcpy function the visual studio gives me an error

error C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.

After searching online and many answers from StackOverflow, the summary is that strcpy_s is safer than strcpy when copying a large string into a shorter one. So, I tried the following code for coping into shorter string:

char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(a), a);
printf("String = %s", b);

The code copiles successfuly. However, there is still a runtime error: enter image description here

So, how is scrcpy_s is safe? Am I understanding the safty concept wrong?

Osama El-Ghonimy
  • 335
  • 2
  • 12
  • 1
    You have not called [`strcpy_s`](https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/strcpy-s-wcscpy-s-mbscpy-s?view=vs-2019) correctly, so this is imaginary code. Please post the [Minimal Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example) that shows the problem. Unless you enable full compiler warnings and deal with them, nothing is "safer". – Weather Vane Dec 08 '19 at 20:45
  • `strcpy_s(a, b);` should never compile, it's missing a parameter – UnholySheep Dec 08 '19 at 20:45
  • You have the arguments back to front too. `strcpy_s(a, b);` overwrites an initialised string with an unitialised one. – Weather Vane Dec 08 '19 at 20:50
  • Sorry for this error. I edited the question. Please recheck – Osama El-Ghonimy Dec 08 '19 at 20:52
  • 2
    The second parameter is the size of the destination buffer (`sizeof b`), not the source (`sizeof a`) - so you are calling the function with wrong parameters still – UnholySheep Dec 08 '19 at 20:54
  • Standard C already has `strncpy`. The MS versions are no safer, and some of them even less safe because they are tricky to use. For example `scanf_s` is **NOT** a direct replacement for `scanf`. – Weather Vane Dec 08 '19 at 20:55
  • So, I might be confused between the buffer and the string itself. I think this is my problem. Would you please explain more? @UnholySheep – Osama El-Ghonimy Dec 08 '19 at 20:55
  • @weathervane `strncpy` isn't necessarily safer, as it can leave the destination without a NUL terminator. – Jonathon Reinhart Dec 08 '19 at 20:58
  • 1
    `strcpy_s(b, sizeof(a), a);` should be `strcpy_s(b, sizeof(b), a);` - you are providing the wrong size for the destination in the function call. This has nothing to do with buffers or strings (which in this case are nearly the same thing), you need to provide the correct parameters to a function call – UnholySheep Dec 08 '19 at 20:59
  • @JonathonReinhart true, but it's a standard function. – Weather Vane Dec 08 '19 at 20:59
  • @UnholySheep I understand you. However, this function is said to be safer to such situations. Is this right? – Osama El-Ghonimy Dec 08 '19 at 21:00
  • If no, what is the difference then between it and strcpy if it is not safe to that situations? – Osama El-Ghonimy Dec 08 '19 at 21:01
  • It's true that `strcpy_s` includes a nul string terminator, whereas with `strncpy` it is not guaranteed. – Weather Vane Dec 08 '19 at 21:01
  • @WeatherVane Sorry I cannot get it? Would you please give me more details? So, both strcpy_s and strcpy are not safe againest the copy of longer string as I am thinking? – Osama El-Ghonimy Dec 08 '19 at 21:04
  • No function is safe against a programmer passing wrong parameters. It's the programmers responsibility to make sure they provide valid parameters. What `strcpy_s` aims to achieve is to avoid writing past the bounds of the destination buffer, but that requires you to actually "tell the function" how big that buffer is – UnholySheep Dec 08 '19 at 21:04
  • No function is safe is unless used correctly, as your first edit of the use of `strcpy_s` showed. This is C: don't be tricked by MS into thinking you can hand over safety to them. – Weather Vane Dec 08 '19 at 21:05
  • Thank you I think I got what you mean. So, the term safe is not about coping longer strings into shorter ones. Is this right? So, now, what makes strcpy_s more safe? Some details in explanation please. – Osama El-Ghonimy Dec 08 '19 at 21:08
  • You'll have to ask MS that, but you have to take *some* kinds of precaution when copying to a smaller buffer space. – Weather Vane Dec 08 '19 at 21:08

3 Answers3

6

Why is strcpy_s() "safer"? Well, it's actually quite involved. (Note that this answer ignores any specific code issues in the posted code.)

First, when MSVC tells you standard functions such as strcpy() are "deprecated", at best Microsoft is being incomplete. At worst, Microsoft is downright lying to you. Ascribe whatever motiviation you want to Microsoft here, but strcpy() and a host of other functions that MSVC calls "deprecated" are standard C functions and they are most certainly NOT deprecated by anyone other than Microsoft. So when MSVC warns you that a function required to be implemented in any conforming C compiler (most of which then flow by requirement into C++...), it omits the "by Microsoft" part.

The "safer" functions that Microsoft is "helpfully" suggesting that you use - such as strcpy_s() would be standard, as they are part of the optional Annex K of the C standard, had Microsoft implemented them per the standard.

Per N1967 - Field Experience With Annex K — Bounds Checking Interfaces

Microsoft Visual Studio implements an early version of the APIs. However, the implementation is incomplete and conforms neither to C11 nor to the original TR 24731-1. For example, it doesn't provide the set_constraint_handler_s function but instead defines a _invalid_parameter_handler _set_invalid_parameter_handler(_invalid_parameter_handler) function with similar behavior but a slightly different and incompatible signature. It also doesn't define the abort_handler_s and ignore_handler_s functions, the memset_s function (which isn't part of the TR), or the RSIZE_MAX macro. The Microsoft implementation also doesn't treat overlapping source and destination sequences as runtime-constraint violations and instead has undefined behavior in such cases.

As a result of the numerous deviations from the specification the Microsoft implementation cannot be considered conforming or portable.

Outside of a few specific cases (of which strcpy() is one), whether Microsoft's version of Annex K's "safer" bounds-checking functions are safer is debatable. Per N1967 (bolding mine):

Suggested Technical Corrigendum

Despite more than a decade since the original proposal and nearly ten years since the ratification of ISO/IEC TR 24731-1:2007, and almost five years since the introduction of the Bounds checking interfaces into the C standard, no viable conforming implementations has emerged. The APIs continue to be controversial and requests for implementation continue to be rejected by implementers.

The design of the Bounds checking interfaces, though well-intentioned, suffers from far too many problems to correct. Using the APIs has been seen to lead to worse quality, less secure software than relying on established approaches or modern technologies. More effective and less intrusive approaches have become commonplace and are often preferred by users and security experts alike.

Therefore, we propose that Annex K be either removed from the next revision of the C standard, or deprecated and then removed.

Note, however, in the case of strcpy(), strcpy_s() is actually more akin to strncpy() as strcpy() is just a bog-standard C string function that doesn't do bounds checking, but strncpy() is a perverse function in that it will completely fill its target buffer, starting with data from the source string, and filling the entire target buffer with '\0' char values. Unless the source string fills the entire target buffer, in which case strncpy() will NOT terminate it with a '\0' char value.

I'll repeat that: strncpy() does not guarantee a properly terminated copy.

It's hard not to be "safer" than strncpy(). In this case strcpy_s() does not violate the principle of least astonishment like strncpy() does. I'd call that "safer".

But using strcpy_s() - and all the other "suggested" functions - makes your code de facto non-portable, as Microsoft is the only significant implementation of any form of Annex K's bounds-checking functions.

Community
  • 1
  • 1
Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
0

The header definiton for C is:

errno_t strcpy_s(char *dest,rsize_t dest_size,const char *src)

The invocation for your example should be:

#include <stdlib.h>

char a[50] = "void";
char b[3];
strcpy_s(b, sizeof(b), a);
printf("String = %s", b);
-1

strcpy_s needs the size of the destination, which is smaller than the source in your example.

strcpy_s(b, sizeof(b), a);

would be the way to go.

As for the safety concept, there are many checks now done, and better ways to handle errors.

In your example, had you used strcpy, you would have triggered a buffer overflow. Other functions, like strncpy or strlcpy, would have copied the 3 first characters without any null-byte terminator, which in turn would have triggered a buffer overflow (in reading, this time).

David Larochette
  • 1,200
  • 10
  • 18
  • Yes, @JL2210 I am also believing that Microsoft has a lot of junk in its products. However, as far as I know, the new _s functions are included in the new C standards. So, they must have any meaning. Unless you mean that Microsoft is not implementing them properly in their compiler. – Osama El-Ghonimy Dec 08 '19 at 21:59
  • @OsamaEl-Ghonimy MS CS does not implement `_s` well in some areas of Annex K - which is optional - notably the type used in size parameters. – chux - Reinstate Monica Dec 08 '19 at 22:10