Microsoft Visual Studio: Secure CRT Functions

Introduction

Two programmers went to buy cigarettes. One buys them and goes "Dude, did you read this? Warning! Smoking causes lung cancer witch is fatal". Then the other one says "Yeah, forget the warning, just tell me the errors!"

When using Microsoft Visual Studio 2005 or newer, the compiler may give a bunch of annoying warnings saying something like: "warning 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". CRT functions like strcpy are standard functions, so why the compiler complains? Well, it simply recommends using of more secure versions of CRT functions which have '_s' postfix (strcpy_s instead of strcpy, sprintf_s instead of sprintf and so on). So, at a first look nothing fatal happened and we can go ahead. However, simply ignoring the warnings is not a good practice and moreover someone may work in a company or project in which "zero warnings" is a must.

This article is about how to deal with C4996 warning, what secure CRT functions are and how to correctly use them. Further, let's call them "_s functions".

Can we get rid of C4996 warnings?

Especially when porting code written under an older Visual C++ version, we may want to get rid of C4996 warnings. The answer is: yes, we can like in case of other compiler warnings, by adding pragma warning directive in the source code.

#pragma warning(disable: 4996)

You may add pragma warning in each source file or, if the project uses precompiled header, adding only it in StdAfx.h is pretty enough.

Another and better way is to add _CRT_SECURE_NO_WARNINGS to preprocessor definitions, as suggested in the description of the warning. To find out how to add _CRT_SECURE_NO_WARNINGS, take a look in MSDN at /D (Preprocessor Definitions).

No warnings, no more headaches, and the boss is happy. However, please read further! One good way to avoid C4996 warnings is… by using _s functions.

Why using _s functions?

Here, I would like to quote from one of Michael Howard's articles:

Think about it for a moment. When were functions like strcpy and strcat invented? They were designed in happier times when the C language was first developed by Kernighan and Ritchie long ago, when threats were by no means as serious as they are today, and when networking wasn't as pervasive as it is today. Now don't get me wrong, you can write secure code with functions like strcpy. It's the data that's the culprit, after all. But functions like strcpy don't help you write secure code, and an error in such a function can be catastrophic. Of course, gets is just plain evil! 'Nuff said.

I heard C/C++ programmers saying: "I've never ever made a bug". That's pretty possible if they never ever made a line of code. Otherwise, I can't believe them. Nobody is perfect and everyone can do mistakes.
In the first side, standard C functions were designed for speed. For that reason, they do not perform run-time checking which is usually performed in other programming languages. A programmer must be carefully when use those functions and validate parameters in the own code in order to avoid troubles like buffer overrun, access violation, malicious attacks, and so on.

Well, _s functions do additional checking for you. Details about Security Enhancements in the CRT can be found in MSDN library.
I will give just a trivial example concerning null termination string problem. One can say "this is stupid, something like that can never happen". Wrong! In the real programming world, other ones even more stupid, much more insidious and having uglier effects, can be found.

Two strings walk into a bar. One of them says: "A beer, please!%@8Hj(^&9))%@!$%*" The other one says: "You'll have to excuse my friend, he is not zero-terminated."

May be a good programmers' joke, but in a C/C++ application, a not-zero terminated string is not so funny. Let's try translating it into code:

#define MAX_BUFFER 1000
void append_joke(char* buff, const char* psz)
{
   strcat(buff, psz); // classic
}

int main()
{
   char* joke = new char[MAX_BUFFER];
   memcpy(joke, "A beer, please!", strlen("A beer, please!"));
   append_joke(joke, "You'll have to excuse my friend…");
   printf(joke);
   delete []joke;
#ifdef _DEBUG
   system("pause");
#endif
   return 0;
}

If the program doesn't crash (here because of heap corruption) we can't say that we are lucky. The result may be a bunch of garbage like in the above joke. But if we use strcat_s instead of strcat, a run-time checking against not properly null terminated string will be performed. Further we'll see what's happen in this case.

Do _s functions prevent program crashing?

Most of programmers dealing first time with _s functions think that program will never crash even they are doing mistakes. In other words, simply replacing standard CRT functions with more secure ones, prevents application crashing. That is not true. Let's modify append_joke function and replace strcat with "more secure" strcat_s.

void append_joke(char* buff, const char* psz)
{
   strcat_s(buff, MAX_BUFFER, psz); // more secure
}

Now, let's run again the program in debug mode. Oups!.. A "Debug Assertion Failed" message box is shown. If press "Ignore" button, another "fatal error" message is shown then program terminates. What happened? First, strcat_s function checks parameters validity. If one is invalid (in our example we have not null terminated string) and if the program runs in debug mode, a "debug assertion failed" message is shown. That's very good, because we have a chance to fix the mistake, first looking at assertion message (here is "String is not null terminated"), then pressing "Retry" and search the source of error in "Call Stack" window. That is not possible in case of using the "classic" function strcat.
Finally, an invalid parameter handler function is called and the process terminates. That's also good because, if something is really going bad, it's preferable to close the application instead of let it doing unpredictable things.

How to customize the _s functions behavior?

