Fix crash when trying to read empty replay files

It was crashing because it tried to seek 8 bytes before the end
of a file that was empty (zero length).

I also added a few more checks and another try/catch to prevent
any more crashes related to damaged files.
This commit is contained in:
Pavlos Touboulidis
2014-05-13 22:29:56 +03:00
parent f4c52eefae
commit 38a5e326f6

View File

@@ -46,8 +46,8 @@ namespace OpenRA.FileFormats
if (version != MetaVersion)
throw new NotSupportedException("Metadata version {0} is not supported".F(version));
// Read game info
string data = ReadUtf8String(reader);
// Read game info (max 100K limit as a safeguard against corrupted files)
string data = ReadUtf8String(reader, 1024 * 100);
GameInfo = GameInformation.Deserialize(data);
}
@@ -87,28 +87,38 @@ namespace OpenRA.FileFormats
if (!fs.CanSeek)
return null;
fs.Seek(-(4 + 4), SeekOrigin.End);
using (var reader = new BinaryReader(fs))
if (fs.Length < 20)
return null;
try
{
var dataLength = reader.ReadInt32();
if (reader.ReadInt32() == MetaEndMarker)
fs.Seek(-(4 + 4), SeekOrigin.End);
using (var reader = new BinaryReader(fs))
{
// go back end marker + length storage + data + version + start marker
fs.Seek(-(4 + 4 + dataLength + 4 + 4), SeekOrigin.Current);
try
var dataLength = reader.ReadInt32();
if (reader.ReadInt32() == MetaEndMarker)
{
return new ReplayMetadata(reader, path);
}
catch (InvalidOperationException ex)
{
Log.Write("debug", ex.ToString());
}
catch (NotSupportedException ex)
{
Log.Write("debug", ex.ToString());
// go back by (end marker + length storage + data + version + start marker) bytes
fs.Seek(-(4 + 4 + dataLength + 4 + 4), SeekOrigin.Current);
try
{
return new ReplayMetadata(reader, path);
}
catch (InvalidOperationException ex)
{
Log.Write("debug", ex.ToString());
}
catch (NotSupportedException ex)
{
Log.Write("debug", ex.ToString());
}
}
}
}
catch (IOException ex)
{
Log.Write("debug", ex.ToString());
}
return null;
}
@@ -128,9 +138,13 @@ namespace OpenRA.FileFormats
return 4 + bytes.Length;
}
static string ReadUtf8String(BinaryReader reader)
static string ReadUtf8String(BinaryReader reader, int maxLength)
{
return Encoding.UTF8.GetString(reader.ReadBytes(reader.ReadInt32()));
var length = reader.ReadInt32();
if (length > maxLength)
throw new InvalidOperationException("The length of the string ({0}) is longer than the maximum allowed ({1}).".F(length, maxLength));
return Encoding.UTF8.GetString(reader.ReadBytes(length));
}
}
}