Why is strncpy marked as unsafe? - c++

I am getting a warning:
warning C4996: 'strncpy': This function or variable may be unsafe. Consider using strncpy_s instead.
To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
F:\vuStudio\VC\include\string.h(188) : see declaration of 'strncpy'
I read on stackoverflow.com that strcpy is not safe and I should use strncpy instead. But now why I am getting warning that strncpy is unsafe ?
I am calling it as:
strncpy(this->title, title.c_str(), sizeof(this->title));

strncpy has a few dangerous quirks.
First, it zeros the target buffer past the end of the copy, which can be surprising.
Second, if there is not enough room in the target buffer, it does not null terminate the target buffer.
Third, if it truncates, it 'mostly works'. Which discourages error handling (truncated strings are often worse than useless, but do not appear to be worse than useless at first glance).
strncpy_s requires an input length (or explicit truncation request), and errors if there is not enough room to null terminate (writing just a zero length string in the output). The input length is sometimes inefficient to provide (and not required for some of its changes), but it does guarantee a null terminated output buffer (so long as it isn't a nullptr, or zero length) even in error conditions. I am unsure if it zeros past the end of the copied string or not.
This behavior prevents or mitigates some common fenceposting errors in string code.

Visual studio compiler has it's own implementation of strncpy, you won't get this warning with gcc or clang. It is safe, and more portable (because strncpy_s is not standard) to use strncpy.
If you don't care about portability, strncpy_s is indeed more secure because it has an additional length check (but like strncpy it won't save you if you pass bad parameter).

The "n" variants of str functions (like strncmp, strncpy, etc) are the "safe" choice, because they all are limiting the size of string buffer used.
The "old" str functions (not the "n" variants, like strcpy) are all subject to many programming errors and memory attacks (off by one, heap overwriting, etc).

Related

Is it legal to read into an array that doesn't have space for the null terminator?

Every C string is terminated with the null character when it is stored in a C-string variable, and this always consumes one array position.
So why is this legal:
char name[3];
std::cin >> name;
when a 3 letter word "cow" is input to std::cin?
Why is it allowing this?
The compiler cannot know what input you will be giving at runtime, so it cannot say that you will be doing something illegal. If the input fits in the array, then it's legal.
Prior C++20:
The behaviour of the program is undefined. Never do this.
Since C++20:
The input will be truncated to fit into the array, so the array will contain the string "co".
It is allowed because the memory management is left to the programmer.
In this case the error occurs at run-time and it's impossible for the compiler to spot it at compile time.
What you are getting here is an undefined behavior, where the program can crash, can go on smoothly, or present some odd behavior in the future.
Most likely here you are overflowing the allocated memory by one byte which will be stored in the first byte of the subsequent declared variable, or in other addresses which may or may not be already filled with relevant information.
You eventually may experience an abort of the execution if - for example - some read-only memory area is overwritten, or if you point your Instruction Pointer to some invalid area (again, by overwriting its value in memory)
Depends what you mean by "legal". In context of your question, there is no precise meaning.
According to the standard (at least before C++20) your code (if supplied with that input) has undefined behaviour. When behaviour is undefined, any observable outcome is permitted, and no diagnostics are required.
In particular, there is no requirement that an implementation (the compiler, the host system, or anything else) diagnose a problem (e.g. issue an error message), take preventative action (e.g. electrocute the programmer for entering "cow" before hitting the enter key), or take recovery action (e.g. truncate the input to "co").
The reason the standard allows such things is a combination of;
allowing implementation freedoms. For example, the standard permits but does not require your host system to electrocute the user for entering bad input to your program - but doesn't prevent an evil-minded system developer providing hardware and driver support to do exactly that;
technical infeasibility or technical difficulty. In a simple case like your code might be easy to detect. But, in more complicated programs (e.g. your code is buried away among other code) it might be impossible to identify a problem. Or, it might be possible, but take much longer than a programmer is willing/able to spend waiting.
In short, the C++ standard does not coddle the programmer. The programmer - not the standard, not the compiler - is responsible for avoiding undefined behaviour, and responsible if a program with undefined behaviour does undesirable things.