As stated above, when _s functions detect an invalid parameter, a message is shown then the application process terminates. However, someone may want to do something else before application exits or simply wants application to continue. Someone else may wonder why the _s functions return an error code as long as by default, if an invalid parameter is passed, the process is terminated. Well, the default invalid parameter handler function may be replaced with an application-defined one. For doing that, we can call _set_invalid_parameter_handler function.

Here is an example. It prevents showing the debug assertion failure message and sets an application-defined invalid parameter handler function. In case that invalid parameter is passed, the process isn't terminated. Also, the error code returned by strcat_s is used by program, which prints out the string only if it's Ok.

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

void app_handler(const wchar_t * expression,
                 const wchar_t * function, 
                 const wchar_t * file, 
                 unsigned int line,
                 uintptr_t pReserved)
{
   wprintf_s(L"%s\nFunction:%s\nFile:%s\nLine:%u\n",  
             expression, function, file, line);
}

#define MAX_BUFFER 1000
errno_t finish_joke(char* buff, const char* psz)
{
   return strcat_s(buff, MAX_BUFFER, psz); 
}

int main()
{
   // prevent showing "debug assertion failed" dialog box
   _CrtSetReportMode(_CRT_ASSERT, 0); 
    // set application-defined invalid parameter handler
   _set_invalid_parameter_handler(app_handler);
   
   char* joke = new char[MAX_BUFFER];
   memcpy(joke, "A beer, please!", strlen("A beer, please!"));
   errno_t ret = finish_joke(joke, "You'll have to excuse my friend…");
   if(0 == ret) // prints only if finish_joke succeeded
   {
      printf_s(joke);
   }
   delete []joke;
#ifdef _DEBUG
   system("pause");
#endif
   return 0;
}

Conclusion

  • It's no sweat to get rid of C4996 warnings but also it's good to know that secure CRT functions are great.
  • Secure CRT functions perform run-time parameters checking which helps to find mistakes and prevent troubles.
  • The default invalid parameter handler terminates the aplication process; if we want to change this, we have to use an application-defined handler.
  • Last but not the least: if you want to write more solid and secure code, prefer using secure version of CRT functions!

See also

 



About the Author

Ovidiu Cucu

Graduated at "Gh. Asachi" Technical University - Iasi, Romania. Programming in C++ using Microsoft technologies since 1995. Microsoft MVP awardee since 2006. Moderator and article reviewer at Codeguru.com, the number one developer site. Co-founder of Codexpert.ro, a website dedicated to Romanian C++ developers.

Related Articles

Comments

  • International swim couplet official sighs with emotion Only Wu Minxia still is holding to nowadays0

    Posted by lfwonxaaxw on 05/18/2013 12:07am

    International swim couplet official sighs with emotion: Only Wu Minxia still is holding to nowadays Although the sports meet publicizes before London Olympic Games 8 player to be able to take part in the match, but this international swim Beijing of match of couplet diving set stands, according to international swim couplet announces take part in the match list, project of single person of 10 meters of diving tower has the man only 3 players attend the Garcia of the Lin Yue of the Minibayefu of Russia, China and Mexico, the Dampier of the Qiu Bo of the Budiya of before including London Olympic Games 3 United States, China and England inside numerous ace absent, how to compare to the project that only 3 people take part in the match? Makulaisi gave out yesterday the answer, "Because of the Olympic Games hind, some players are off, some get hurt, do not have a law to come so. " he says, "But the player complement that this we can allow two-men project comes over. "But the player complement that this we can allow two-men project comes over.. To the Chinese diving team that heads with Wu Minxia, makulaisi gave very high opinion, he says: "Only Wu Minxia is holding to. " and Wu Minxia will attend this only female the match of pair of 3 rice board, use pair of diligent of the court of a feudal ruler with Chongqing record player. Whether should hold to all the time to oneself in make an appointment with the Olympic Games, wu Minxia said yesterday: "The Olympic Games is being made an appointment with in still is a very far end to me, dare think now [url=http://jordankicks.page4.me/]jordan sneakers for sale[/url] far from more. My idea trains every time namely, had held position. Had held position.. J131 of Li Yuanfei of our newspaper reporter Article origin: Beijing evening paper

    Reply
  • A bit misleading

    Posted by mlgoff on 02/24/2011 02:39pm

    "To disable deprecation" The CRT functions that trigger this warning are NOT deprecated. Microsoft promised to stop inferring that these standard functions are deprecated. A promise they have not kept. It needs to be noted that the _s version for the CRT functions are Microsoft specific. They are not cross-platform nor are they portable. Shame on you for not even mentioning that fact, let alone making it clear.

    • RE: A bit misleading

      Posted by ovidiucucu on 02/25/2011 05:43am

      I know, there are many discussions beside the word 'deprecated'. That is not in scope of this short article. However, it offers solutions to both situations: using _s functions or, not using and simply getting rid of C4996 warnings. I think that's pretty fair and no reason to be ashamed... ;)

      Reply
    Reply
  • Good article!

    Posted by VictorN on 02/24/2011 12:06pm

    Very good explained and P8Q P8Q very easy to read!

    • RE: Good article!

      Posted by ovidiucucu on 02/25/2011 05:50am

      Especially the old jokes, I think... :-) Thank you, Victor!

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: September 10, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild". This loop of continuous delivery and continuous feedback is …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds