sprint_f macro in Linux for cross-platform application - c++

I'm porting an existing Windows application to Linux.
The most of the OS APIs\ Microsoft non-standard extension functions can be easily (more or less...) replaced by equivalent Linux\ GCC APIs, however, I don't know how to deal with sprintf_s which gets variable numbers of arguments.
Does anyone have an idea (If you can please put the code example as well) for that?
Thank you all in advance.

First, can you just port your code to use C++ iostreams instead (for example ostringstream)? This would completely remove all the possible issues with the sprintf line of functions, and if there are a limited number of call points is probably the best option.
If that isn't an option: The sprintf_s function is basically a helper to prevent mistakes (and external abuse to cause buffer overflows. From http://msdn.microsoft.com/en-us/library/ce3zzk1k%28VS.80%29.aspx we learn that it does two things: It checks the format string for valid formats (this doesn't mean it does type checking - it still can't do that), and it allows a max length to be specified.
The best replacement will be snprintf which does have limitations compared to sprintf_s. It won't do format string validation. And not all versions guarantee that the final string will be null terminated: You always want to also store a null into the last character of your buffer after the call to ensure that the final string is null terminated.

Add to end of your header file or beginning of source file:
#ifndef _WIN32
#define sprintf_s(dest,len,format,...) sprintf(dest,format,__VA_ARGS__)
#endif

snprintf has the same signature, but AFAIK it behaves in a slightly different way.

sprintf_s is just a "secure" version (takes buffer length as extra argument) of sprintf , cant you just use sprintf for your port ?

Why not just provide a conditionally compiled implementation of sprintf_s for Linux? This implementation could simply ignore the extra argument and call through to sprintf().

Related

inet_ntoa() in Winsock2 is deprecated?

