String copy is saying buffer is too small, strcpy_s source issue - c++

I'm so confused, I'm sorry if this obvious, but:
int main()
{
char stringDest[20];
char stringSource[20];
strcpy_s(stringDest, stringSource);
return 0;
}
Throws the exception "Buffer is too small". Whereas:
char stringSource[20];
int main()
{
char stringDest[20];
strcpy_s(stringDest, stringSource);
return 0;
}
Works fine.
Furthermore, I thought the point of the safe strcpy_s(dest, size, source) was that you specify the number of bytes that are copied, however when I do this:
int main()
{
char stringDest[20];
char stringSource[20];
strcpy_s(stringDest, 1, stringSource);
return 0;
}
I get a "Buffer is too small exception".
I am so confused. Why does declaring the variable outside main() make a difference? And why is it wrong to specify 1 byte to copy?

Gives me an unhandled RangeChecks exception, whereas:
C's arrays are zero indexed, that means for char stringSource[20];, the elements are from 0 to 19, when you do stringSource[20] = '\0';, the access is out of array bounds, which results undefined behavior.
Throws the exception "Buffer is too small". Whereas:
That's because stringSource is of automatic storage and is not initialized to a valid string, use of it cause undefined behavior.
While the second case, when you put char stringSource[20]; out of the function, the array is static storage, it is by default initialized with zero value, it is effectively the same as char stringSource[20] = "";, that's why this case the strcpy succeeded.

You are invoking undefined behaviour here, because you are not initializing the source string.
In most cases, there will be garbage, and the first 0 byte is most likely after the length of 20, which is why the compiler/runtime complaines.
char stringSource[20] = {0};
or alternatively
char stringSource[20] = "";
Whatever suits best.
Depending on your environment, in the debug version, the compiler can intentionally fill the variables with values like 0xff so that the first 0-byte will always be beyond the limit.
If you put char stringDest[20] outside the function it will be a global variable, which are always iniatlized to 0 by the CRT startup.
In your last example, you should take a look at the description of strcpy_s.
This variant will cause an error if
destsz is less or equal strnlen_s(src, destsz); in other words, truncation would occur
strcpy_s(stringDest, 1, stringSource); means that 1 is smaller than your uninitialized stringlen, so it gives an error.
Note, that this parameter does not tell the function how many characters it should copy, but how big the destination is supposed to be. You don't tell it to copy only 1 character, you tell it, that it can copy at most 1 character ( which would be needed for the 0 byte anyway).

Related

getting buffer overflow error using strcat

New to C++, I was goofing around trying to get my head around complex systems like pointers and solving questions. I made this simple program which will concatenate char strings. But it always throws the same error: L'buffer is too small &&0.
Here is my code -
const char* str = "larry";
const char* yo{"is one of the stooges" };
size_t buffer{ std::strlen(str) + std::strlen(yo) + 1 };
std::cout << buffer;
char* buff = new char[buffer];
strcpy_s(buff, strlen(str), str);
strcat(buff, yo);
std::cout << *buff << std::endl;
delete[] buff;
and here is my program output as requested:
27 // the size of buffer
the program then crashes.
Please point out whats wrong.
Thanks
According to the C Standard (K.3.7.1.3 The strcpy_s function)
2 Neither s1 nor s2 shall be a null pointer. s1max shall not be
greater than RSIZE_MAX. s1max shall not equal zero. s1max shall be
greater than strnlen_s(s2, s1max). Copying shall not take place
between objects that overlap.
That is you have to write
strcpy_s(buff, strlen(str) + 1, str);
Otherwise the terminating zero of the string pointed to by str will not be copied. In this case the next call
strcat(buff, yo);
invokes undefined behaviour.
The second parameter to strcpy_s is the size of the destination array, including the 0 byte. However, you pass in the size of the source string, excluding the 0 byte. strcpy_s attempts to copy the 0 byte, which it can't, as the destination array is supposedly (as indicated by the parameter) too small. Pass buffer (not a good name, btw) as the 2nd parameter to strcpy_s to indicate the destination size correctly.

