String copy with strcpy_s - c++

Trying to copy string using strcpy_s
char foo[10]; // a buffer able to hold 9 chars (plus the null)
char bar[] = "A string longer than 9 chars";
strcpy_s( foo, 10, bar );
Got Assertion:
Expression: (L"Buffer is too small" && 0)
Can't understand why. foo has space for 10 characters and second parameter is 10. So, what is wrong?

This is the expected behaviour
in docs you have:
numberOfElements
Size of the destination string buffer in char units for narrow and multi-byte functions, and wchar_t units for wide functions.
so second parametr is the size of your destination buffer. And function tries to copy all characters from the source.
If you want to copy as many as possible elements using *_s function then consider using:
strncpy_s(foo, sizeof(foo)/sizeof(foo[0]), bar, _TRUNCATE);

errno_t strcpy_s(
char *strDestination,
size_t numberOfElements,
const char *strSource
);
The strcpy_s function copies the contents in the address of strSource, including the terminating null character, to the location that's specified by strDestination. The destination string must be large enough to hold the source string and its terminating null character. The behavior of strcpy_s is undefined if the source and destination strings overlap.
From MSDN documentation, if the destination is not large enough, you will get error.

You are writing as much characters as the buffer could contain. As stated in the documentation:
2) Same as (1), except that it may clobber the rest of the destination
array with unspecified values and that the following errors are
detected at runtime and call the currently installed constraint
handler function:
[...]
destsz is less or equal strnlen_s(src, destsz); in other words, truncation would occur
[...]
You fall in the "equal" case, thus the error. If you known what you do, you can ignore it or enable truncation.

Related

Is it Safe to strncpy Into a string That Doesn't Have Room for the Null Terminator?

Consider the following code:
const char foo[] = "lorem ipsum"; // foo is an array of 12 characters
const auto length = strlen(foo); // length is 11
string bar(length, '\0'); // bar was constructed with string(11, '\0')
strncpy(data(bar), foo, length);
cout << data(bar) << endl;
My understanding is that strings are always allocated with a hidden null element. If this is the case then bar really allocates 12 characters, with the 12th being a hidden '\0' and this is perfectly safe... If I'm wrong on that then the cout will result in undefined behavior because there isn't a null terminator.
Can someone confirm for me? Is this legal?
There have been a lot of questions about why to use strncpy instead of just using the string(const char*, const size_t) constructor. My intent has been to make my toy code close to my actual code which contains a vsnprintf. Unfortunately even after getting excellent answers here I've found that vsnprintf doesn't behave the same as strncpy, and I've asked a follow up question here: Why is vsnprintf Not Writing the Same Number of Characters as strncpy Would?
This is safe, as long as you copy [0, size()) characters into the string . Per [basic.string]/3
In all cases, [data(), data() + size()] is a valid range, data() + size() points at an object with value charT() (a “null terminator”), and size() <= capacity() is true.
So string bar(length, '\0') gives you a string with a size() of 11, with an immutable null terminator at the end (for a total of 12 characters in actual size). As long as you do not overwrite that null terminator, or try to write past it, you're okay.
There are two different things here.
First, does strncpy add an additional \0 in this instance (11 non-\0 elements to be copied in a string of size 11). The answer is no:
Copies at most count characters of the byte string pointed to by src (including the terminating null character) to character array pointed to by dest.
If count is reached before the entire string src was copied, the resulting character array is not null-terminated.
So the call is perfectly fine.
Then data() gives you a proper \0-terminated string:
c_str() and data() perform the same function. (since C++11)
So it seems that for C++11, you are safe. Whether the string allocates an additional \0 or not doesn't seems to be indicated in the documentation, but the API is clear that what you are doing is perfectly fine.
You have allocated an 11-character std::string. You are not trying to read nor write anything past that, so that part will be safe.
So the real question is whether you have messed up the internals of the string. Since you haven't done anything that isn't allowed, how would that be possible? If it's required for the string to internally keep a 12-byte buffer with a null padding at the end in order to fulfill its contract, that will be the case no matter what operations you performed.
Yes it's safe according to the char * strncpy(char* destination, const char* source, size_t num):
Copy characters from string
Copies the first num characters of source to destination. If the end of the source C string (which is signaled by a null-character) is found before num characters have been copied, destination is padded with zeros until a total of num characters have been written to it.

Determining size of vsprintf output