I was experimenting with Winsock2 at the moment, and got a warning that inet_ntoa() is deprecated and that I should use inet_pton(). I tried it, but it was little endian, so the whole string that was saved in the buffer was "wrong". I'm guessing inet_ntoa() is big endian?
And I could only use inet_pton() with #include <ws2tcpip.h>, so for me it just gets more confusing from here on. Why should I use something else outside the <winsock2.h> library?
Currently, I'm avoiding this by using #pragma warning(disable : 4996), which I don't like, because I just don't want to ignore all warnings.
This whole Winsock topic is like a maze for me, sorry if I'm missing some information, hope that's enough.
inet_pton() is NOT the successor for inet_ntoa(), but for inet_addr() instead. You want inet_ntop() instead.
inet_ntoa()/inet_ntop() convert an IP address from binary form to string form. inet_addr()/inet_pton() do the opposite conversion.
However, there are actually several functions that you can use instead of inet_ntoa(), including getnameinfo(), WSAAddressToString(), RtlIpv4AddressToString()/RtlIpv6AddressToString(), etc.
That being said, yes inet_ntoa() is indeed deprecated, because it only support IPv4 addresses. Functions like inet_ntop(), getnameinfo(), etc support both IPv4 and IPv6 addresses, which makes writing IP version-agnostic code a bit easier.
If you are having trouble with inet_ntop() then you are using it wrong, but you did not show your code. IPv4 addresses are always expressed in binary form in "network byte order" (big endian), even on little endian systems, like Windows.
As for <ws2tcpip.h>, that is part of the Winsock2 library. Nothing requires an API to only have 1 header file (indeed, the Win32 API as a whole consists of thousands of header files, beginning with but not limited to <windows.h>).
The correct way to deal with the deprecation warning is to update your code to use a modern API that is not deprecated, like it wants you to. Otherwise, if that is not an option for you at this time, then at the very least you can use #pragma warning(suppress : 4996) on just the affected code, rather than use #pragma warning(disable : 4996) globally. Or, you can define _WINSOCK_DEPRECATED_NO_WARNINGS in your project setup, or you can #define it in your code before #include'ing any Winsock2 headers.
inet_ntoa() has several limitations that limit its usefulness in the modern world.
For one thing, it only works for IPv4 addresses -- if you need to convert an IPv6 address into human-readable text, you're out of luck as far as inet_ntoa() is concerned.
Another problem is that inet_ntoa() returns a char * that points to a static buffer, which is problematic -- if you don't immediately copy out the string into somewhere else, the static buffer's contents might be overwritten by another sockets-API call before you read it, which could be a difficult runtime bug to track down and fix. (There might also be race-conditions possible when multiple threads are calling inet_ntoa() around the same time, although the wording of Microsoft's documentation page makes me suspect that Microsoft may be returning a pointer to a thread-local buffer to avoid that particular can of worms)
Best practice would therefore be to avoid calling inet_ntoa() if possible, and call its modern replacement inet_ntop() instead. (inet_ntop() is a bit harder to use, but it avoids the problems listed above)

This function or variable may be unsafe [duplicate]

I'm trying to get rid of some compiler warnings that say strcpy, sprintf, etc are unsafe.
I get why they're unsafe, but I can't think of a good way to fix the code, in a C++ style.
Here's a excerpt of the code:
extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName); // unsafe
// strncpy(extList->names[i],extName,length); // also unsafe
Here's the message:
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.
I can't think of a safe way to copy the data over in C++ without knowing the length of the stuff to copy.
I know there's strlen(), but that's also unsafe since it assumes (maybe incorrectly) that the data is null-terminated.
Also:
// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);
C4996: 'sprintf': This function or variable may be unsafe. Consider
using sprintf_s instead. To disable deprecation, use
_CRT_SECURE_NO_WARNINGS. See online help for details.
Using std::string to concatenate is easy enough, but then I need to get the data into extStr somehow (and not using strcpy, lol). The string::c_str() function returns a pointer to un-modifiable data, so I can't just set extStr equal to it. (And I'm not even sure if the c_str() pointer needs delete called on it later? Does it allocate space using "new"?)
Any advice on this stuff?
This is part of a 10,000 line file that's not mine... so I'm not exactly keen on re-writing the thing in the C++ way.
You don't really need pragmas to disable them.
For win32/msvc, in ProjectProperties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, add following macros:
_CRT_SECURE_NO_DEPRECATE
_CRT_NONSTDC_NO_DEPRECATE
Or you can pass thos in command line parameters (-D_CRT_SECURE_NO_DEPRECATE). You can probably #define them at the beginning of certain *.cpp files.
Also, there are probably more of them (see crtdefs.h - looks like there are a lot of them...). Those kind of warnings normally tell you with which macros you can disable them - just read compiler output.
Here is another answer to this question.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
strcpy(destination, source);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
If getting rid of warnings only is your objective... simply define this _CRT_SECURE_NO_WARNINGS and it will suppress all the deprecation warnings. But this will not fix the underlying problems with unsafe CRT functions.
If you are on visual studio version >= 2005 and want to fix these warnings in a proper way... easiest method is to #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 and #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 in your project.
without any further code changes you can observe most of the warnings are fixed automatically. By defining this windows will automatically call the secure overloaded functions for most of the unsafe CRT functions. Buffer sizes for static arrays are calculated automatically.
Although Dynamically allocated buffers are not fixed by this way and we need to fix them manually. Please refer this link for further details.
Below is a way to correct your example programatically
strcpy_s(extList->names[i], length, extName);
You do know how much to copy - you allocated space for it!
Surely you wouldn't willingly copy more than the space you allocated?
I would prefer to use a method that explicitly avoids buffer overruns by limiting the number of items copied. Back when I was a C programmer we used
dest = malloc(len); // note: where did we get len?
if ( dest is null ) panic! // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;
This is slightly messy, and has been pointed out is using strncpy() a method which really was originally designed for fixed-width fields rather than strings. However it does ach
There are methods such as strdup() and strlcpy() which may we help.
My recommendations:
1). Your target should not be to suppress warnings but to make the code robust.
2). When copying strings you need to ensure these things:
Protect yourself from bad input, for example an unterminated or excessively long string.
Protect yourself from malloc failures,
Strongly prefer copies of counted numbers of characters to copying until we see a null
If you claim to build a string, then make abolsutely sure you null terminate it
If strlcpy() is available in your environment then you could use it, otherwise why not write your own little utilityy function? Then if there are warnings in just that function you've localised then problem.
In your first example, you know the length already. Since you aren't allocating length+1 bytes I'll assume that length INCLUDES the null terminator. In that case, just std::copy the string: std::copy(extName, extName + length, expList->names[i]);
In your second example assuming the source strings are null terminated you could compute the destination string length and use std::copy again to concatenate manually, or you could use std::string and the std::copy from the results of c_str into your destination (Again assuming you allocated enough space for it).
c_str() does not allocate memory that would require external deletion.
Finally note that sizeof(char) will always be one and so is redundant in your malloc, although the number of bits in that character may not be 8 (See CHAR_BIT).
I think that you should replace all the function-calls if possible to call an implementation of your own. A good example here would be a function to replace strcpy and call the compiler-specific version of strcpy inside it. Your implementation can then easily be modified to suit any compiler of your choice, specifically if you will be adding or changing platforms/compilers.
Example:
char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
return strcpy_s(Destination, Source, DestinationSize);
#else
if(!(strlen(Source) >= DestinationSize))
return strcpy(Destination, Source);
else
return 0x0;
#endif
}
If portability is not a concern, you can use 'strcpy_s'.
as it is suggested in the message, use _CRT_SECURE_NO_WARNINGS to disable this warnings.
in ProjectProperties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, add following macros:
_CRT_SECURE_NO_WARNINGS
If this code is only to be compiled for windows platform then it is better to use the secured version of these functions. However, if this code is going to compiled across multiple platforms(linux, Aix etc) then either you can disable the warning in your windows project configuration file (for example, .vcxproj) by using _CRT_SECURE_NO_WARNINGS or, you can use a code snippet like this one in places where those functions have been called in the .cpp file.
#if _OS_ == _OS__WINDOWS
//secure function call
#else
//already written code
#endif

