diff --git a/SharpCoreDB/DataStructures/Table.cs b/SharpCoreDB/DataStructures/Table.cs index b7dad838..46a3e74a 100644 --- a/SharpCoreDB/DataStructures/Table.cs +++ b/SharpCoreDB/DataStructures/Table.cs @@ -193,15 +193,44 @@ private List> SelectInternal(string? where, string? o using var reader = new BinaryReader(ms); while (ms.Position < ms.Length) { - var row = new Dictionary(); - bool valid = true; - for (int i = 0; i < this.Columns.Count; i++) + try { - try { row[this.Columns[i]] = this.ReadTypedValue(reader, this.ColumnTypes[i]); } - catch { valid = false; break; } + // Read the length prefix that was written by AppendBytes + int recordLength = reader.ReadInt32(); + + // Validate length to prevent issues with corrupted data + if (recordLength < 0 || recordLength > data.Length) + { + break; // Corrupted record, stop scanning + } + + // Read the record data + var recordData = reader.ReadBytes(recordLength); + + // Deserialize the record + using var recordMs = new MemoryStream(recordData); + using var recordReader = new BinaryReader(recordMs); + + var row = new Dictionary(); + bool valid = true; + for (int i = 0; i < this.Columns.Count; i++) + { + try { row[this.Columns[i]] = this.ReadTypedValue(recordReader, this.ColumnTypes[i]); } + catch { valid = false; break; } + } + if (valid && (string.IsNullOrEmpty(where) || EvaluateWhere(row, where))) + results.Add(row); + } + catch (EndOfStreamException) + { + // Reached end of file + break; + } + catch (Exception) + { + // Corrupted record, skip and continue + break; } - if (valid && (string.IsNullOrEmpty(where) || EvaluateWhere(row, where))) - results.Add(row); } } } diff --git a/SharpCoreDB/Services/Storage.cs b/SharpCoreDB/Services/Storage.cs index 3c43755c..f99c7cc4 100644 --- a/SharpCoreDB/Services/Storage.cs +++ b/SharpCoreDB/Services/Storage.cs @@ -199,16 +199,24 @@ public long AppendBytes(string path, byte[] data) using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); fs.Seek(position, SeekOrigin.Begin); - var buffer = new byte[maxLength]; - int bytesRead = fs.Read(buffer, 0, maxLength); - if (bytesRead == 0) + using var reader = new BinaryReader(fs); + + // Read the length prefix that was written by AppendBytes + int length = reader.ReadInt32(); + + // Validate length to prevent excessive memory allocation + if (length < 0 || length > maxLength * 10) // Allow some buffer but prevent abuse { - return null; + throw new InvalidDataException($"Invalid record length: {length}"); } - - if (bytesRead < maxLength) + + // Read the actual data (maxLength is for the data portion, not including prefix) + int bytesToRead = Math.Min(length, maxLength); + var buffer = reader.ReadBytes(bytesToRead); + + if (buffer.Length == 0) { - Array.Resize(ref buffer, bytesRead); + return null; } var effectiveNoEncrypt = noEncrypt || this.noEncryption;