how does cin.get() function works?

I would like to know how does cin.get() function works?
For example, I have char array of 256 characters. If input contains less than 256 characters, what's 'empty' array elements containing then? Is every unused element is '\0' or what?
Thanks in advance,
Janis
For example, You have a simple code and you entered a string "ex: Hello world!" as follow:
char str[256]; // Uninitialized variable
std::cin.get(str, 256);
The result:
The same code but with initialized variable:
char str[256] = {}; // Initialized variable
std::cin.get(str, 256);
The result:
The part of the array that is not filled is untouched. If the array is fresh, typically you see zeros, as the operating system zeros out newly allocated pages. Consider this an artifact, expect anything.
get() is an overloaded function of the basic_istream class. Assuming you are calling it like:
cin.get(array, size)
Then it will fill up to size - 1 characters in the array. The rest are leaved unmodified, so you cannot know the value they have.
If input contains less than 256 characters, what's 'empty' array elements containing then? Is every unused element is '\0' or what?
It depends.
Global and static variables are default initialized. Local variables are uninitialized - unless you explicitly initialize them.
char buf1[256]; // global variable, all zeroes
int main() {
char buf2[256]; // uninitialized memory
}
Reading from buf1 has well defined behavior but reading from buf2 has not, so if you std::cin.get(buf2, <some_size>); and read from the memory beyond the \0 that std::cin.get() puts in your array, your program will have undefined behavior.
To amend that, you can default initialize your local variables too:
int main() {
char buf2[256]{}; // default initialized memory
}

Error when instantiating a class which has an attribute with generic types [duplicate]

Given:
char test[] = "bla-bla-bla";
Which of the two is more correct?
char *test1 = malloc(strlen(test));
strcpy(test1, test);
or
char *test1 = malloc(sizeof(test));
strcpy(test1, test);
This will work on all null-terminated strings, including pointers to char arrays:
char test[] = "bla-bla-bla";
char *test1 = malloc(strlen(test) + 1);
strcpy(test1, test);
You won't get the correct size of the array pointed to by char* or const char* with sizeof. This solution is therefore more versatile.
Neither:
#include <string.h>
char *mine = strdup(test);
You should use strlen, because sizeof will fail silently if you change test to be a run-time defined string. This means that strlen is a far safer idea than sizeof as it will keep working.
char test[]="bla-bla-bla";
char *test1 = malloc(strlen(test) + 1); // +1 for the extra NULL character
strcpy(test1, test);
I think sizeof is the correct one. Reason behind that is strlen(str) will give you length of the string( excluding the terminating null). And if you are using strcpy, it actually copy the whole string including the terminating null, so you will allocate one byte less if you use strlen in malloc. But sizeof gives the size of the string pointed by test, including the terminating null, so you will get correct size malloc chunk to copy the string including the terminating null.
1) definitely causes UB
2) may cause UB (if malloc fails)
I'd go with 2) as there is a better chance of the construct working as intended; or even better I'd write a version that works as intended (without UB) in all situations.
Edit
Undefined Behaviour in 1)
test1 will have space for the characters in test, but not for the terminating '\0'. The call to strcpy() will try to write a '\0' to memory that does not belong to test1, hence UB.
Undefined Behaviour in 2)
If the call to malloc() fails to reserve the requested memory, test1 will be assigned NULL. Passing NULL to strcpy() invokes UB.
The return value of calls to malloc() (and calloc() and friends) should always be tested to ensure the operation worked as expected.
(1) with strlen but not adding 1 is definitely incorrect. If you add 1, it would have the added benefit that it also works for pointers, not just arrays.
On the other hand, (2) is preferred as long as your string is actually an array, as it results in a compile-time constant, rather than a call to strlen (and thus faster and smaller code). Actually a modern compiler like gcc can probably optimize the strlen out if it knows the string is constant, but it may be hard for the compiler to determine this, so I'd always use sizeof when possible.
If it is a critical path, sizeof has advantage over strlen as it has an O(1) complexity which can save CPU cycles.

