Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions src/libraries/System.Console/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,6 @@
<data name="IO_SharingViolation_NoFileName" xml:space="preserve">
<value>The process cannot access the file because it is being used by another process.</value>
</data>
<data name="IndexOutOfRange_IORaceCondition" xml:space="preserve">
<value>Probable I/O race condition detected while copying memory. The I/O package is not thread safe by default. In multithreaded applications, a stream must be accessed in a thread-safe way, such as a thread-safe wrapper returned by TextReader's or TextWriter's Synchronized methods. This also applies to classes like StreamWriter and StreamReader.</value>
</data>
<data name="Arg_InvalidConsoleColor" xml:space="preserve">
<value>The ConsoleColor enum value was not defined on that enum. Please use a defined color from the enum.</value>
</data>
Expand Down
6 changes: 3 additions & 3 deletions src/libraries/System.Console/src/System/ConsolePal.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ internal sealed unsafe class LogcatStream : ConsoleStream
{
public LogcatStream() : base(FileAccess.Write) {}

public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported();
public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();

public override unsafe void Write(byte[] buffer, int offset, int count)
public override unsafe void Write(ReadOnlySpan<byte> buffer)
{
string log = ConsolePal.OutputEncoding.GetString(buffer, offset, count);
string log = ConsolePal.OutputEncoding.GetString(buffer);
Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", log);
}
}
Expand Down
33 changes: 9 additions & 24 deletions src/libraries/System.Console/src/System/ConsolePal.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1212,15 +1212,13 @@ private void AddKey(TermInfo.Database db, string extendedName, ConsoleKey key, b
/// <summary>Reads data from the file descriptor into the buffer.</summary>
/// <param name="fd">The file descriptor.</param>
/// <param name="buffer">The buffer to read into.</param>
/// <param name="offset">The offset at which to start writing into the buffer.</param>
/// <param name="count">The maximum number of bytes to read.</param>
/// <returns>The number of bytes read, or a negative value if there's an error.</returns>
internal static unsafe int Read(SafeFileHandle fd, byte[] buffer, int offset, int count)
internal static unsafe int Read(SafeFileHandle fd, Span<byte> buffer)
{
fixed (byte* bufPtr = buffer)
{
int result = Interop.CheckIo(Interop.Sys.Read(fd, (byte*)bufPtr + offset, count));
Debug.Assert(result <= count);
int result = Interop.CheckIo(Interop.Sys.Read(fd, bufPtr, buffer.Length));
Debug.Assert(result <= buffer.Length);
return result;
}
}
Expand Down Expand Up @@ -1424,26 +1422,13 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

public override int Read(byte[] buffer, int offset, int count)
{
ValidateRead(buffer, offset, count);

if (_useReadLine)
{
return ConsolePal.StdInReader.ReadLine(buffer, offset, count);
}
else
{
return ConsolePal.Read(_handle, buffer, offset, count);
}
}
public override int Read(Span<byte> buffer) =>
_useReadLine ?
ConsolePal.StdInReader.ReadLine(buffer) :
ConsolePal.Read(_handle, buffer);

public override void Write(byte[] buffer, int offset, int count)
{
ValidateWrite(buffer, offset, count);

ConsolePal.Write(_handle, buffer.AsSpan(offset, count));
}
public override void Write(ReadOnlySpan<byte> buffer) =>
ConsolePal.Write(_handle, buffer);

public override void Flush()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,13 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported();
public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();

public override unsafe void Write(byte[] buffer, int offset, int count)
public override unsafe void Write(ReadOnlySpan<byte> buffer)
{
ValidateWrite(buffer, offset, count);

fixed (byte* bufPtr = buffer)
{
Write(_handle, bufPtr + offset, count);
Write(_handle, bufPtr, buffer.Length);
}
}

Expand Down
54 changes: 20 additions & 34 deletions src/libraries/System.Console/src/System/ConsolePal.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1118,24 +1118,24 @@ protected override void Dispose(bool disposing)
base.Dispose(disposing);
}

public override int Read(byte[] buffer, int offset, int count)
public override int Read(Span<byte> buffer)
{
ValidateRead(buffer, offset, count);

int bytesRead;
int errCode = ReadFileNative(_handle, buffer, offset, count, _isPipe, out bytesRead, _useFileAPIs);
int errCode = ReadFileNative(_handle, buffer, _isPipe, out int bytesRead, _useFileAPIs);
if (Interop.Errors.ERROR_SUCCESS != errCode)
{
throw Win32Marshal.GetExceptionForWin32Error(errCode);
}

return bytesRead;
}

public override void Write(byte[] buffer, int offset, int count)
public override void Write(ReadOnlySpan<byte> buffer)
{
ValidateWrite(buffer, offset, count);

int errCode = WriteFileNative(_handle, buffer, offset, count, _useFileAPIs);
int errCode = WriteFileNative(_handle, buffer, _useFileAPIs);
if (Interop.Errors.ERROR_SUCCESS != errCode)
{
throw Win32Marshal.GetExceptionForWin32Error(errCode);
}
}

