Your code is setting the lpstrFile (to point at the buffer obtained with GetBuffer) BUT it's not setting the corresponding nMaxFile member, which must be set to the size of the buffer pointed to by lpstrFile.
According to MSDN, the buffer should be at least 256 characters long (see MSDN notes on nMaxFile in entry for OPENFILENAME structure.) But most people use _MAX_PATH here, which is 260, a #define provided by the CRT for this purpose.
fileDlg.m_ofn.lpstrFile = fileName.GetBuffer(_MAX_PATH);
fileDlg.m_ofn.nMaxFile = _MAX_PATH;
BUT another part of the problem is that you were reinventing the wheel. The MFC automatically handles the initial filename if you pass it as the third parameter of the constructor call. They set up an internal buffer and the length during construction. So your crash was probably because you were changing lpstrFile to point to a smaller buffer but not altering nMaxFile, which was still set to the default 260 chars. Of course, when you made your buffer longer than 260, the problem went away.
So, if you let MFC do more of the work, you end up with:
CString fileName = getDefaultFileName(false); //returns a CString. it also uses
//CString Replace and Remove functions.
fileName, // let MFC know the initial filename (they copy it into their buffer)
_T("Ignore this line (*.txt, *.xml)|*.txt;*.xml||")
if(IDOK == fileDlg.DoModal())
save_file( fileDlg.GetPathName(), false );
Which doesn't need either GetBuffer or ReleaseBuffer to be used!
PS The only time I have seen an external buffer provided to CFileDialog is when its being used in multi-select mode, in which case you need more space than 260 chars.