C++ Swap string

I am trying to create a non-recursive method to swap a c-style string. It throws an exception in the Swap method. Could not figure out the problem.
void Swap(char *a, char* b)
{
char temp;
temp = *a;
*a = *b;
*b = temp;
}
void Reverse_String(char * str, int length)
{
for(int i=0 ; i <= length/2; i++) //do till the middle
{
Swap(str+i, str+length - i);
}
}
EDIT: I know there are fancier ways to do this. But since I'm learning, would like to know the problem with the code.
It throws an exception in the Swap method. Could not figure out the problem.
No it doesn't. Creating a temporary character and assigning characters can not possibly throw an exception. You might have an access violation, though, if your pointers don't point to blocks of memory you own.
The Reverse_String() function looks OK, assuming str points to at least length bytes of writable memory. There's not enough context in your question to extrapolate past that. I suspect you are passing invalid parameters. You'll need to show how you call Reverse_String() for us to determine if the call is valid or not.
If you are writing something like this:
char * str = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
Then you will definitely get an access violation, because str points to read-only memory. Try the following syntax instead:
char str[] = "Foo";
Reverse_String(str, 3);
printf("Reversed: '%s'.\n", str);
This will actually make a copy of the "Foo" string into a local buffer you can overwrite.
This answer refers to the comment by #user963018 made under #André Caron's answer (it's too long to be a comment).
char *str = "Foo";
The above declares a pointer to the first element of an array of char. The array is 4 characters long, 3 for F, o & o and 1 for a terminating NULL character. The array itself is stored in memory marked as read-only; which is why you were getting the access violation. In fact, in C++, your declaration is deprecated (it is allowed for backward compatibility to C) and your compiler should be warning you as such. If it isn't, try turning up the warning level. You should be using the following declaration:
const char *str = "Foo";
Now, the declaration indicates that str should not be used to modify whatever it is pointing to, and the compiler will complain if you attempt to do so.
char str[] = "Foo";
This declaration states that str is a array of 4 characters (including the NULL character). The difference here is that str is of type char[N] (where N == 4), not char *. However, str can decay to a pointer type if the context demands it, so you can pass it to the Swap function which expects a char *. Also, the memory containing Foo is no longer marked read-only, so you can modify it.
std::string str( "Foo" );
This declares an object of type std::string that contains the string "Foo". The memory that contains the string is dynamically allocated by the string object as required (some implementations may contain a small private buffer for small string optimization, but forget that for now). If you have string whose size may vary, or whose size you do not know at compile time, it is best to use std::string.

Memcpy, string and terminator