public override void Flush()
Expand All @@ -1149,35 +1149,26 @@ public override void Flush()
// world working set and to avoid requiring a reference to the
// System.IO.FileSystem contract.

private static unsafe int ReadFileNative(IntPtr hFile, byte[] bytes, int offset, int count, bool isPipe, out int bytesRead, bool useFileAPIs)
private static unsafe int ReadFileNative(IntPtr hFile, Span<byte> buffer, bool isPipe, out int bytesRead, bool useFileAPIs)
{
Debug.Assert(offset >= 0, "offset >= 0");
Debug.Assert(count >= 0, "count >= 0");
Debug.Assert(bytes != null, "bytes != null");
// Don't corrupt memory when multiple threads are erroneously writing
// to this stream simultaneously.
if (bytes.Length - offset < count)
throw new IndexOutOfRangeException(SR.IndexOutOfRange_IORaceCondition);

// You can't use the fixed statement on an array of length 0.
if (bytes.Length == 0)
if (buffer.IsEmpty)
{
bytesRead = 0;
return Interop.Errors.ERROR_SUCCESS;
}

bool readSuccess;
fixed (byte* p = &bytes[0])
fixed (byte* p = buffer)
{
if (useFileAPIs)
{
readSuccess = (0 != Interop.Kernel32.ReadFile(hFile, p + offset, count, out bytesRead, IntPtr.Zero));
readSuccess = (0 != Interop.Kernel32.ReadFile(hFile, p, buffer.Length, out bytesRead, IntPtr.Zero));
}
else
{
// If the code page could be Unicode, we should use ReadConsole instead, e.g.
int charsRead;
readSuccess = Interop.Kernel32.ReadConsole(hFile, p + offset, count / BytesPerWChar, out charsRead, IntPtr.Zero);
readSuccess = Interop.Kernel32.ReadConsole(hFile, p, buffer.Length / BytesPerWChar, out charsRead, IntPtr.Zero);
bytesRead = charsRead * BytesPerWChar;
}
}
Expand All @@ -1193,24 +1184,19 @@ private static unsafe int ReadFileNative(IntPtr hFile, byte[] bytes, int offset,
return errorCode;
}

private static unsafe int WriteFileNative(IntPtr hFile, byte[] bytes, int offset, int count, bool useFileAPIs)
private static unsafe int WriteFileNative(IntPtr hFile, ReadOnlySpan<byte> bytes, bool useFileAPIs)
{
Debug.Assert(offset >= 0, "offset >= 0");
Debug.Assert(count >= 0, "count >= 0");
Debug.Assert(bytes != null, "bytes != null");
Debug.Assert(bytes.Length >= offset + count, "bytes.Length >= offset + count");

// You can't use the fixed statement on an array of length 0.
if (bytes.Length == 0)
if (bytes.IsEmpty)
return Interop.Errors.ERROR_SUCCESS;

bool writeSuccess;
fixed (byte* p = &bytes[0])
fixed (byte* p = bytes)
{
if (useFileAPIs)
{
int numBytesWritten;
writeSuccess = (0 != Interop.Kernel32.WriteFile(hFile, p + offset, count, out numBytesWritten, IntPtr.Zero));
writeSuccess = (0 != Interop.Kernel32.WriteFile(hFile, p, bytes.Length, out numBytesWritten, IntPtr.Zero));
// In some cases we have seen numBytesWritten returned that is twice count;
// so we aren't asserting the value of it. See https://github.com/dotnet/runtime/issues/23776
}
Expand All @@ -1223,8 +1209,8 @@ private static unsafe int WriteFileNative(IntPtr hFile, byte[] bytes, int offset
// However, we do not need to worry about that because the StreamWriter in Console has
// a much shorter buffer size anyway.
int charsWritten;
writeSuccess = Interop.Kernel32.WriteConsole(hFile, p + offset, count / BytesPerWChar, out charsWritten, IntPtr.Zero);
Debug.Assert(!writeSuccess || count / BytesPerWChar == charsWritten);
writeSuccess = Interop.Kernel32.WriteConsole(hFile, p, bytes.Length / BytesPerWChar, out charsWritten, IntPtr.Zero);
Debug.Assert(!writeSuccess || bytes.Length / BytesPerWChar == charsWritten);
}
}
if (writeSuccess)
Expand Down
8 changes: 3 additions & 5 deletions src/libraries/System.Console/src/System/ConsolePal.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ internal sealed class NSLogStream : ConsoleStream
{
public NSLogStream() : base(FileAccess.Write) {}

public override int Read(byte[] buffer, int offset, int count) => throw Error.GetReadNotSupported();
public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();

public override unsafe void Write(byte[] buffer, int offset, int count)
public override unsafe void Write(ReadOnlySpan<byte> buffer)
{
ValidateWrite(buffer, offset, count);

fixed (byte* ptr = buffer)
{
Interop.Sys.Log(ptr + offset, count);
Interop.Sys.Log(ptr, buffer.Length);
}
}
}
Expand Down
62 changes: 35 additions & 27 deletions src/libraries/System.Console/src/System/IO/ConsoleStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;

namespace System.IO
{
Expand All @@ -21,66 +20,75 @@ internal ConsoleStream(FileAccess access)
_canWrite = ((access & FileAccess.Write) == FileAccess.Write);
}

protected override void Dispose(bool disposing)
public override void Write(byte[] buffer, int offset, int count)
{
_canRead = false;
_canWrite = false;
base.Dispose(disposing);
ValidateWrite(buffer, offset, count);
Write(new ReadOnlySpan<byte>(buffer, offset, count));
}

public sealed override bool CanRead
{
get { return _canRead; }
}
public override void WriteByte(byte value) => Write(MemoryMarshal.CreateReadOnlySpan(ref value, 1));

public sealed override bool CanWrite
public override int Read(byte[] buffer, int offset, int count)
{
get { return _canWrite; }
ValidateRead(buffer, offset, count);
return Read(new Span<byte>(buffer, offset, count));
}

public sealed override bool CanSeek
public override int ReadByte()
{
get { return false; }
byte b = 0;
int result = Read(MemoryMarshal.CreateSpan(ref b, 1));
return result != 0 ? b : -1;
}

public sealed override long Length
protected override void Dispose(bool disposing)
{
get { throw Error.GetSeekNotSupported(); }
_canRead = false;
_canWrite = false;
base.Dispose(disposing);
}

public sealed override bool CanRead => _canRead;

public sealed override bool CanWrite => _canWrite;

public sealed override bool CanSeek => false;

public sealed override long Length => throw Error.GetSeekNotSupported();

public sealed override long Position
{
get { throw Error.GetSeekNotSupported(); }
set { throw Error.GetSeekNotSupported(); }
get => throw Error.GetSeekNotSupported();
set => throw Error.GetSeekNotSupported();
}

public override void Flush()
{
if (!CanWrite) throw Error.GetWriteNotSupported();
}

public sealed override void SetLength(long value)
{
throw Error.GetSeekNotSupported();
}
public sealed override void SetLength(long value) => throw Error.GetSeekNotSupported();

public sealed override long Seek(long offset, SeekOrigin origin)
{
throw Error.GetSeekNotSupported();
}
public sealed override long Seek(long offset, SeekOrigin origin) => throw Error.GetSeekNotSupported();

protected void ValidateRead(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);

if (!_canRead) throw Error.GetReadNotSupported();
if (!_canRead)
{
throw Error.GetReadNotSupported();
}
}

protected void ValidateWrite(byte[] buffer, int offset, int count)
{
ValidateBufferArguments(buffer, offset, count);

if (!_canWrite) throw Error.GetWriteNotSupported();
if (!_canWrite)
{
throw Error.GetWriteNotSupported();
}
}
}
}
9 changes: 4 additions & 5 deletions src/libraries/System.Console/src/System/IO/StdInReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,9 @@ internal unsafe int ReadStdin(byte* buffer, int bufferSize)
return line;
}

