Heap corruption after second use of strcat - c++

This is driving me nuts because I'm not seeing what bonehead mistake I'm making here.
In the following snippet (note this is just a test snippet is from a larger method), I'm basically just attempting to copy a string that's retrieved from a SQL method, and then if the user specifies in the method an additional number of columns, append a delimiter (in this case a semi-colon) and the additional string:
//...
char** pLocalArray;
char buff[512];
//... pLocalArray is allocated
// The semicolon is replaced by a variable passed into the function, but just putting this for simplicity
char delimeterStr[2] { ';', '\0' };
for (int uCol = 0; uCol < numCols; uCol++)
{
if (uCol >= 1)
{
const char* test2 = "1704EB18-FE46-4AE4-A90F-06E42C3EE07A"; // Just a test GUID
memcpy(buff, test2, 37); // Just testing some logic, copy the string into the buffer
strcat(pLocalArray[uRow], delimeterStr); // This works just fine if I stop here
// strcat(pLocalArray[uRow], buff); // ***** If I uncomment out this line, it throws a heap exception
std::cout << "Check 3 -- Output is: " << pLocalArray[uRow] << endl; // Output: MyFirstString|MySecondString|MyThirdString;1704EB18-FE46-4AE4-A90F-06E42C3EE07A
std::memset(buff, '\0', sizeof(buff));
std::cout << "Check 4 -- Output is: " << pLocalArray[uRow] << endl; //Sanity check - MyFirstString|MySecondString|MyThirdString;1704EB18-FE46-4AE4-A90F-06E42C3EE07A
}
else
{
const char* test = "MyFirstString|MySecondString|MyThirdString";
memcpy(buff, test, 43);
pLocalArray[uRow] = _strdup(buff);
std::cout << "Check -- Output is: " << pLocalArray[uRow] << endl; // Output: MyFirstString|MySecondString|MyThirdString
std::memset(buff, '\0', sizeof(buff));
std::cout << "Check 2 -- Output is: " << pLocalArray[uRow] << endl; //Sanity check - Output: MyFirstString|MySecondString|MyThirdString
}
}
//...
However, as you can see from the comments, Its throwing an exception when I use the second strcat call. I'm not understanding why doing the strcat on the delimiter is working just fine, but appending the delimiter and then immediately appending the GUID string does not work. Can someone point out to me what I'm doing incorrectly or not taking into account?

You may be misunderstanding how the strdup function works. In the following line:
pLocalArray[uRow] = _strdup(buff);
which is called to initially allocate memory for pLocalArray[uRow], the amount of space allocated will be the actual length of the buff string, interpreted as a nul-terminated character array; this will be the length of the "MyFirstString|MySecondString|MyThirdString" literal, rather than the specified size of the buff array.
Then, when you later try to append a string to that, you are overflowing the allocated space (your first strcat only seems to work, but it is nevertheless undefined behaviour).
To allow space for up to 511 characters (plus the nul-terminator), you will need code like the following:
pLocalArray[uRow] = malloc(sizeof(buff)); // Allocate full size of "buff"
strcpy(pLocalArray[uRow], buff); // then copy the strung data

Related

why passing string to a function which accepts LPSTR does noy work?