Why in msvc++ we have _snprintf while other compilers allows snprintf

What "_" means? Why Microsoft adds this mark at the beginning?
Identifiers in the global namespace starting with _ are reserved for the implementation. _snprintf is just a function that the implementation (Visual Studio) has provided. As to the rationale for that, Visual Studio implements C89, and snprintf is part of a later C99 standard.
Besides that, the semantics of both functions are different in the return type, which in snprintf is always the number of characters that the formatted string takes (whether there was enough space in the buffer or not, while _snprintf will return a negative number if there is not enough space in the buffer.
That is, to allocate a buffer just large enough for the output you can do:
int size = snprintf( 0, 0, "%s %d\n", str, i );
char * buffer = malloc( size+1 );
snprintf( buffer, size+1, "%s %d\n", str, i );
You cannot do that with _snprintf as the only information that the function yields back is that the current size is not enough.
snprintf() was not yet part of the standard at the time Microsoft's C runtime began to support it.
Since the function prototype was not standardized, and the developers did not want to use the name snprintf (in case the standard later specified a different prototype), they opted to add a leading underscore to denote the function as being a Microsoft extension to the standard.
Adding to the above,
there are proper C99 snprintf() and vsnprintf() available since Visual Studio 2015
and they do not even trigger the well known unsafe function deprecation warning.
_snprintf_s() or _vsnprintf_s(), while provided, are "secure variants" of the MSVC-specific functions, with the non-C99 behavior.
Aside from a different return value in case of insufficiently large buffer (described in David's answer), functions from _sn... group differ from the standard snprintf in another important regard. If the target buffer is too short by just one character, the _sn... functions consider this situation a "success".
In more detail, if the target buffer is long enough to store the whole resultant sequence but without the terminating zero character, the _sn... functions do not truncate the result, do not write the terminating zero into the target buffer and return the size of the buffer as a result. So, in general case the result is not guaranteed to be zero-terminated.
In the same situation, snprintf will discard the last character of the resultant sequence and write zero terminator in its place. The result of snprintf is always zero-terminated.

SystemC error, using visual c++ 2008

I am using systemC with visual C++ 2008. I wrote a simple hello world program. However I am getting this error repeatedly:
warning C4996: 'sprintf': This function or variable may be unsafe.
Why this is happening? I would appreciate any help.
The compiler warns against sprintf() use because it may cause buffer overflow since it doesn't check buffer's limit. Instead, use snprintf() which never fills the buffer beyond the passed-in limit.
This advice is also given by the manpage:
Because sprintf() and vsprintf() assume an arbitrarily long string, callers must be
careful not to overflow the actual space; this is often impossible to assure. Note that
the length of the strings produced is locale-dependent and difficult to predict. Use
snprintf() and vsnprintf() instead (or asprintf(3) and vasprintf(3)).
It's insecure because - From MSDN
There is no way to limit the number of characters written, which means that code using sprintf is susceptible to buffer overruns. Consider using the related function _snprintf, which specifies a maximum number of characters to be written to buffer, or use _scprintf to determine how large a buffer is required. Also, ensure that format is not a user-defined string.

Safe counterparts of itoa()?

I am converting some old c program to a more secure version. The following functions are used heavily, could anyone tell me their secure counterparts? Either windows functions or C runtime library functions. Thanks.
itoa()
getchar()
strcat()
memset()
itoa() is safe as long as the destination buffer is big enough to receive the largest possible representation (i.e. of INT_MIN with trailing NUL). So, you can simply check the buffer size. Still, it's not a very good function to use because if you change your data type to a larger integral type, you need to change to atol, atoll, atoq etc.. If you want a dynamic buffer that handles whatever type you throw at it with less maintenance issues, consider an std::ostringstream (from the <sstream> header).
getchar() has no "secure counterpart" - it's not insecure to begin with and has no buffer overrun potential.
Re memset(): it's dangerous in that it accepts the programmers judgement that memory should be overwritten without any confirmation of the content/address/length, but when used properly it leaves no issue, and sometimes it's the best tool for the job even in modern C++ programming. To check security issues with this, you need to inspect the code and ensure it's aimed at a suitable buffer or object to be 0ed, and that the length is computed properly (hint: use sizeof where possible).
strcat() can be dangerous if the strings being concatenated aren't known to fit into the destination buffer. For example: char buf[16]; strcpy(buf, "one,"); strcat(buf, "two"); is all totally safe (but fragile, as further operations or changing either string might require more than 16 chars and the compiler won't warn you), whereas strcat(buf, argv[0]) is not. The best replacement tends to be a std::ostringstream, although that can require significant reworking of the code. You may get away using strncat(), or even - if you have it - asprintf("%s%s", first, second), which will allocate the required amount of memory on the heap (do remember to free() it). You could also consider std::string and use operator+ to concatenate strings.
None of these functions are "insecure" provided you understand the behaviour and limitations. itoa is not standard C and should be replaced with sprintf("%d",...) if that's a concern to you.
The others are all fine to the experienced practitioner. If you have specific cases which you think may be unsafe, you should post them.
I'd change itoa(), because it's not standard, with sprintf or, better, snprintf if your goal is code security. I'd also change strcat() with strncat() but, since you specified C++ language too, a really better idea would be to use std::string class.
As for the other two functions, I can't see how you could make the code more secure without seeing your code.

c++ what happens if you print more characters with sprintf, than the char pointer has allocated?

I assume this is a common way to use sprintf:
char pText[x];
sprintf(pText, "helloworld %d", Count );
but what exactly happens, if the char pointer has less memory allocated, than it will be print to?
i.e. what if x is smaller than the length of the second parameter of sprintf?
i am asking, since i get some strange behaviour in the code that follows the sprintf statement.
It's not possible to answer in general "exactly" what will happen. Doing this invokes what is called Undefined behavior, which basically means that anything might happen.
It's a good idea to simply avoid such cases, and use safe functions where available:
char pText[12];
snprintf(pText, sizeof pText, "helloworld %d", count);
Note how snprintf() takes an additional argument that is the buffer size, and won't write more than there is room for.
This is a common error and leads to memory after the char array being overwritten. So, for example, there could be some ints or another array in the memory after the char array and those would get overwritten with the text.
See a nice detailed description about the whole problem (buffer overflows) here. There's also a comment that some architectures provide a snprintf routine that has a fourth parameter that defines the maximum length (in your case x). If your compiler doesn't know it, you can also write it yourself to make sure you can't get such errors (or just check that you always have enough space allocated).
Note that the behaviour after such an error is undefined and can lead to very strange errors. Variables are usually aligned at memory locations divisible by 4, so you sometimes won't notice the error in most cases where you have written one or two bytes too much (i.e. forget to make place for a NUL), but get strange errors in other cases. These errors are hard to debug because other variables get changed and errors will often occur in a completely different part of the code.
This is called a buffer overrun.
sprintf will overwrite the memory that happens to follow pText address-wise. Since pText is on the stack, sprintf can overwrite local variables, function arguments and the return address, leading to all sorts of bugs. Many security vulnerabilities result from this kind of code — e.g. an attacker uses the buffer overrun to write a new return address pointing to his own code.
The behaviour in this situation is undefined. Normally, you will crash, but you might also see no ill effects, strange values appearing in unrelated variables and that kind of thing. Your code might also call into the wrong functions, format your hard-drive and kill other running programs. It is best to resolve this by allocating more memory for your buffer.
I have done this many times, you will receive memory corruption error. AFAIK, I remember i have done some thing like this:-
vector<char> vecMyObj(10);
vecMyObj.resize(10);
sprintf(&vecMyObj[0],"helloworld %d", count);
But when destructor of vector is called, my program receive memory corruption error, if size is less then 10, it will work successfully.
Can you spell Buffer Overflow ? One possible result will be stack corruption, and make your app vulnerable to Stack-based exploitation.