c++, reading files, segmentation fault - c++

I was working on this function read. The main I used has no problem in file I/O, it connects fine, closes, the files are okay too. However, I am getting a segmentation fault by the end of the reading. I have tried printing out for testing, and the error is reading the last line. It finishes reading the last line for string a, and then x, and then in.good() becomes false too. I have tried resetting in.clear(), also, setting the string a=""; if in.good becomes false. Nothing is working.
read(istream& in){
string a;
int x;
in>>a;
while( in.good() ){
in>>x;
char *ch;
strcpy( ch, a.c_str() );
Word cwd(ch);
anObject.add(cwd,x);
}
}

You see a segfault because you're not allocating space for ch, and then you're attempting to copy a string over it. ch is an uninitialized memory address that doesn't belong to you.
You'll need to allocate space for the string:
char *ch = new[(MAX_SIZE + 1) * sizeof(char)];
But why is it that you need a char * here? Note that you can always pass around a and use a.c_str() if you must have a C string. I'm not sure what Word is, or if it needs it's own copy of a string, but can you use: Word cwd(a.c_str())?

It seems you don't allocate memory storage for char *ch. The moment you define this variable, it is a random value on the stack. Writing a random memory will corrupt the memory and cause seg fault when cleanup the memory(both manually or automatically at function return).

Related

Program creating file path using strdup and strcat crashes when fed more than 39 characters

I am trying to concatenate two char arrays using the function strcat(). However the program crashes.
#include <cstdio>
#include <cstring>
int main() {
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *file_bk_path = strcat(strdup(file_path), ".bk");
printf("%s\n", file_bk_path);
return 0;
}
The strangest thing to me is that the program indeed produces an output before crashing:
D:/MyFolder/YetAnotherFolder/test.txt.bk
What is the reason for this problem and how it can be fixed?
Error state is reproduced in Windows (MinGW 7.2.0).
strdup is creating new memory for you to hold a duplicate of the string. The memory is only as long as strlen(file_path) + 1. You then try to add an extra 2 characters into memory that you don't own. You will go out of range of the memory created and create some undefined behaviour. It might print because setting the memory and printing the first part could be happening correctly, but it is undefined and anything can happen. Also note, in strdup you need to call free on the memory it creates for you, or you are going to leak some memory.
Here is a much simpler way to do this, use a std::string:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
std::string file_bk_path = std::string(file_path) + ".bk";
std::cout << file_bk_path << "\n";
Here is a live example.
If it absolutely needs to be in C-style then you are better off controlling the memory yourself:
const char *file_path = "D:/MyFolder/YetAnotherFolder/test.txt";
const char *bk_string = ".bk";
char *file_bk_path = malloc((strlen(file_path) + strlen(bk_string) + 1)*sizeof(char));
if (!file_bk_path) { exit(1); }
strcpy(file_bk_path, file_path);
strcat(file_bk_path, bk_string);
printf("%s\n", file_bk_path);
free(file_bk_path);
Here is a live example.
As mentioned in the comments and answers, strdup mallocs the length of your path string, plus an extra cell for the string end character '\0'. When you concatenate to this two characters writing after the allocated area.
Following #Ben's comments, I'd like to elucidate some more:
To be clear strcat adds a delimiter, but this is already after the memory you were allocated.
In general unless you specifically hit no-no addresses, the program will probably run fine - in fact this is a common hard to find bug. If for example you allocate some more memory right after that address, you will be deleting said delimiter (so printing the string will read further into the memory.
So in general, you may be OK crash wise. The crash (probably) occurs when the program ends, and the OS cleans up the memory you forgot to free yourself - That extra cell is a memory leak, and will cause the crash. So you do get a full print, and only after a crash.
Of course all of this is undefined behavior, so may depend on the compiler and OS.

Character Constant Array is empty, even though values has been assigned to it [C++]

I am facing problems while assigning string value in a character constant array. Every time when it assigns string value to a particular position of character array. That position value in an array become initialized to empty string, after getting a new value in string variable. I have tried hard to get it out but in vain. Following is the code that I am using:
const char *array[40];
string line="";
ifstream myfile( "text.txt");
if (myfile)
{
int in=0;
while (getline( myfile, line ))
{
array[in]=line.data();
in++;
}
myfile.close();
}
else return;
Now, array variable has all the empty string values. Please let me know how can I do it?
You are accessing the internal data buffer of string object line and let array[in] point to it. When reading the next line, this buffer is either overwritten or may point to a different memory location, such that the previously written array[in] points to a memory that has been overwritten with new content or is invalid at all.
If you want to use a const char*[...] array, copy the buffer first:
array[in]= strdup(line.c_str());
Note further, that line.data() gives you an array but without guarantee of a terminating 0x0 at the end. See documentation of string::data() at cppreference.com

Expected behaviour when assigning std::string to non-terminated char array?

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).