Following code gives empty string and length = 0, but while debugging I can see the childDisplayName has correct name.
CHAR fileSystemName[MAX_PATH + 1] = { 0 };
DWORD serialNumber = 0; DWORD maxComponentLen = 0;
string childDisplayName = "";
DWORD fileSystemFlags = 0;
if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
(LPSTR)&childDisplayName, MAX_PATH+1,
&serialNumber, &maxComponentLen,
&fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
{
cout << childDisplayName << "length: "<<childDisplayName.length()<<endl;
}
following code works fine. I am not getting why LPSTR works when I pass char array and does not work when I pass a string.
CHAR fileSystemName[MAX_PATH + 1] = { 0 };
DWORD serialNumber = 0; DWORD maxComponentLen = 0;
CHAR childDisplayName[MAX_PATH + 1] = { 0 };
DWORD fileSystemFlags = 0;
if (GetVolumeInformationA("C:\\", // L"\\MyServer\MyShare\"
childDisplayName, MAX_PATH+1,
&serialNumber, &maxComponentLen,
&fileSystemFlags, fileSystemName, sizeof(fileSystemName)) == true)
{
cout << childDisplayName << "length: "<<strlen(childDisplayName)<<endl;
}
string childDisplayName = ""; creates an empty empty string (zero size and unspecified capacity). Using that as a data-buffer to write into is not likely to go well.
You can do this: string childDisplayName(MAX_PATH + 1, ' '); to create a string with the proper space allocated.
Secondly, as #churill wrote, the address of a string is not the address of the characters in it. Instead use childDisplayName.data() to get a char* to the internal storage of the string that you can write in - but make sure not to write outside the range [data(); data() + size()).
EDIT: A bit on how std::string and .data() works.
I made a small example program:
#include<iostream>
#include<string>
void print(const std::string& s)
{
std::cout << "String size: " << s.size() << '\n';
std::cout << "String contents: >>" << s << "<<\n";
std::cout << "String as c-string: >>" << s.c_str() << "<<\n";
std::cout << '\n';
}
int main() {
std::string bla = "";
auto bladata = bla.data();
for (int i = 0;i < 5;++i) {
bladata[i] = '!';
}
print(bla);
std::string bla2(10, '\0');
auto bla2data = bla2.data();
for (int i = 0;i < 5;++i) {
bla2data[i] = '!';
}
print(bla2);
}
When run this outputs:
String size: 0
String contents: >><<
String as c-string: >>!!!!!╠╠╠╠╠╠╠╠╠╠╠<<
String size: 10
String contents: >>!!!!! <<
String as c-string: >>!!!!!<<
What is going on here? First thing to notice is that an empty std::string is created with zero size and unspecified capacity - looking in my debugger, I know that on my system that unspecified capacity is 15, so as long as I don't go beyond that nothing should crash. But this is obviously not something you should do in real code (writing here is strictly undefined behavior).
This means that the bla string is size 0, and contains a 15 character char buffer, where I set the first 5 characters to '!'. So when I try to print its size() or print it as a std::string it is identical to any regular empty string. However, if I use .c_str() to print the internal buffer directly, then it prints as any old char* and just prints whatever is in memory until it encounters a null-character.
On the other hand, bla2 is initialized to contain 10 null-characters. That means that its size is 10, and its capacity is at least 10 (in my case it happens to also be 15). This means that after the loop it still reports as size 10, regardless of how many '!'s I put into the buffer, and when I print it as a std::string it prints all the 10 characters it contains; both the 5 '!'s and the 5 '\0's. However, when I print it as a char* it prints the 5 '!'s and then stop as soon as it encounters a null-character.
In first code snippet, I cannot get the correct name of childDisplayName.
Although it seems to have several characters, but an exception is triggered when I want to output it.
So you passed a wrong address to the GetVolumeInformationA.Because the address of a string is not the address of the characters
You can test like the following code:
string s("test");
CHAR cs[] = "test";
cout << (void*)&s << endl;
cout << (void*)&s[0] << endl;
cout << (void*)&cs << endl;
cout << (void*)&cs[0] << endl;
Output:
As #churill says, std::string only manages a dynamic array of characters.So you can not pass the address of string to the function.
And according to MSDN:
If you modify the contents of the string returned by the const overload of data, the behavior is undefined. You also get undefined behavior if the terminal null character is changed to any other value. The returned pointer may be invalidated if a non-const reference to the string is passed to a standard library function. It can also be invalidated by a call to a non-const member function.
So even if you really succeed in passing childDisplayName.data() into the function. This is also an undefined behavior.I recommend that you pass in the parameter types required by the function correctly, instead of trying to pass other undefined or untyped behaviors, which will cause you a lot of confusion.

When creating a char array, its length is different from required

I need to create a newStr array with length of str array. But after its created the strlen(newStr) is totally different. For example if a strlen(str) is 5, then strlen(newStr) would be 22. What am I doing wrong?
#include <iostream>
using namespace std;
int main()
{
char *str = "Hello";
int strLength = strlen(str);
std::cout << "str = " << str << "\t" << "strLength = " << strLength << std::endl;
char *newStr = new char[strLength];
std::cout << "newStrLength = " << strlen(newStr) << std::endl;
system("pause");
return 0;
}
In the console will be
str = Hello strLength = 5
newStrLength = 22
You are mixing up two different concepts:
new[] allocates uninitialized memory block to your program,
strlen(...) counts characters in a C string before null terminator '\0' is reached.
The size of the allocated block cannot be measured with strlen. In fact, it cannot be measured at all - your program must know how much memory it has requested, and make sure that it does not go past the limit.
Once you allocated new char[n], you can safely copy a C string of length up to n-1 into that block. C++ guarantees that enough memory would be there for you to complete the operation successfully:
char *newStr = new char[strLength+1]; // Note +1 for null terminator
strcpy(newStr, str);
std::cout << "newStrLength = " << strlen(newStr) << std::endl;
delete[] newStr;
The way strlen works is that it examines the contents of the string passed to it, and counts how many characters there are until the first terminating character. The terminating character for a string is '\0' (or 0).
What you've done is asked for the length of a string that you've not assigned any value to; leading to strlen examining random memory; looking for the first 0. In this case, it found it 22 bytes further down; but it could be anything. It could even crash because you start looking into memory you don't have read access to.
The best way to resolve this is to use std::string and then you can call length and other helper functions without having to worry about the underlying pointers too much; which will also resolve your memory leak.

Read into std::string using scanf

As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string

weird output when printing data of custom string (c++ newbie)