How to get rid of "unsafe" warnings / errors in Visual Studio (strcpy, sprintf, strdup)

I'm trying to get rid of some compiler warnings that say strcpy, sprintf, etc are unsafe.
I get why they're unsafe, but I can't think of a good way to fix the code, in a C++ style.
Here's a excerpt of the code:
extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName); // unsafe
// strncpy(extList->names[i],extName,length); // also unsafe
Here's the message:
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.
I can't think of a safe way to copy the data over in C++ without knowing the length of the stuff to copy.
I know there's strlen(), but that's also unsafe since it assumes (maybe incorrectly) that the data is null-terminated.
Also:
// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);
C4996: 'sprintf': This function or variable may be unsafe. Consider
using sprintf_s instead. To disable deprecation, use
_CRT_SECURE_NO_WARNINGS. See online help for details.
Using std::string to concatenate is easy enough, but then I need to get the data into extStr somehow (and not using strcpy, lol). The string::c_str() function returns a pointer to un-modifiable data, so I can't just set extStr equal to it. (And I'm not even sure if the c_str() pointer needs delete called on it later? Does it allocate space using "new"?)
Any advice on this stuff?
This is part of a 10,000 line file that's not mine... so I'm not exactly keen on re-writing the thing in the C++ way.
You don't really need pragmas to disable them.
For win32/msvc, in ProjectProperties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, add following macros:
_CRT_SECURE_NO_DEPRECATE
_CRT_NONSTDC_NO_DEPRECATE
Or you can pass thos in command line parameters (-D_CRT_SECURE_NO_DEPRECATE). You can probably #define them at the beginning of certain *.cpp files.
Also, there are probably more of them (see crtdefs.h - looks like there are a lot of them...). Those kind of warnings normally tell you with which macros you can disable them - just read compiler output.
Here is another answer to this question.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4996)
#endif
strcpy(destination, source);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
If getting rid of warnings only is your objective... simply define this _CRT_SECURE_NO_WARNINGS and it will suppress all the deprecation warnings. But this will not fix the underlying problems with unsafe CRT functions.
If you are on visual studio version >= 2005 and want to fix these warnings in a proper way... easiest method is to #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 and #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 in your project.
without any further code changes you can observe most of the warnings are fixed automatically. By defining this windows will automatically call the secure overloaded functions for most of the unsafe CRT functions. Buffer sizes for static arrays are calculated automatically.
Although Dynamically allocated buffers are not fixed by this way and we need to fix them manually. Please refer this link for further details.
Below is a way to correct your example programatically
strcpy_s(extList->names[i], length, extName);
You do know how much to copy - you allocated space for it!
Surely you wouldn't willingly copy more than the space you allocated?
I would prefer to use a method that explicitly avoids buffer overruns by limiting the number of items copied. Back when I was a C programmer we used
dest = malloc(len); // note: where did we get len?
if ( dest is null ) panic! // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;
This is slightly messy, and has been pointed out is using strncpy() a method which really was originally designed for fixed-width fields rather than strings. However it does ach
There are methods such as strdup() and strlcpy() which may we help.
My recommendations:
1). Your target should not be to suppress warnings but to make the code robust.
2). When copying strings you need to ensure these things:
Protect yourself from bad input, for example an unterminated or excessively long string.
Protect yourself from malloc failures,
Strongly prefer copies of counted numbers of characters to copying until we see a null
If you claim to build a string, then make abolsutely sure you null terminate it
If strlcpy() is available in your environment then you could use it, otherwise why not write your own little utilityy function? Then if there are warnings in just that function you've localised then problem.
In your first example, you know the length already. Since you aren't allocating length+1 bytes I'll assume that length INCLUDES the null terminator. In that case, just std::copy the string: std::copy(extName, extName + length, expList->names[i]);
In your second example assuming the source strings are null terminated you could compute the destination string length and use std::copy again to concatenate manually, or you could use std::string and the std::copy from the results of c_str into your destination (Again assuming you allocated enough space for it).
c_str() does not allocate memory that would require external deletion.
Finally note that sizeof(char) will always be one and so is redundant in your malloc, although the number of bits in that character may not be 8 (See CHAR_BIT).
I think that you should replace all the function-calls if possible to call an implementation of your own. A good example here would be a function to replace strcpy and call the compiler-specific version of strcpy inside it. Your implementation can then easily be modified to suit any compiler of your choice, specifically if you will be adding or changing platforms/compilers.
Example:
char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
return strcpy_s(Destination, Source, DestinationSize);
#else
if(!(strlen(Source) >= DestinationSize))
return strcpy(Destination, Source);
else
return 0x0;
#endif
}
If portability is not a concern, you can use 'strcpy_s'.
as it is suggested in the message, use _CRT_SECURE_NO_WARNINGS to disable this warnings.
in ProjectProperties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, add following macros:
_CRT_SECURE_NO_WARNINGS
If this code is only to be compiled for windows platform then it is better to use the secured version of these functions. However, if this code is going to compiled across multiple platforms(linux, Aix etc) then either you can disable the warning in your windows project configuration file (for example, .vcxproj) by using _CRT_SECURE_NO_WARNINGS or, you can use a code snippet like this one in places where those functions have been called in the .cpp file.
#if _OS_ == _OS__WINDOWS
//secure function call
#else
//already written code
#endif

