Bug 11699 - FileStream writing incorrectly (some internal position is wrong)
Summary: FileStream writing incorrectly (some internal position is wrong)
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: mscorlib (show other bugs)
Version: unspecified
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: marcos.henrich
URL:
Depends on:
Blocks:
 
Reported: 2013-04-10 05:48 UTC by Andrii Nakryiko
Modified: 2016-02-29 14:01 UTC (History)
5 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Andrii Nakryiko 2013-04-10 05:48:29 UTC
We've had a problems with FileStream under Mono (different versions, both 2.10.x and 3.0.x). It seems like some internal positioning problem, because instead of overwriting some parts of file, it just appends written data. It is very critical that the amount of bytes written is larger than internal buffer size. I've managed to create small isolated test case that shows both what is necessary for bug to occur and easy workaround for that. But hopefully this will be fixed as this is core functionality.

    using System;
    using System.IO;
    using NUnit.Framework;

    [TestFixture]
    public class mono_filestream_bug
    {
        [Test]
        public void show_time()
        {
            const int pos = 1;
            const int bufferSize = 128;

            var filename = Path.GetTempFileName();
            File.WriteAllBytes(filename, new byte[pos + 1]); // init file with zeros

            var bytes = new byte[bufferSize + 1 /* THIS IS WHAT MAKES A BIG DIFFERENCE */];
            new Random().NextBytes(bytes);

            using (var file = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.Read,
                                             bufferSize, FileOptions.SequentialScan))
            {
                file.Read(new byte[pos], 0, pos); // THIS READ IS CRITICAL, WITHOUT IT EVERYTHING WORKS
                Assert.AreEqual(pos, file.Position); // !!! here it says position is correct, but writes at different position !!!
                // file.Position = pos; // !!! this fixes test !!!
                file.Write(bytes, 0, bytes.Length);

                //Assert.AreEqual(pos + bytes.Length, file.Length); -- fails
            }

            using (var filestream = File.Open(filename, FileMode.Open, FileAccess.Read))
            {
                var bb = new byte[bytes.Length];
                filestream.Position = pos;
                filestream.Read(bb, 0, bb.Length);
                Assert.AreEqual(bytes, bb);
            }
        }
    }
Comment 1 Marek Safar 2013-04-24 03:38:19 UTC
We are mixing reading and writing buffer offsets here. We need to split buf_offset to be read and write specific
Comment 2 Andrii Nakryiko 2013-06-25 09:56:43 UTC
Any updates on this issue?
Comment 3 Miguel de Icaza [MSFT] 2015-05-20 16:12:51 UTC
The issue in this particular bug is that our first call to Read() will fill the buffer with as much data as possible, in this case 2 bytes.

The reason why file.Position returns 1 instead of 2 is because we are not actually calling the OS seek functionality.  We only do that when the Handle has been surfaced (isExposed).

So the right fix, like Marek suggests is to keep two separate poiters.

For reference, this is what the CoreFX does: 

https://github.com/dotnet/corefx/blob/master/src/System.IO.FileSystem/src/System/IO/FileStream.cs
Comment 4 marcos.henrich 2016-02-25 18:56:22 UTC
After a successful Read the buffer position is updated to the char after the last one read.
The problem as mentioned by Miguel is that the position does not reflect the actual file handle position.

The pull request below fixes this by doing a seek before the write. 
https://github.com/mono/mono/pull/2678
Comment 5 marcos.henrich 2016-02-29 14:01:58 UTC
Fixed in mono master 7013a709c30ab2f1e1eee56b7aa8d4088e7f555e.
https://github.com/mono/mono/commit/7013a709c30ab2f1e1eee56b7aa8d4088e7f555e

Should be included in Cycle 8, Mono 4.6.