Lost a lot of time the last days trying to get Keepass 2.28 to run on my OpenSUSE Linux box with mono. Keepass window opened correctly, but whenever I tried accessing a file (either open an existing or create a new one), it crashed with a "System.Text.DecoderFallbackException".
After trying a lot of Mono workarounds (as some old posts suggested Mono issues here), I finally found that it was trying to modify my ~/.recently-used file and expected an XML there. For any reason, this was a binary file on my system leading to the mentioned crash.
After removing the file, it worked well.
Could you please either fix this in Keepass or add an according note to http://keepass.info/help/v2/setup.html? Thanks!
Reproducing is easy:
# cd
# mv .recently-used .recently-used.sic
# cp /bin/bash .recently-used
# cd Keepass-dir
# mono KeePass.exe
# Click on icon to create new DB
System.Xml.XmlException: Invalid data ---> System.Text.DecoderFallbackException: Exception of type 'System.Text.DecoderFallbackException' was thrown.
at System.Text.DecoderExceptionFallbackBuffer.Fallback (System.Byte[] bytesUnknown, Int32 index) [0x00000] in <filename unknown>:0
at System.Text.UTF8Encoding.Fallback (System.Object provider, System.Text.DecoderFallbackBuffer& buffer, System.Byte[]& bufferArg, System.Byte* bytes, Int64 byteIndex, UInt32 size, System.Char* chars, System.Int32& charIndex) [0x00000] in <filename unknown>:0
at System.Text.UTF8Encoding.InternalGetChars (System.Byte* bytes, Int32 byteCount, System.Char* chars, Int32 charCount, System.UInt32& leftOverBits, System.UInt32& leftOverCount, System.Object provider, System.Text.DecoderFallbackBuffer& fallbackBuffer, System.Byte[]& bufferArg, Boolean flush) [0x00000] in <filename unknown>:0
at System.Text.UTF8Encoding.InternalGetChars (System.Byte[] bytes, Int32 byteIndex, Int32 byteCount, System.Char[] chars, Int32 charIndex, System.UInt32& leftOverBits, System.UInt32& leftOverCount, System.Object provider, System.Text.DecoderFallbackBuffer& fallbackBuffer, System.Byte[]& bufferArg, Boolean flush) [0x00000] in <filename unknown>:0
at System.Text.UTF8Encoding+UTF8Decoder.GetChars (System.Byte[] bytes, Int32 byteIndex, Int32 byteCount, System.Char[] chars, Int32 charIndex) [0x00000] in <filename unknown>:0
at System.Xml.NonBlockingStreamReader.ReadBuffer () [0x00000] in <filename unknown>:0
at System.Xml.NonBlockingStreamReader.Read (System.Char[] dest_buffer, Int32 index, Int32 count) [0x00000] in <filename unknown>:0
at System.Xml.XmlStreamReader.Read (System.Char[] dest_buffer, Int32 index, Int32 count) [0x00000] in <filename unknown>:0
--- End of inner exception stack trace ---
at System.Xml.XmlStreamReader.Read (System.Char[] dest_buffer, Int32 index, Int32 count) [0x00000] in <filename unknown>:0
at Mono.Xml2.XmlTextReader.ReadTextReader (Int32 remained) [0x00000] in <filename unknown>:0
at Mono.Xml2.XmlTextReader.PeekChar () [0x00000] in <filename unknown>:0
at Mono.Xml2.XmlTextReader.ReadContent () [0x00000] in <filename unknown>:0
at Mono.Xml2.XmlTextReader.Read () [0x00000] in <filename unknown>:0
at System.Xml.XmlTextReader.Read () [0x00000] in <filename unknown>:0
at Mono.Xml.EntityResolvingXmlReader.Read () [0x00000] in <filename unknown>:0
at Mono.Xml.DTDValidatingReader.ReadContent () [0x00000] in <filename unknown>:0
at Mono.Xml.DTDValidatingReader.Read () [0x00000] in <filename unknown>:0
at Mono.Xml.Schema.XsdValidatingReader.Read () [0x00000] in <filename unknown>:0
at System.Xml.XmlValidatingReader.Read () [0x00000] in <filename unknown>:0
at System.Xml.XmlDocument.ReadNodeCore (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Xml.XmlDocument.ReadNode (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Xml.XmlDocument.Load (System.Xml.XmlReader reader) [0x00000] in <filename unknown>:0
at System.Xml.XmlDocument.Load (System.String filename) [0x00000] in <filename unknown>:0
at System.Windows.Forms.UnixFileSystem.WriteRecentlyUsedFiles (System.String fileToAdd) [0x00000] in <filename unknown>:0
at System.Windows.Forms.MWFVFS.WriteRecentlyUsedFiles (System.String filename) [0x00000] in <filename unknown>:0
at System.Windows.Forms.MWFFileView.WriteRecentlyUsed (System.String fullfilename) [0x00000] in <filename unknown>:0
at (wrapper remoting-invoke-with-check) System.Windows.Forms.MWFFileView:WriteRecentlyUsed (string)
at System.Windows.Forms.FileDialog.OnClickOpenSaveButton (System.Object sender, System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Control.OnClick (System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Button.OnClick (System.EventArgs e) [0x00000] in <filename unknown>:0
at System.Windows.Forms.ButtonBase.OnMouseUp (System.Windows.Forms.MouseEventArgs mevent) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Button.OnMouseUp (System.Windows.Forms.MouseEventArgs mevent) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Control.WmLButtonUp (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Control.WndProc (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.ButtonBase.WndProc (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Button.WndProc (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Control+ControlWindowTarget.OnMessage (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.Control+ControlNativeWindow.WndProc (System.Windows.Forms.Message& m) [0x00000] in <filename unknown>:0
at System.Windows.Forms.NativeWindow.WndProc (IntPtr hWnd, Msg msg, IntPtr wParam, IntPtr lParam) [0x00000] in <filename unknown>:0
Works fine on my Ubuntu x64.
As the .recently-used file is not created by KeePass I can't see why KeePass should check it for validity.
KeePass stores recently used file information in /usr/USER/.config/KeePass/KeePass.config.xml on my Ubuntu. Is that the file you are expecting?
cheers, Paul
No, I'm exactly speaking about $HOME/.recently-used. In the working state, it looks like this:
As you can see, all used Keepass databases will end up there. I also have /home/gernot/.config/KeePass/KeePass.config.xml, but this is completely different and did NOT cause my problem. I strace-d it and found that it crashed after accessing $HOME/.recently-used and could prove it by just removing that file.
After a closer look to the backtrace above, I start to believe that this is an implementation detail of Mono. Likely, the FileDialog implementation internally uses this file on Linux to store file open history. As I've neither any clue about Mono internals nor about .NET programming, I'm not sure whether you can influence this in KeePass at all.
So probably one should verify this with a small Mono test program and file another bug report with Mono folks...
Nevertheless, it could help to add a small hint to the KeePass Setup page?
Ok, so I think here are the missing bits:
FreeDesktop standard for this file:
http://standards.freedesktop.org/recent-file-spec/recent-file-spec-0.2.html
Mono access code:
https://github.com/mono/mono/blob/mono-3.8.0-branch/mcs/class/Managed.Windows.Forms/System.Windows.Forms/FileDialog.cs#L962
https://github.com/mono/mono/blob/mono-3.8.0-branch/mcs/class/Managed.Windows.Forms/System.Windows.Forms/FileDialog.cs#L3815
=> So it seems this is a Mono implementation detail which can trigger an unexpected exception when using the FileDialog on a system with broken recently-used file. As the freedesktop standard also clearly states that this file should be XML, having a binary file is probably not to be expected, so I probably just had bad luck...
Looks like you had an unusual problem that is specific to OpenSUSE. Let us know if you have more problems or a solution.
cheers, Paul
It's not an OpenSUSE specific issue. It still occurs at KeePass 2.30 on Ubuntu 14.04
It's the System.Xml component throwing an exception at a badly formed XML file.
The KeePass app then surfaces the exception and crashes, rather than swallowing it and saying I don't care if the .recently-used file is XML invalid, and that being the case, I'll warn and ignore it.
You can find the issue in the file with
In my case it was libreoffice not putting a closing tag at the end of the file, as it made a mess of the last entry. I deleted the last RecentItem block and added an end tag
Now KeyPass can open, new and save files.
If KeePass can't tell mono to behave gracefully with a try-catch on the FileDialog, then it should pre-flight check the xml .recently-used file, and dialog offer options to fix it, delete it, rename it, or pause until it is manually fixed.
This is a moderate impact bug, as it causes KeyPass to die on first-time use, when saving it's first database, when used on a machine for the first time that has a longtime invalid recently used file. This could cause new users to go ahh, garbage and move on to another app.
It could also mean long-time keepass users suddenly can't access or save their database, through no fault of keepass, as any other app could mess up the shared recently-used file. This could cause stress if it's at a critical login time, such as a banking or physical access transaction.
The exception cannot simply be ignored using a try-catch, because then KeePass doesn't get the results (file names) of the FileDialog.
I've now implemented the following: before showing a FileDialog, KeePass tries to load the file ~/.recently-used and deletes it, if it doesn't contain valid XML data. This behavior should be ok, as the file doesn't contain any important data anyway and other applications probably would have problems loading the file, too.
Here's the latest KeePass development snapshot for testing:
http://keepass.info/filepool/KeePass_151121.zip
Thanks and best regards,
Dominik