tmpnam warning saying it is dangerous

I get this warning saying that tmpnam is dangerous, but I would prefer to use it, since it can be used as is in Windows as well as Linux. I was wondering why it would be considered dangerous (I'm guessing it's because of the potential for misuse rather than it actually not working properly).
From tmpnam manpage :
The tmpnam() function generates a different string each time it is called, up to TMP_MAX times. If it is called more than TMP_MAX times, the behavior is implementation defined.
Although tmpnam() generates names that are difficult to guess, it is nevertheless possible that between the time that tmpnam() returns a pathname, and the time that the program opens it, another program might create that pathname using open(2), or create it as a symbolic link. This can lead to security holes. To avoid such possibilities, use the open(2) O_EXCL flag to open the pathname. Or better yet, use mkstemp(3) or tmpfile(3).
Mktemp really create the file, so you are assured it works, whereas tmpnam returns a name, possibly already existing.
If you want to use the same symbol on multiple platforms, use a macro to define TMPNAM. As long as you pick more secure functions with the same interface, you'll be able to use it on both. You have conditional compilation somewhere in your code anyway, right?
if you speak about the compiler warning of MSVC:
These functions are deprecated because more secure versions are available;
see tmpnam_s, _wtmpnam_s.
(http://msdn.microsoft.com/de-de/library/hs3e7355(VS.80).aspx)
otherwise just read what the manpages say about the drawbacks of this function. it is mostly about a 2nd process creating exactly the same file name as your process just did.
From the tmpnam(3) manpage:
Although tmpnam() generates names that are difficult to guess, it is nevertheless possible that between the time
that tmpnam() returns a pathname, and the time that the program opens it, another program might create that path‐
name using open(2), or create it as a symbolic link. This can lead to security holes. To avoid such possibili‐
ties, use the open(2) O_EXCL flag to open the pathname. Or better yet, use mkstemp(3) or tmpfile(3).
The function is dangerous, because you are responsible for allocating a buffer that will be big enough to handle the string that tmpnam() is going to write into that buffer. If you allocate a buffer that is too small, tmpnam() has no way of knowing that, and will overrun the buffer (Causing havoc). tmpnam_s() (MS's secure version) requires you to pass the length of the buffer, so tmpnam_s know when to stop.

Issue with using std::copy

I am getting warning when using the std copy function.
I have a byte array that I declare.
byte *tstArray = new byte[length];
Then I have a couple other byte arrays that are declared and initialized with some hex values that i would like to use depending on some initial user input.
I have a series of if statements that I use to basically parse out the original input, and based on some string, I choose which byte array to use and in doing so copy the results to the original tstArray.
For example:
if(substr1 == "15")
{
std::cout<<"Using byte array rated 15"<<std::endl;
std::copy(ratedArray15,ratedArray15+length,tstArray);
}
The warning i get is
warning C4996: 'std::copy': Function call with parameters
that may be unsafe
- this call relies on the caller to check that the passed
values are correct.
A possible solution is to to disable this warning is by useing -D_SCL_SECURE_NO_WARNINGS, I think. Well, that is what I am researching.
But, I am not sure if this means that my code is really unsafe and I actually needed to do some checking?
C4996 means you're using a function that was marked as __declspec(deprecated). Probably using D_SCL_SECURE_NO_WARNINGS will just #ifdef out the deprecation. You could go read the header file to know for sure.
But the question is why is it deprecated? MSDN doesn't seem to say anything about it on the std::copy() page, but I may be looking at the wrong one. Typically this was done for all "unsafe string manipulation functions" during the great security push of XPSP2. Since you aren't passing the length of your destination buffer to std::copy, if you try to write too much data to it it will happily write past the end of the buffer.
To say whether or not your usage is unsafe would require us to review your entire code. Usually there is a safer version they recommend when they deprecate a function in this manner. You could just copy the strings in some other way. This article seems to go in depth. They seem to imply you should be using a std::checked_array_iterator instead of a regular OutputIterator.
Something like:
stdext::checked_array_iterator<char *> chkd_test_array(tstArray, length);
std::copy(ratedArray15, ratedArray15+length, chkd_test_array);
(If I understand your code right.)
Basically, what this warning tells you is that you have to be absolutely sure that tstArray points to an array that is large enough to hold "length" elements, as std::copy does not check that.
Well, I assume Microsoft's unilateral deprecation of the stdlib also includes passing char* to std::copy. (They've messed with a whole range of functions actually.)
I suppose parts of it has some merit (fopen() touches global ERRNO, so it's not thread-safe) but other decisions do not seem very rational. (I'd say they took a too big swathe at the whole thing. There should be levels, such as non-threadsafe, non-checkable, etc)
I'd recommend reading the MS-doc on each function if you want to know the issues about each case though, it's pretty well documented why each function has that warning, and the cause is usually different in each case.
At least it seems that VC++ 2010 RC does not emit that warning at the default warning level.