Hi i'm using visual studio and trying to make a program that replicate itself to a disk, when i run it does just that, but then i get the message:
"*Run-Time Check Failure #2 - Stack around the variable 'folderPath' was corrupted*."
the code is as follows:
void copyToDrive(char driveLetter) {
char folderPath[10] = { driveLetter };
strcat(folderPath, ":\\");
strcat(folderPath, FILE_NAME);
char filename[MAX_PATH];
DWORD size = GetModuleFileNameA(NULL, filename, MAX_PATH);
std::ifstream src(filename, std::ios::binary);
std::ofstream dest(folderPath, std::ios::binary);
dest << src.rdbuf();
return;
}
what is causing it? and how can i fix that?
The string "app.exe" is seven characters long. That means the total length of the string you construct will be ten characters long.
Unfortunately you seem to forget that char strings in C++ are really called null-terminated byte strings, and that the null-terminator also needs space.
Since there is no space for the null-terminator (character '\0') the last strcat call will write out of bounds of your folderPath array, leading to undefined behavior (and the error you get).
The simple solution is to add one element to the array to make space for the terminator as well:
char folderPath[11];
A more correct solution is to use std::string instead, and not have to worry about the length.
And since you are working with paths I would suggest you use std::filesystem::path (or Boost filesystem path if you don't have C++17 available).
Related
I'm working on C++ code developed by other people, and have found a section where a std::string is assigned to a char array which is not null-terminated. The code (simplified) is something like this:
char *filePath="c:\\filename.txt"; //file known to contain 20 chars per line.
int size=20;
char *buffer;
std::string bufferstr;
buffer=new char[size];
std::ifstream input(filePath, std::ios::in | std::ios::binary);
input.read(buffer,size);
bufferstr=buffer; // Assign string to non-null-terminated char array.
// Lots of other code omitted here.
input.close();
delete[] buffer;
I'm not surprised to find memory errors when checking the code with Dr. Memory, and have now changed this so that buffer is always null-terminated, but the code has had this error for about 3 years and has behaved as intended (on Windows, Linux, and Solaris) until I recently made changes in a seemingly unrelated part of the code.
My questions are:
- What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
- Why would this code have started misbehaving after I made changes elsewhere?
If the char array is non-null-terminated the result is UB. What is likely to happen is that string constructor will go beyond the allocated buffer and encounter a null byte sooner or later.
What is the expected behaviour when assigning a std::string to a non-null-terminated char array?
std::string will consider everything from the pointer received to the first address containing a zero value, to be part of the string. Usually, this means you either get a few garbage characters at the end of your string, or you get an application core dump, with an error like "unable to allocate " or "access violation reading ".
Why would this code have started misbehaving after I made changes elsewhere?
Because your changes elsewhere, also changed where zeros were, in the memory adjacent to the end of your non-zero terminated buffer (this is an educated guess).
I'm trying to open a file whose name is composed by constant and variable parts.
My actual code is
char filename[100];
char extension1[] = ".pdb";
vector<string> id;
//code to find the ids(it works)
sprintf(filename, "/home/giovanni/Scrivania/enzimi/ligan/%s", id[1].c_str());
sprintf(filename, "%s%s", filename,extension1);
The problem is that filenames becomes
.pdbe/giovanni/Scrivania/enzimi/ligan/102M
instead of
/home/giovanni/Scrivania/enzimi/ligan/102M.pdb
Simply use std::string:
string filename = "/home/giovanni/Scrivania/enzimi/ligan/" + id[1] + ".pdb";
...
std::ifstream file(filename.c_str());
Simply using this code would do (sprintf takes variable number of arguments):
sprintf(filename,"/home/giovanni/Scrivania/enzimi/ligan/%s%s", id[1].c_str(), extension1);
But, as you are using C++, Doing it in C style is not preferable. sprintf() can cuase buffer overflows and you can you safer version snprintf(). Best option would be to use std::string
C99 and POSIX.1-2001 specify that the results are undefined if a call to sprintf()/snprintf would cause copying to take place between objects that overlap (e.g., if the target string array and one of the supplied input arguments refer to the same buffer).
So line sprintf(filename, "%s%s", filename,extension1) is illegal.
You can try other options like std::string.
Watch Out For Buffer Overflow!
You need to append to the existing string; you need to know the number of characters in it, then offset the pointer you pass in to the second call to sprintf:
int len = sprintf(filename, "/home/giovanni/Scrivania/enzimi/ligan/%s", id[1].c_str());
sprintf(filename + len, "%s", extension1);
(sprintf returns the number of characters written into the buffer, but does not include the NUL terminator.)
Note that the second call to sprintf only has one "%s".
could you say me what is the mistake in my following code?
char* line="";
printf("Write the line.\n");
scanf("%s",line);
printf(line,"\n");
I'm trying to get a line as an input from the console.But everytime while using "scanf" the program crashes. I don't want to use any std, I totally want to avoid using cin or cout. I'm just trying to learn how to tak a full line as an input using scanf().
Thank you.
You need to allocate the space for the input string as sscanf() cannot do that itself:
char line[1024];
printf("Write the line.\n");
scanf("%s",line);
printf(line,"\n");
However this is dangerous as it's possible to overflow the buffer and is therefore a security concern. Use std::string instead:
std::string line;
std::cout << "Write the line." << std::endl;
std::cin >> line;
std::cout << line << std::endl;
or:
std::getline (std::cin, line);
Space not allocated for line You need to do something like
char *line = malloc();
or
Char line[SOME_VALUE];
Currently line is a poor pointer pointing at a string literal. And overwriting a string literal can result in undefined behaviour.
scanf() doesn't match lines.
%s matches a single word.
#include <stdio.h>
int main() {
char word[101];
scanf("%100s", word);
printf("word <%s>\n", word);
return 0;
}
input:
this is a test
output:
word <this>
to match the line use %100[^\n"] which means 100 char's that aren't newline.
#include <stdio.h>
int main() {
char word[101];
scanf("%100[^\n]", word);
printf("word <%s>\n", word);
return 0;
}
You are trying to change a string literal, which in C results in Undefined behavior, and in C++ is trying to write into a const memory.
To overcome it, you might want to allocate a char[] and assign it to line - or if it is C++ - use std::string and avoid a lot of pain.
You should allocate enough memory for line:
char line[100];
for example.
The %s conversion specifier in a scanf call expects its corresponding argument to point to a writable buffer of type char [N] where N is large enough to hold the input.
You've initialized line to point to the string literal "". There are two problems with this. First is that attempting to modify the contents of a string literal results in undefined behavior. The language definition doesn't specify how string literals are stored; it only specifies their lifetime and visibility, and some platforms stick them in a read-only memory segment while others put them in a writable data segment. Therefore, attempting to modify the contents of a string literal on one platform may crash outright due to an access violation, while the same thing on another platform may work fine. The language definition doesn't mandate what should happen when you try to modify a string literal; in fact, it explicitly leaves that behavior undefined, so that the compiler is free to handle the situation any way it wants to. In general, it's best to always assume that string literals are unwritable.
The other problem is that the array containing the string literal is only sized to hold 1 character, the 0 terminator. Remember that C-style strings are stored as simple arrays of char, and arrays don't automatically grow when you add more characters.
You will need to either declared line as an array of char or allocate the memory dynamically:
char line[MAX_INPUT_LEN];
or
char *line = malloc(INITIAL_INPUT_LEN);
The virtue of allocating the memory dynamically is that you can resize the buffer as necessary.
For safety's sake, you should specify the maximum number of characters to read; if your buffer is sized to hold 21 characters, then write your scanf call as
scanf("%20s", line);
If there are more characters in the input stream than what line can hold, scanf will write those extra characters to the memory following line, potentially clobbering something important. Buffer overflows are a common malware exploit and should be avoided.
Also, %s won't get you the full line; it'll read up to the next whitespace character, even with the field width specifier. You'll either need to use a different conversion specifier like %[^\n] or use fgets() instead.
The pointer line which is supposed to point to the start of the character array that will hold the string read is actually pointing to a string literal (empty string) whose contents are not modifiable. This leads to an undefined behaviour manifested as a crash in your case.
To fix this change the definition to:
char line[MAX]; // set suitable value for MAX
and read atmost MAX-1 number of characters into line.
Change:
char* line="";
to
char line[max_length_of_line_you_expect];
scanf is trying to write more characters than the reserved by line. Try reserving more characters than the line you expect, as been pointed out by the answers above.
I'm having a bit of a problem with this piece of code:
string StringServices::ToStringf(float value)
{
char buffer[10];
sprintf (buffer, "%f", value);
return (string) buffer; // signal SIGABRT
}
Its been working previously and continues to work for other calls, but I currently get a SIGABRT on the return, when the function is being passed -211.0
The buffer loads up fine, and I'm really not sure why this isn't working. Can someone who understands std::string and c strings a lot better then me help me out here?
You probably overflowed your buffer because you're not using snprintf. You have this tagged C++ so do it that way:
std::string buffer = boost::lexical_cast<std::string>(value);
Or without boost use a string stream:
std::ostringstream os;
os << value;
// os.str() has the string representation now.
The main problem with C and its string functions is that you have to do too much work manually. You also have to make too many decisions when you write in C. One of the trivial issues is buffer overflow. Consider this code:
char buf[5]; // 5 chars, ok
sprintf(buf, "qwert"); // 5 letters, ok
You're going to have problems with this code, since when talking about strings, 5 chars means 4 letters + '\0'. So, you may try:
printf("'%s'\n", buf); // you'll probably get 'qwertIOUYOIY*&T^*&TYDGKUYTU&*#*#T^&#$T67...'
What you do with your code is a trivial buffer overflow :-)
sprintf() just has no way to check the size of buf, so a piece of memory that goes right after buf can get corrupted.
I have a function designed to get a file's contents:
bool getFileContents(std::string loc, std::string &code) {
std::ifstream file(loc.c_str());
if(!file.is_open())
return err("Source file could not be read");
int length;
file.seekg(0, std::ios::end);
length = file.tellg();
file.seekg(0, std::ios::beg);
char *buffer = new char[length];
file.read(buffer, length);
code = buffer;
delete[] buffer;
file.close();
return true;
}
When I run this function, the file's length is always retrieved accurately. However, if I call the function once with a file, call it again with a nonexistent file, then call it one more time with the original file, the character string 'buffer' is larger than the int 'length'.
Well, that may not be accurate, rather - when the string 'buffer' is copied to the string 'code', 'code' is longer than 'length'. 'code' is, in each instance, instantiated immediately before the call to 'getFileContents', so it's not a matter of a previous value.
This also seems to occur if I retrieve the contents of a file, subsequently add or remove some text from the file, and retrieve the same file's contents again.
I have little experience with character strings, and figure that I'm not using them correctly, but the code I'm using came from an example, and I can't for the life of me find anything wrong with it.
Thanks for any help,
Wyatt
Well, the problem is that code = buffer relies on a NUL (\0) character to know where the buffer ends. You may be getting the NUL character by chance sometimes (esp. when the program has just started), but not always. Hence the intermittent behaviour.
Try replacing code = buffer with code = std::string(buffer, length).
Apart of the \0 problem described by aix, you do double allocation, which is not necessary here and unsafe (it might be an exception before delete, and you'll have a memory leak). Instead, you can allocate the buffer inside the string, as follows:
code.resize(length);
file.read(&code[0], length);
And don't forget to check the return value of read. It is not guaranteed that all length bytes will be read in one step.