Why does program's calling strncat() generate segmentation fault?

I am having trouble trying to figure how why my g++ compiled program seg faults at a strncat() call.
I've been jumping around this site and general Googling and found a number of similar problems but haven't found any solutions that work for me. This is part of a much larger code and there's only so much I can do to redefine variables as the code isn't mine.
All this section of the code is meant to do is read in the last line of a file, remove the relevant data and concatenate to a char*
When I run it, I get a segmentation fault at the line with strncat(RAM,nextchar,1)
char line[256]={"0"};
char nextchar[10]={"0"};
int length=0;
double rac;
double decc;
bool SPACE=false;
char * RAM="RA: ";
char * DECM="DEC: ";
if(AutoColData.good()){
while(!AutoColData.eof()) AutoColData.getline(line,256);
for(int i=0;i<strlen(line);i++){
nextchar[0]=line[i];
cout<<line[i];
if(isspace(nextchar[0])&& !SPACE) SPACE=!SPACE;
else if(SPACE && !isspace(nextchar[0])){
SPACE=!SPACE;
length++;
}
if(length==6) {
cout<<"\n"<<RAM<<nextchar<<"\n";
strncat(RAM,nextchar,1);
}
else if(length==7) strcat(DECM,nextchar);
}
}
There are some sloppy choices here, I know (the whole "SPACE" thing is messy). But I don't see any reason for this to Seg Fault. It runs fine up until the line with strncat(). The cout works fine, both strings print and have the right data in them but then strncat fails. I've tried using malloc(), strings and nothing seems to work. If anyone could point out what stupid thing I'm doing, it would be very helpful. Thank you.
RAM is wrongly declared as a char *, when it really should be a const char *: String literals are read-only, and you are not allowed to write to them. Your strncat call is simply undefined behaviour.
If you want a writable string, you could make a large enough char array: char RAM[100] = "RA: "; (this will be zero-padded at the back), or better even, just use std::string:
std::string RAM = "RA: ";
RAM += nextchar;

C++ char* in methods

Listen people, i want to write a method that gets a line from the user, so i wrote this:
static char* getline(){
char temp[0];
cin >> temp;
return temp;
}
I also have a writeline method:
static void writeline(char* text){
cout<<text<<endl;
}
and then i go to the main and wrote this:
writeline(getline());
and it didnt work..
i want to say that when i wrote this:
static char* getline(){
char temp[0];
cin >> temp;
writeline(getline());
return temp;
}
and i wrote in main this:
getline();
it did work!
so what do i need to do?
There are a few things going on here.
First, you have to allocate memory when working with char*; a zero-length array won't be long enough. It's a lot easier to just use std::string which takes care of all the dirty work for you. Further, an array declared with a size in your function is allocated on the stack rather than the heap; once your getline function returns, the memory is no longer valid.
Second, the >> operator for strings reads the next word, not the next line. For that you need the getline method. Here comes the tricky thing: getline doesn't use std::string, so you still need the char*. You just don't want to return one, because then you need to deallocate it unless it's a global (or static) array. So, what you can do is the following:
std::string getline() {
char buf[1024]; // we have a cap on the line size
cin.getline(buf, 1024); // reads a line, up to 1023 characters
return std::string(buf); // makes a copy of buf into a properly-managed string
}
void writeline(const std::string &s) {
cout <<s <<endl;
}
Now you can do
writeline(readline());
and it should work fine. You can see here for more info on cin.getline().
There are two issues with your code.
First, you are trying to read a variable size input into a fixed-size array that is not a sufficient size - temp[0] may only be a single byte long. You are overruning the array and stomping on other data that is on the stack (like the return address.) This could cause a crash or odd behavior when the function returns.
Second, you are returning a local variable from a function. As soon as the function returns, the variable is out of scope and its stack space will be reused. You need to actually allocate memory if you are going to return it from a function.
The reason the second version works is that the stack-based array is still valid during the call to getline(), and since arrays grow downward getline() is immune to any stack corruption that was caused.
I think the problem is that your char temp[0] is defined inside the function (local to the function). Another problem i see is the temp[0], how many characters are you trying to allocate for the text input?
your returning corrupted memory, thats why
static char* getline(){
char temp[0];
cin >> temp;
return temp;
}
change this to
char temp[10000]; // put this outside in a class or global, give it some space
static char* getline(){
cin >> temp;
return temp;
}
There are a few things that are a bit suspect here.
First of all inside the getline() function you are declaring
char temp[0];
Which is an array of characters with no members. That can't possibly be what you intend.
Secondly your declaration of temp is as a variable on the stack. You can't use it as the return value of the function as it will go out of scope when you return.
Finally cin >> will only return a single character. Since your function is called getline I assume you want whole lines.
cin can do that for you using the getline function, but you need to pass it a buffer to put the line into.
See this reference:
http://www.cplusplus.com/reference/iostream/istream/getline/