public int ReadLine(byte[] buffer, int offset, int count)
public int ReadLine(Span<byte> buffer)
{
if (count == 0)
if (buffer.IsEmpty)
{
return 0;
}
Expand All @@ -114,11 +114,10 @@ public int ReadLine(byte[] buffer, int offset, int count)
Encoder encoder = _bufferReadEncoder ??= _encoding.GetEncoder();
int bytesUsedTotal = 0;
int charsUsedTotal = 0;
Span<byte> destination = buffer.AsSpan(offset, count);
foreach (ReadOnlyMemory<char> chunk in _readLineSB.GetChunks())
{
encoder.Convert(chunk.Span, destination, flush: false, out int charsUsed, out int bytesUsed, out bool completed);
destination = destination.Slice(bytesUsed);
encoder.Convert(chunk.Span, buffer, flush: false, out int charsUsed, out int bytesUsed, out bool completed);
buffer = buffer.Slice(bytesUsed);
bytesUsedTotal += bytesUsed;
charsUsedTotal += charsUsed;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public bool KeyAvailable
}
}

public int ReadLine(byte[] buffer, int offset, int count)
=> Inner.ReadLine(buffer, offset, count);
public int ReadLine(Span<byte> buffer) => Inner.ReadLine(buffer);
}
}
5 changes: 2 additions & 3 deletions src/libraries/System.Console/src/System/TermInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,9 @@ private static bool TryOpen(string filePath, [NotNullWhen(true)] out SafeFileHan
{
throw new InvalidOperationException(SR.IO_TermInfoInvalid);
}
int fileLen = (int)termInfoLength;

byte[] data = new byte[fileLen];
if (ConsolePal.Read(fd, data, 0, fileLen) != fileLen)
byte[] data = new byte[(int)termInfoLength];
if (ConsolePal.Read(fd, data) != data.Length)
{
throw new InvalidOperationException(SR.IO_TermInfoInvalid);
}
Expand Down