From 9a50bdcf3664109e27c1c5ad3c62e2fd2e6ec72a Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 8 Apr 2022 09:53:04 +0200 Subject: [PATCH 1/4] Add functional test --- ..._Emulator.Aot_System.IO.Stream.Test.csproj | 16 +++++++ .../AOT_System.IO.Stream/Program.cs | 48 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Android.Device_Emulator.Aot_System.IO.Stream.Test.csproj create mode 100644 src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Program.cs diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Android.Device_Emulator.Aot_System.IO.Stream.Test.csproj b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Android.Device_Emulator.Aot_System.IO.Stream.Test.csproj new file mode 100644 index 00000000000000..c8d2f37c34880d --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Android.Device_Emulator.Aot_System.IO.Stream.Test.csproj @@ -0,0 +1,16 @@ + + + Exe + true + false + true + $(NetCoreAppCurrent) + Android.Device_Emulator.Aot_System.IO.Stream.Test.dll + 42 + true + + + + + + diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Program.cs b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Program.cs new file mode 100644 index 00000000000000..29215aeb777147 --- /dev/null +++ b/src/tests/FunctionalTests/Android/Device_Emulator/AOT_System.IO.Stream/Program.cs @@ -0,0 +1,48 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + +using System; +using System.IO; + +// https://github.com/dotnet/runtime/issues/67402 + +public static class Program +{ + public static int Main(string[] args) + { + var stream = new DummyStream(); + var buffer = new byte[stream.Length]; + int read = stream.ReadAsync(buffer, 0, buffer.Length).GetAwaiter().GetResult(); + return read + buffer[0]; + } + + private sealed class DummyStream : System.IO.Stream + { + protected override void Dispose (bool disposing) => throw new NotImplementedException (); + + public override int Read (byte[] buffer, int offset, int count) + { + buffer[0] = 41; + return 1; + } + + public override long Seek (long offset, SeekOrigin origin) => 0; + public override void SetLength (long value) {} + public override void Write (byte[] buffer, int offset, int count) {} + public override void Flush () {} + + public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) + { + Console.WriteLine("BeginRead"); + return base.BeginRead(buffer, offset, count, callback, state); + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + + public override long Length => 1; + public override long Position { get; set; } = 0; + } +} From dfa7c01d96159c6d940a7ea46ee98218afad920c Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Fri, 8 Apr 2022 09:56:30 +0200 Subject: [PATCH 2/4] Fix vtable setup --- src/mono/mono/metadata/icall.c | 35 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index b1e2d737f2246e..3f91e363fbc132 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -3227,44 +3227,41 @@ init_io_stream_slots (void) io_stream_slots_set = TRUE; } -MonoBoolean -ves_icall_System_IO_Stream_HasOverriddenBeginEndRead (MonoObjectHandle stream, MonoError *error) + +static MonoBoolean +stream_has_overriden_begin_or_end_method (MonoObjectHandle stream, int begin_slot, int end_slot) { MonoClass* curr_klass = MONO_HANDLE_GET_CLASS (stream); MonoClass* base_klass = mono_class_try_get_stream_class (); - if (!io_stream_slots_set) - init_io_stream_slots (); - // slots can still be -1 and it means Linker removed the methods from the base class (Stream) // in this case we can safely assume the methods are not overridden // otherwise - check vtable + mono_class_setup_vtable (curr_klass); MonoMethod **curr_klass_vtable = m_class_get_vtable (curr_klass); - gboolean begin_read_is_overriden = io_stream_begin_read_slot != -1 && curr_klass_vtable [io_stream_begin_read_slot]->klass != base_klass; - gboolean end_read_is_overriden = io_stream_end_read_slot != -1 && curr_klass_vtable [io_stream_end_read_slot]->klass != base_klass; + gboolean begin_is_overriden = begin_slot != -1 && curr_klass_vtable [begin_slot]->klass != base_klass; + gboolean end_is_overriden = end_slot != -1 && curr_klass_vtable [end_slot]->klass != base_klass; + + return begin_is_overriden || end_is_overriden; +} +MonoBoolean +ves_icall_System_IO_Stream_HasOverriddenBeginEndRead (MonoObjectHandle stream, MonoError *error) +{ + if (!io_stream_slots_set) + init_io_stream_slots (); // return true if BeginRead or EndRead were overriden - return begin_read_is_overriden || end_read_is_overriden; + return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_read_slot, io_stream_end_read_slot); } MonoBoolean ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite (MonoObjectHandle stream, MonoError *error) { - MonoClass* curr_klass = MONO_HANDLE_GETVAL (stream, vtable)->klass; - MonoClass* base_klass = mono_class_try_get_stream_class (); - if (!io_stream_slots_set) init_io_stream_slots (); - // slots can still be -1 and it means Linker removed the methods from the base class (Stream) - // in this case we can safely assume the methods are not overridden - // otherwise - check vtable - MonoMethod **curr_klass_vtable = m_class_get_vtable (curr_klass); - gboolean begin_write_is_overriden = io_stream_begin_write_slot != -1 && curr_klass_vtable [io_stream_begin_write_slot]->klass != base_klass; - gboolean end_write_is_overriden = io_stream_end_write_slot != -1 && curr_klass_vtable [io_stream_end_write_slot]->klass != base_klass; - // return true if BeginWrite or EndWrite were overriden - return begin_write_is_overriden || end_write_is_overriden; + return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_write_slot, io_stream_end_write_slot); } MonoBoolean From e3a9dfd64ca88377d165f4e4b8e1020e9858cb1f Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 11 Apr 2022 16:51:28 +0200 Subject: [PATCH 3/4] Add suggested code changes --- src/mono/mono/metadata/icall.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 3f91e363fbc132..4f93e98bb3805f 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -3229,18 +3229,23 @@ init_io_stream_slots (void) static MonoBoolean -stream_has_overriden_begin_or_end_method (MonoObjectHandle stream, int begin_slot, int end_slot) +stream_has_overriden_begin_or_end_method (MonoObjectHandle stream, MonoError *error, int begin_slot, int end_slot) { MonoClass* curr_klass = MONO_HANDLE_GET_CLASS (stream); MonoClass* base_klass = mono_class_try_get_stream_class (); + mono_class_setup_vtable (curr_klass); + if (mono_class_has_failure (curr_klass)) { + mono_error_set_for_class_failure (error, curr_klass); + return_val_if_nok (error, FALSE); + } + // slots can still be -1 and it means Linker removed the methods from the base class (Stream) // in this case we can safely assume the methods are not overridden // otherwise - check vtable - mono_class_setup_vtable (curr_klass); MonoMethod **curr_klass_vtable = m_class_get_vtable (curr_klass); - gboolean begin_is_overriden = begin_slot != -1 && curr_klass_vtable [begin_slot]->klass != base_klass; - gboolean end_is_overriden = end_slot != -1 && curr_klass_vtable [end_slot]->klass != base_klass; + gboolean begin_is_overriden = begin_slot != -1 && curr_klass_vtable [begin_slot] != NULL && curr_klass_vtable [begin_slot]->klass != base_klass; + gboolean end_is_overriden = end_slot != -1 && curr_klass_vtable [end_slot] != NULL && curr_klass_vtable [end_slot]->klass != base_klass; return begin_is_overriden || end_is_overriden; } @@ -3250,8 +3255,9 @@ ves_icall_System_IO_Stream_HasOverriddenBeginEndRead (MonoObjectHandle stream, M { if (!io_stream_slots_set) init_io_stream_slots (); + // return true if BeginRead or EndRead were overriden - return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_read_slot, io_stream_end_read_slot); + return stream_has_overriden_begin_or_end_method (stream, error, io_stream_begin_read_slot, io_stream_end_read_slot); } MonoBoolean @@ -3261,7 +3267,7 @@ ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite (MonoObjectHandle stream, init_io_stream_slots (); // return true if BeginWrite or EndWrite were overriden - return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_write_slot, io_stream_end_write_slot); + return stream_has_overriden_begin_or_end_method (stream, error, io_stream_begin_write_slot, io_stream_end_write_slot); } MonoBoolean From 344110e89abc3ce055a8e3eb94f973ef38133764 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Mon, 11 Apr 2022 17:40:25 +0200 Subject: [PATCH 4/4] Improve arguments ordering --- src/mono/mono/metadata/icall.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index 4f93e98bb3805f..a671c641175072 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -3229,7 +3229,7 @@ init_io_stream_slots (void) static MonoBoolean -stream_has_overriden_begin_or_end_method (MonoObjectHandle stream, MonoError *error, int begin_slot, int end_slot) +stream_has_overriden_begin_or_end_method (MonoObjectHandle stream, int begin_slot, int end_slot, MonoError *error) { MonoClass* curr_klass = MONO_HANDLE_GET_CLASS (stream); MonoClass* base_klass = mono_class_try_get_stream_class (); @@ -3257,7 +3257,7 @@ ves_icall_System_IO_Stream_HasOverriddenBeginEndRead (MonoObjectHandle stream, M init_io_stream_slots (); // return true if BeginRead or EndRead were overriden - return stream_has_overriden_begin_or_end_method (stream, error, io_stream_begin_read_slot, io_stream_end_read_slot); + return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_read_slot, io_stream_end_read_slot, error); } MonoBoolean @@ -3267,7 +3267,7 @@ ves_icall_System_IO_Stream_HasOverriddenBeginEndWrite (MonoObjectHandle stream, init_io_stream_slots (); // return true if BeginWrite or EndWrite were overriden - return stream_has_overriden_begin_or_end_method (stream, error, io_stream_begin_write_slot, io_stream_end_write_slot); + return stream_has_overriden_begin_or_end_method (stream, io_stream_begin_write_slot, io_stream_end_write_slot, error); } MonoBoolean