I am implementing a printf(const char * format, ...) like method for a class, where I need to determine the exact size of it's output given only the supplied format and the arguments given in va_list, before calling vsprintf() to perform the actual writing.
Is there a function that can take the format and va_list to generate the exact length of the output?
As from the example in the documentation, you can determine the necessary buffer size 1st (emphasis mine):
std::vector<char> buf(1+std::vsnprintf(NULL, 0, fmt, args1)); // <<<
va_end(args1);
std::vsnprintf(buf.data(), buf.size(), fmt, args2);
4) Writes the results to a character string buffer. At most buf_size-1 characters are written. The resulting character string will be terminated with a null character, unless buf_size is zero. If buf_size is zero, nothing is written and buffer may be a null pointer, however the return value (number of bytes that would be written not including the null terminator) is still calculated and returned.
Generally all variants of the <x>sprintf() functions family can be used to calculate the necessary buffer size if the target buffer parameter is passed as NULL or nullptr.

sprintf() is adding an extra variable

Why is this happening?:
char buf[256];
char date[8];
sprintf(date, "%d%02d%02d", Time.year(), Time.month(), Time.day());
snprintf(buf, sizeof(buf), "{\"team\":\"%s\"}", team.c_str());
Serial.println(date);
output:
20180202{"team":"IND"}
it should only be: 20180202
I don't know why {"team":"IND"} is getting added to the end of it.
Very likely you declared two arrays and they are lined up in a way that allowed for the buf to overwrite the null terminator of date and thus it's "concatenating" the two.
I can't write code to reproduce this because it's undefined behavior and thus not reliable. But I can tell you how you can avoid it,
snprintf(date, sizeof(date), "%d%02d%02d", Time.year(), Time.month(), Time.day());
snprintf(buf, sizeof(buf), "{\"team\":\"%s\"}", team.c_str());
Having said that, why are you using snprintf() when this appears to be c++? And so there are more suitable solutions for this kind of problem.
This would print an incorrect value, but would not cause any unexpected behavior.
Strings in c are simply arrays with a special arrangement. If the string has n printable characters it should be stored in an array of size n + 1, so that you can add what is called a null terminator. It's a special value that indicates the end of the string.
Your second snprintf() is overwriting such null terminator of the date array and thus appearing to concatenate both strings.
You have reserved space to store exactly 8 chars:
char date[8];
To store the date properly 20180202 you need
char date[9];
because sprintf() puts the extra '\0' character to the buffer you pass for proper c-style string termination.
I'd suspect you declared your buffers like
char buffer[???];
char date[8];
since these are most likely stored on your processors stack, you need to read that backwards, thus the output placed at buffer overwrites that terminating '\0', and appears immediately after date.

Strncpy should only be used with fixed length arrays