my main concern is if i am doing this safely, efficiently, and for the most part doing it right.
i need a bit of help writing my implementation of a string class. perhaps someone could help me with what i would like to know?
i am attempting to write my own string class for extended functionality and for learning purposes. i will not use this as a substitute for std::string because that could be potentially dangerous. :-P
when i use std::cout to print out the contents of my string, i get some unexpected output, and i think i know why, but i am not really sure. i narrowed it down to my assign function because any other way i store characters in the string works quite fine. here is my assign function:
void String::assign(const String &s)
{
unsigned bytes = s.length() + 1;
// if there is enough unused space for this assignment
if (res_ >= bytes)
{
strncpy(data_, s.c_str(), s.length()); // use that space
res_ -= bytes;
}
else
{
// allocate enough space for this assignment
data_ = new char[bytes];
strcpy(data_, s.c_str()); // copy over
}
len_ = s.length(); // optimize the length
}
i have a constructor that reserves a fixed amount of bytes for the char ptr to allocate and hold. it is declared like so:
explicit String(unsigned /*rbytes*/);
the res_ variable simply records the passed in amount of bytes and stores it. this is the constructor's code within string.cpp:
String::String(unsigned rbytes)
{
data_ = new char[rbytes];
len_ = 0;
res_ = rbytes;
}
i thought using this method would be a bit more efficient rather than allocating new space for the string. so i can just use whatever spaced i reserved initially when i declared a new string. here is how i am testing to see if it works:
#include <iostream>
#include "./string.hpp"
int main(int argc, char **argv)
{
winks::String s2(winks::String::to_string("hello"));
winks::String s(10);
std::cout << s2.c_str() << "\n" << std::endl;
std::cout << s.unused() << std::endl;
std::cout << s.c_str() << std::endl;
std::cout << s.length() << std::endl;
s.assign(winks::String::to_string("hello")); // Assign s to "hello".
std::cout << s.unused() << std::endl;
std::cout << s.c_str() << std::endl;
std::cout << s.length() << std::endl;
std::cout.flush();
std::cin.ignore();
return 0;
}
if you are concerned about winks::String::to_string, i am simply converting a char ptr to my string object like so:
String String::to_string(const char *c_s)
{
String temp = c_s;
return temp;
}
however, the constructor i use in this method is private, so i am forcing to_string upon myself. i have had no problems with this so far. the reason why i made this is to avoid rewriting methods for different parameters ie: char * and String
the code for the private constructor:
String::String(const char *c_s)
{
unsigned t_len = strlen(c_s);
data_ = new char[t_len + 1];
len_ = t_len;
res_ = 0;
strcpy(data_, c_s);
}
all help is greatly appreciated. if i have no supplied an efficient amount of information please notify me with what you want to know and i will gladly edit my post.
edit: the reason why i am not posting the full string.hpp and string.cpp is because it is rather large and i am not sure if you guys would like that.
You have to make a decision whether you will always store your strings internally terminated with a 0. If you don't store your strings with a terminating zero byte, your c_str function has to add one. Otherwise, it's not returning a C-string.
Your assign function doesn't 0 terminate. So either it's broken, or you didn't intend to 0 terminate. If the former, fix it. If the latter, check your c_str function to make sure it puts a 0 on the end.

how to print char array in c++

how can i print a char array such i initialize and then concatenate to another char array? Please see code below
int main () {
char dest[1020];
char source[7]="baby";
cout <<"source: " <<source <<endl;
cout <<"return value: "<<strcat(dest, source) <<endl;
cout << "pointer pass: "<<dest <<endl;
return 0;
}
this is the output
source: baby
return value: v����baby
pointer pass: v����baby
basically i would like to see the output print
source: baby
return value: baby
pointer pass: baby
You haven't initialized dest
char dest[1020] = ""; //should fix it
You were just lucky that it so happened that the 6th (random) value in dest was 0. If it was the 1000th character, your return value would be much longer. If it were greater than 1024 then you'd get undefined behavior.
Strings as char arrays must be delimited with 0. Otherwise there's no telling where they end. You could alternatively say that the string ends at its zeroth character by explicitly setting it to 0;
char dest[1020];
dest[0] = 0;
Or you could initialize your whole array with 0's
char dest[1024] = {};
And since your question is tagged C++ I cannot but note that in C++ we use std::strings which save you from a lot of headache. Operator + can be used to concatenate two std::strings
Don't use char[]. If you write:
std::string dest;
std::string source( "baby" )
// ...
dest += source;
, you'll have no problems. (In fact, your problem is due to the fact
that strcat requires a '\0' terminated string as its first argument,
and you're giving it random data. Which is undefined behavior.)
your dest array isn't initialized. so strcat tries to append source to the end of dest wich is determined by a trailing '\0' character, but it's undefined where an uninitialized array might end... (if it does at all...)
so you end up printing more or less random characters until accidentially a '\0' character occurs...
Try this
#include <iostream>
using namespace std;
int main()
{
char dest[1020];
memset (dest, 0, sizeof(dest));
char source[7] = "baby";
cout << "Source: " << source << endl;
cout << "return value: " << strcat_s(dest, source) << endl;
cout << "pointer pass: " << dest << endl;
getchar();
return 0;
}
Did using VS 2010 Express.
clear memory using memset as soon as you declare dest, it's more secure. Also if you are using VC++, use strcat_s() instead of strcat().