I have to write a function that fills a char* buffer for an assigned length with the content of a string. If the string is too long, I just have to cut it. The buffer is not allocated by me but by the user of my function. I tried something like this:
int writebuff(char* buffer, int length){
string text="123456789012345";
memcpy(buffer, text.c_str(),length);
//buffer[length]='\0';
return 1;
}
int main(){
char* buffer = new char[10];
writebuff(buffer,10);
cout << "After: "<<buffer<<endl;
}
my question is about the terminator: should it be there or not? This function is used in a much wider code and sometimes it seems I get problems with strange characters when the string needs to be cut.
Any hints on the correct procedure to follow?
A C-style string must be terminated with a zero character '\0'.
In addition you have another problem with your code - it may try to copy from beyond the end of your source string. This is classic undefined behavior. It may look like it works, until the one time that the string is allocated at the end of a heap memory block and the copy goes off into a protected area of memory and fails spectacularly. You should copy only until the minimum of the length of the buffer or the length of the string.
P.S. For completeness here's a good version of your function. Thanks to Naveen for pointing out the off-by-one error in your terminating null. I've taken the liberty of using your return value to indicate the length of the returned string, or the number of characters required if the length passed in was <= 0.
int writebuff(char* buffer, int length)
{
string text="123456789012345";
if (length <= 0)
return text.size();
if (text.size() < length)
{
memcpy(buffer, text.c_str(), text.size()+1);
return text.size();
}
memcpy(buffer, text.c_str(), length-1);
buffer[length-1]='\0';
return length-1;
}
If you want to treat the buffer as a string you should NULL terminate it. For this you need to copy length-1 characters using memcpy and set the length-1 character as \0.
it seems you are using C++ - given that, the simplest approach is (assuming that NUL termination is required by the interface spec)
int writebuff(char* buffer, int length)
{
string text = "123456789012345";
std::fill_n(buffer, length, 0); // reset the entire buffer
// use the built-in copy method from std::string, it will decide what's best.
text.copy(buffer, length);
// only over-write the last character if source is greater than length
if (length < text.size())
buffer[length-1] = 0;
return 1; // eh?
}
char * Buffers must be null terminated unless you are explicitly passing out the length with it everywhere and saying so that the buffer is not null terminated.
Whether or not you should terminate the string with a \0 depends on the specification of your writebuff function. If what you have in buffer should be a valid C-style string after calling your function, you should terminate it with a \0.
Note, though, that c_str() will terminate with a \0 for you, so you could use text.size() + 1 as the size of the source string. Also note that if length is larger than the size of the string, you will copy further than what text provides with your current code (you can use min(length - 2, text.size() + 1/*trailing \0*/) to prevent that, and set buffer[length - 1] = 0 to cap it off).
The buffer allocated in main is leaked, btw
my question is about the terminator: should it be there or not?
Yes. It should be there. Otherwise how would you later know where the string ends? And how would cout would know? It would keep printing garbage till it encounters a garbage whose value happens to be \0. Your program might even crash.
As a sidenote, your program is leaking memory. It doesn't free the memory it allocates. But since you're exiting from the main(), it doesn't matter much; after all once the program ends, all the memory would go back to the OS, whether you deallocate it or not. But its good practice in general, if you don't forget deallocating memory (or any other resource ) yourself.
I agree with Necrolis that strncpy is the way to go, but it will not get the null terminator if the string is too long. You had the right idea in putting an explicit terminator, but as written your code puts it one past the end. (This is in C, since you seemed to be doing more C than C++?)
int writebuff(char* buffer, int length){
char* text="123456789012345";
strncpy(buffer, text, length);
buffer[length-1]='\0';
return 1;
}
It should most defiantly be there*, this prevents strings that are too long for the buffer from filling it completely and causing an overflow later on when its accessed. though imo, strncpy should be used instead of memcpy, but you'll still have to null terminate it. (also your example leaks memory).
*if you're ever in doubt, go the safest route!
First, I don't know whether writerbuff should terminate the string or not. That is a design question, to be answered by the person who decided that writebuff should exist at all.
Second, taking your specific example as a whole, there are two problems. One is that you pass an unterminated string to operator<<(ostream, char*). Second is the commented-out line writes beyond the end of the indicated buffer. Both of these invoke undefined behavior.
(Third is a design flaw -- can you know that length is always less than the length of text?)
Try this:
int writebuff(char* buffer, int length){
string text="123456789012345";
memcpy(buffer, text.c_str(),length);
buffer[length-1]='\0';
return 1;
}
int main(){
char* buffer = new char[10];
writebuff(buffer,10);
cout << "After: "<<buffer<<endl;
}
In main(), you should delete the buffer you allocated with new., or allocate it statically (char buf[10]). Yes, it's only 10 bytes, and yes, it's a memory "pool," not a leak, since it's a one-time allocations, and yes, you need that memory around for the entire running time of the program. But it's still a good habit to be into.
In C/C++ the general contract with character buffers is that they be null-terminiated, so I would include it unless I had been explicitly told not to do it. And if I did, I would comment it, and maybe even use a typedef or name on the char * parameter indicating that the result is a string that is not null terminated.