Thread: wifstream crashes the program

  1. #1
    Registered User
    Join Date
    Aug 2007
    Posts
    13

    wifstream crashes the program

    I am having problem to write a wstring to a file. I have made functions to write and read strings and wstrings but for a reason the I don't know it doesn't work for wstrings.

    Here is my header
    Code:
    #include <string>
    #include <fstream>
    #ifndef _FSTRINGSTREAM_H
    #define _FSTRINGSTREAM_H
    void string_to_file(std::string &s, std::ofstream &fout)
    {
        int len = s.length();
        len++;            // You need to write a '\0' at the end of a char*
        fout.write(reinterpret_cast<char *> (&len), sizeof(int));
        fout.write(s.c_str(), len);
    }
    
    std::string file_to_string(std::ifstream &fin)
    {
        int len;
        fin.read(reinterpret_cast<char *> (&len), sizeof(int));
        char *str_s = new char[len];
        fin.read(str_s, len);
        std::string s = str_s;
        delete str_s;
        return s;
    }
    
    void wstring_to_file(std::wstring &w, std::wofstream &wfout)
    {
        int len = w.length();
        len++;            // You need to write a '\0' at the end of a wchar_t*
        wfout.write(reinterpret_cast<wchar_t *> (&len), sizeof(int));
        wfout.write(w.c_str(), len);
    }
    
    std::wstring file_to_wstring(std::wifstream &wfin)
    {
        int len;
        wfin.read(reinterpret_cast<wchar_t *> (&len), sizeof(int));
        wchar_t *str_w = new wchar_t[len];
        wfin.read(str_w, len);
        std::wstring w = str_w;
        delete str_w;
        return w;
    }
    #endif
    And here is the file I am testing on:
    Code:
    #include <iostream>
    #include <string>
    #include <fstream>
    #ifndef _FSTRINGSTREAM_H
    #include "fstringstream.h"
    #endif
    using namespace std;
    
    int main()
    {
        wofstream fout("testfile.dat");
        if ( !fout.is_open() )
        {
            cerr << "ERROR: can't open file";
            exit(1);
        }
        
        wstring s = L"test";
        wstring_to_file(s, fout);
        fout.close();
        
        wifstream fin("testfile.dat");
        if ( !fin.is_open() )
        {
            cerr << "ERROR: can't open file";
            exit(1);
        }
        
        s = file_to_wstring(fin);
        fin.close();
        wcout << s;
        
        return 0;
    }
    The program gets compiled without problems with Borland C++ compiler 5.5.1 but if I run the program, I get the text "Abnormal program termination". The first time I run the program (and the first time after restarting the computer) Windows gives me the message that there is not enough virtual memory available.

  2. #2
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Code:
        wfout.write(reinterpret_cast<wchar_t *> (&len), sizeof(int));
    I don't think that's a good idea.
    wchar_t is 2 bytes, and you pass in a buffer size of 4 bytes! So the actual buffer length is actually 8 bytes, more than the number of bytes occupied by your integer.
    That means you're writing the len value + 4 undefined bytes which you read back later and get an undefined size.
    Last edited by Elysia; 12-26-2007 at 05:03 AM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  3. #3
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by Elysia View Post
    I don't think that's a good idea.
    wchar_t is TWO bytes, and you pass in a buffer size of 4 bytes!
    That means you're writing the len value + 2 undefined bytes which you read back later and get an undefined size.
    ??
    Think about it again. The cast is only there because write just wants a char* / wchar_t*.
    Kurt

  4. #4
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    He's not writing a wchar_t. He's casting it to a wchar_t *. That could very well still be 4 bytes on a 32-bit machine. It's still wrong, of course.

    Edit: Actually no, I don't think it's wrong per se. Just convoluted because of how the write() function is. To make it better perhaps he should be writing sizeof() with the variable name instead of the type (ie. sizeof(len) vs sizeof(int). That might help make it a little more obvious.
    Last edited by MacGyver; 12-26-2007 at 04:59 AM.

  5. #5
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by MacGyver View Post
    It's still wrong, of course.
    Don't understand that. He's writing 4 bytes of length. Propably 2 or 3 0-bytes but they are there in an int.

    Kurt

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    It turns out wrong, as in this example:
    Code:
    int GetLength(wchar_t* p, int BufSize)
    {
    	wchar_t* pBuffer;
    	pBuffer = new wchar_t[BufSize];
    	for (int i = 0; i < BufSize; i++)
    		pBuffer[i] = p[i];
    	int nReturn;
    	for (int i = 0; i < BufSize; i++)
    		nReturn += p[i] << i * 8;
    	delete [] pBuffer;
    	return nReturn;
    }
    
    void Help()
    {
    	int len = 100;
    	int newlen = GetLength((wchar_t*)&len, sizeof(int));
    }
    Unless write() casts that wchar_t* to a char* internally, it will write 4 more bytes than it should. Thus an undefined value is written and read back.
    Since wchar_t is two bytes, the buffer size is supposed to be 2. The first element gets bytes 1 & 2 and writes them successfully to the buffer. The second takes 3 & 4 and does the same.
    But wait... an int is only 4 bytes! So when the loop comes on the 3rd (bytes 5 & 6) and 4th (bytes 7 & 8) run, it will read junk and store into the buffer.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Deathray Engineer MacGyver's Avatar
    Join Date
    Mar 2007
    Posts
    3,210
    Yeah, I edited my post. I was thinking something else. It's not actually wrong at all.

  8. #8
    Registered User
    Join Date
    Aug 2007
    Posts
    13
    Maybe it is because of my bad English but I don't still understand how I must solve the problem and I don't understand the problem itself very well (why does the write function for the normal string work after looking on what you have wrote). I also don't understand what your doing in the second for-statement.

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    > wchar_t *str_w = new wchar_t[len];
    > wfin.read(str_w, len);
    > std::wstring w = str_w;
    > delete str_w;
    1. does len represent the number of bytes (which read will need), or the number of wchar's (which new will need) ?
    2. The assignment will fail, because there is no \0 at the end. That is, unless you always write a \0 and include that in your count when you write the file.
    3. The delete needs to be delete [ ] str_w. If you use [ ] on the new, then you must use [ ] on the delete.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    The easiest fix is to make this:
    Code:
    wfout.write(reinterpret_cast<wchar_t *> (&len), sizeof(int));
    Into this:
    Code:
    wfout.write(reinterpret_cast<wchar_t *> (&len), sizeof(int) / sizeof(wchar_t));
    And this:
    Code:
     wfin.read(reinterpret_cast<wchar_t *> (&len), sizeof(int));
    Into this:
    Code:
     wfin.read(reinterpret_cast<wchar_t *> (&len), sizeof(int) / sizeof(wchar_t));
    The problem lies in that write take a wchar_t* pointer, which is 2 bytes. 2 bytes for each index. So:

    Code:
    const wchar_t* my_str = L"My string";
    my_str[0]; // Represents bytes 1 & 2.
    my_str[1]; // Represents bytes 3 & 4.
    
    const char* my_str = "My string";
    my_str2[0]; // Represents byte 1
    my_str2[1]: // Represents byte 2.
    The write function writes the number of elements that you specify in the size parameter.
    Thus, it writes index 0, 1, 2 and 3. Bytes 1 & 2, 3 & 4, 5 & 6, 7 & 8. But an int is only 4 bytes long, so the range bytes 5-8 is not part of your int and is something else.

    Does this make sense?
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  11. #11
    Registered User
    Join Date
    Aug 2007
    Posts
    13
    1. len is the number of wchar's. I have replaced wfin.read(str_w, len) by wfin.read(str_w, len*sizeof(wchar_t)); and the same for wfout.read(...);
    2. This will not fail because there is a statement len++ for the '\0';
    3. Your right that I have forgotten [] on the delete.

    But the program still returns "Abnormal program termination".

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Wicket View Post
    1. len is the number of wchar's. I have replaced wfin.read(str_w, len) by wfin.read(str_w, len*sizeof(wchar_t)); and the same for wfout.read(...);
    This is not right.
    It should be:
    Code:
    wfin.read(str_w, len) by wfin.read(str_w, len / sizeof(wchar_t));
    For both read and write. Think a moment what you're doing.

    sizeof(int) is presumably 4 bytes (it is on 32-bit system), so let's assume it's 4 bytes. Then you do * sizeof(wchar_t) which is 2, that makes it 8! And then the write tries to write 8 indexes, thus writing 8 * 2 = 16 bytes. That's a lot more than those 4 bytes of your len variable.

    But if you it the other way... sizeof(int) = 4 / sizeof(wchar_t) = 2 = 7 / 2 = 2. So 2 indexes &#225; 2 bytes = 2 * 2 = 4 bytes. So it writes 4 bytes total, the exact amount of bytes that your len variable is.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Aug 2007
    Posts
    13
    Yes, the functions are working good and I am understanding it better. There is something in testfile.dat.

    I have only the problem left that the program doesn't crash if I remove the line wcout << s; on the end of main().

  14. #14
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Writing binary data using the wide streams is simply wrong, end of story. Use the narrow streams if you want to deal in binary data.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #15
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Translation:
    Don't write binary data using std::wofstream, use std::ofstream.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Simple login program - Crashes :(
    By spadez in forum C Programming
    Replies: 1
    Last Post: 03-23-2009, 04:16 PM
  2. Replies: 3
    Last Post: 02-29-2008, 01:29 PM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. program crashes on closure.
    By ssjnamek in forum C++ Programming
    Replies: 7
    Last Post: 09-26-2005, 04:55 PM
  5. My program crashes with this code
    By blackwyvern in forum C++ Programming
    Replies: 3
    Last Post: 01-28-2002, 12:28 AM