According to this StackOverflow comment strncpy should never be used with a non-fixed length array.
strncpy should never be used unless you're working with fixed-width, not-necessarily-terminated string fields in structures/binary files. – R.. Jan 11 '12 at 16:22
I understand that it is redundant if you are dynamically allocating memory for the string but is there a reason why it would be bad to use strncpy over strcpy
strncpy will copy data up to the limit you specify--but if it reaches that limit before the end of the string, it'll leave the destination unterminated.
In other words, there are two possibilities with strncpy. One is that you get behavior precisely like strcpy would have produced anyway (except slower, since it fills the remainder of the destination buffer with NULs, which you virtually never actually want or care about). The other is that it produces a result you generally can't put to any real use.
If you want to copy a string up to a maximum length into a fixed-length buffer, you can (for example) use sprintf to do the job:
char buffer[256];
sprintf(buffer, "%255s", source);
Unlike strncpy, this always zero-terminates the result, so the result is always usable as a string.
If you don't want to use sprintf (or similar), I'd advise just writing a function that actually does what you want, something on this general order:
void copy_string(char const *dest, char const *source, size_t max_len) {
size_t i;
for (i=0; i<max_len-1 && source[i]; i++)
dest[i] = source[i];
dest[i] = '\0';
}
Since you've tagged this as C++ (in addition to C): my advice would be to generally avoid this whole mess in C++ by just using std::string.
If you really have to work with NUL-terminated sequences in C++, you might consider another possibility:
template <size_t N>
void copy_string(char const (&dest)[N], char const *source) {
size_t i;
for (i=0; i<N-1 && source[i]; i++)
dest[i] = source[i];
dest[i] = '\0';
}
This only works when the destination is an actual array (not a pointer), but for that case, it gets the compiler to deduce the size of the array, instead of requiring the user to pass it explicitly. This will generally make the code a tiny bit faster (less overhead in the function call) and much harder to screw up and pass the wrong size.
The argument against using strncpy is that it does not guarentee that your string will be null terminated.
The less error prone way to copy a string in C when using non-fixed length arrays is to use snprintf which does guarentee null termination of your string.
A good Blog Post Commenting on *n* functions.
These functions let you specify the size of the buffer but – and this is really important – they do not guarantee null-termination. If you ask these functions to write more characters than will fill the buffer then they will stop – thus avoiding the buffer overrun – but they will not null-terminate the buffer.
Which means that the use of strncpy and other such functions when not dealing with fixed arrays introduces unnessisary risk of non-null terminated strings which can be time-bombs in your code.
char * strncpy ( char * destination, const char * source, size_t num );
Limitations of strncpy():
It doesn't put a null-terminator on the destination string if it is completely filled. And, no null-character is implicitly appended at the end of destination if source is longer than num.
If num is greater than the length of source string, the destination string is padded with null characters up to num length.
Like strcpy, it is not a memory-safe operation. Because it does not check for sufficient space in destination before it copies source, it is a potential cause of buffer overruns.
Refer: Why should you use strncpy instead of strcpy?
We have 2 versions for copy string from one to another
1> strcpy
2> strncpy
These two versions is used for fixed and non-fixed length array. The strcpy don't check the upper bound for destination string when copy string, strncpy will check it. When the destination string is reached to this upper bound, the function strncpy will return error code, in the meantime the function strcpy will cause some effect in memory of the current process and terminate the process immediately. So that the strncpy is more secure than strcpy

Not sure why I am getting different lengths when using a string or a char

When I call gethostname using a char my length 25 but when I use a string my length is 64. Not really sure why. Both of them I am declaring the same size on HOST_NAME_MAX.
char hostname[HOST_NAME_MAX];
BOOL host = gethostname(hostname, sizeof hostname);
expectedComputerName = hostname;
int size2 = expectedComputerName.length();
std::string test(HOST_NAME_MAX, 0);
host = gethostname(&test[0], test.length());
int testSize = test.length();
An std::string object can contain NULs (i.e. '\0' characters). You are storing the name in the first bytes of a string object that was created with a size of HOST_NAME_MAX length.
Storing something in the beginning of the string data won't change the length of the string that remains therefore HOST_NAME_MAX.
When creating a string from a char pointer instead the std::string object created will contain up to, but excluding, the first NUL character (0x00). The reason is that a C string cannot contain NULs because the first NUL is used to mark the end of the string.
Consider what you're doing in each case. In the former code snippet, you're declaring a character array capable of holding HOST_NAME_MAX-1 characters (1 for the null terminator). You then load some string data into that buffer via the call to gethostname and then print out the length of buffer by assigning it to a std::string object using std::string::operator= that takes a const char *. One of the effects of this is that it will change an internal size variable of std::string to be strlen of the buffer, which is not necessarily the same as HOST_NAME_MAX. A call to std::string::length simply returns that variable.
In the latter case, you're using the std::string constructor that takes a size and initial character to construct test. This constructor sets the internal size variable to whatever size you passed in, which is HOST_NAME_MAX. The fact that you then copy in some data to std::strings internal buffer has no bearing on its size variable. As with the other case, a call to the length() member function simply returns the size - which is HOST_NAME_MAX - regardless of whether or not the actual length of the underlying buffer is smaller than HOST_NAME_MAX.
As #MattMcNabb mentioned in the comments, you could fix this by:
test.resize( strlen(test.c_str()) );
Why might you want to do this? Consistency with the char buffer approach might be a reason, but another reason may be performance oriented. In the latter case you're not only outright setting the length of the string to HOST_NAME_MAX, but also its capacity (omitting the SSO for brevity), which you can find starting on line 242 of libstdc++'s std::string implementation. What this means in terms of performance is that even though only, say, 25 characters are actually in your test string, the next time you append to that string (via +=,std::string::append,etc), it's more than likely to have to reallocate and grow the string, as shown here, because the internal size and internal capacity are equal. Following #MattMcNabb's suggestion, however, the string's internal size is reduced down to the length of the actual payload, while keeping the capacity the same as before, and you avoid the almost immediate re-growth and re-copy of the string, as shown here.