Directory Roadmap
=================
+* `acceptance-tests/` - Optional third party test suites used to validate Mono against a wider range of test cases.
+
* `data/` - Configuration files installed as part of the Mono runtime.
* `docs/` - Technical documents about the Mono runtime.
{
"name": "ms-test-suite",
"url": "git@github.com:xamarin/ms-test-suite.git",
- "rev": "1ab0d4972937bf0451fc164f39a67475776a9edf",
+ "rev": "4a95604fdf2c0523e68eaad64a17d22eebb051b3",
"remote-branch": "origin/master",
"branch": "master",
"directory": "ms-test-suite"
check-ms-test-suite:
@if $(MAKE) validate-ms-test-suite RESET_VERSIONS=1; then \
- $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -t:library -warn:1 -r:nunit.framework"; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/conformance run NUNIT-CONSOLE="$(RUNTIME) $(CLASS)/nunit-console.exe -nologo -exclude=MonoBug,BadTest" NUNIT_XML_RESULT=$(abs_top_builddir)/acceptance-tests/TestResult-ms-test-suite-conformance.xml; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup build MCS="$(MCS) -debug -warn:1"; \
- $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup run MONO="$(RUNTIME)"; \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/conformance build MCS="$(MCS) -t:library -warn:1 -r:nunit.framework" && \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/conformance run NUNIT-CONSOLE="$(RUNTIME) $(CLASS)/nunit-console.exe -nologo -exclude=MonoBug,BadTest" NUNIT_XML_RESULT=$(abs_top_builddir)/acceptance-tests/TestResult-ms-test-suite-conformance.xml || EXIT_CODE=1; \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup build MCS="$(MCS) -debug -warn:1" && \
+ $(MAKE) -C $(MSTESTSUITE_PATH)/systemruntimebringup run MONO="$(RUNTIME)" || EXIT_CODE=1; \
+ exit $$EXIT_CODE; \
else \
echo "*** [ms-test-suite] Getting the repository failed, you probably don't have access to this Xamarin-internal resource. Skipping."; \
fi
\ No newline at end of file
cd $(ROSLYN_PATH); \
sed -i -e 'N; s/bootstrapArg=".*\n.*"/bootstrapArg=""/g' cibuild.sh; \
sed -i -e 's#-xml Binaries/\$$BUILD_CONFIGURATION/xUnitResults/#-nunit $(abs_top_builddir)/acceptance-tests/TestResult-#g' cibuild.sh; \
- ./cibuild.sh --mono-path $$PREFIX/bin; \
- sed -i -e 's/\\4.5"/\\4.5-api"/g' $$PREFIX/lib/mono/xbuild-frameworks/.NETFramework/v4.5/RedistList/FrameworkList.xml;
+ ./cibuild.sh --mono-path $$PREFIX/bin || EXIT_CODE=1; \
+ sed -i -e 's/\\4.5"/\\4.5-api"/g' $$PREFIX/lib/mono/xbuild-frameworks/.NETFramework/v4.5/RedistList/FrameworkList.xml; \
+ exit $$EXIT_CODE
fi
], [with_cooperative_gc=no])
-AC_ARG_WITH(checked_build, [ --with-checked-build=yes|no Enable checked build (expensive asserts)) (defaults to no)],[
- if test x$with_checked_build != xno ; then
- AC_DEFINE(CHECKED_BUILD,1,[Enable checked build.])
- fi
-], [with_checked_build=no])
+AC_ARG_ENABLE(checked_build, [ --enable-checked-build=LIST To enable checked build (expensive asserts), configure with a comma-separated LIST of checked build modules and then include that same list in the environment variable MONO_CHECK_MODE at runtime. Recognized checked build modules: all, gc, metadata, thread],[
-if test x$with_checked_build != xno ; then
- DISABLED_CHECKED_BUILD_TEST=none
+ if test x$enable_checked_build != x ; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD,1,[Enable checked build])
+ fi
+ for feature in `echo "$enable_checked_build" | sed -e "s/,/ /g"`; do
+ eval "mono_checked_build_test_enable_$feature='yes'"
+ done
- AC_ARG_ENABLE(checked_build_test, [ --enable-checked-build-test=LIST drop support for LIST checked build tests. LIST is a comma-separated list from: gc, metadata, thread.],
- [
- for feature in `echo "$enable_checked_build_test" | sed -e "s/,/ /g"`; do
- eval "mono_checked_build_test_disable_$feature='yes'"
- done
- DISABLED_CHECKED_BUILD_TEST=$enable_checked_build_test
- ],[])
+ if test "x$mono_checked_build_test_enable_all" = "xyes"; then
+ eval "mono_checked_build_test_enable_gc='yes'"
+ eval "mono_checked_build_test_enable_metadata='yes'"
+ eval "mono_checked_build_test_enable_thread='yes'"
+ fi
- if test "x$mono_checked_build_test_disable_gc" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_GC, 1, [Disable GC checked build])
+ if test "x$mono_checked_build_test_enable_gc" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_GC, 1, [Enable GC checked build])
fi
- if test "x$mono_checked_build_test_disable_metadata" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_METADATA, 1, [Disable metadata checked build])
+ if test "x$mono_checked_build_test_enable_metadata" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_METADATA, 1, [Enable metadata checked build])
fi
- if test "x$mono_checked_build_test_disable_thread" = "xyes"; then
- AC_DEFINE(DISABLE_CHECKED_BUILD_THREAD, 1, [Disable thread checked build])
+ if test "x$mono_checked_build_test_enable_thread" = "xyes"; then
+ AC_DEFINE(ENABLE_CHECKED_BUILD_THREAD, 1, [Enable thread checked build])
fi
-fi
+
+], [])
AC_CHECK_HEADER([malloc.h],
[AC_DEFINE([HAVE_USR_INCLUDE_MALLOC_H], [1],
-Subproject commit 35b7594b5498e9712522e0556ec290415691dddd
+Subproject commit df1c00441047e7cc439608aa1aa083f585f5ace0
this mode can be enabled at compile time by using the --with-cooperative-gc
flag when calling configure.
.TP
-\fBMONO_ENABLE_SHM\fR
-Unix only: Enable support for cross-process handles. Cross-process
-handles are used to expose process handles, thread handles, named
-mutexes, named events and named semaphores across Unix processes.
-.TP
\fBMONO_ENV_OPTIONS\fR
This environment variable allows you to pass command line arguments to
a Mono process through the environment. This is useful for example
Locale.cs \
MonoTODOAttribute.cs \
basic-profile-check.cs \
- SR.cs
+ SR.cs \
+ AssemblyRef.cs
DISTFILES = \
README.makefiles \
--- /dev/null
+static class AssemblyRef
+{
+ // FIXME
+ internal const string SystemConfiguration = "System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
+ internal const string System = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
+
+ public const string EcmaPublicKey = "b77a5c561934e089";
+#if NET_2_1
+ public const string FrameworkPublicKeyFull = "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9";
+ public const string FrameworkPublicKeyFull2 = "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB";
+#else
+ public const string FrameworkPublicKeyFull = "00000000000000000400000000000000";
+ public const string FrameworkPublicKeyFull2 = "00000000000000000400000000000000";
+#endif
+ public const string MicrosoftPublicKey = "b03f5f7f11d50a3a";
+
+ public const string MicrosoftJScript = Consts.AssemblyMicrosoft_JScript;
+ public const string MicrosoftVSDesigner = Consts.AssemblyMicrosoft_VSDesigner;
+ public const string SystemData = Consts.AssemblySystem_Data;
+ public const string SystemDesign = Consts.AssemblySystem_Design;
+ public const string SystemDrawing = Consts.AssemblySystem_Drawing;
+ public const string SystemWeb = Consts.AssemblySystem_Web;
+ public const string SystemWebExtensions = "System.Web.Extensions, Version=" + Consts.FxVersion + ", Culture=neutral, PublicKeyToken=31bf3856ad364e35";
+ public const string SystemWindowsForms = Consts.AssemblySystem_Windows_Forms;
+}
\ No newline at end of file
using System.Globalization;
-static class AssemblyRef
-{
- // FIXME
- internal const string SystemConfiguration = "System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
- internal const string System = "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35";
-
- public const string EcmaPublicKey = "b77a5c561934e089";
-#if NET_2_1
- public const string FrameworkPublicKeyFull = "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9";
- public const string FrameworkPublicKeyFull2 = "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB";
-#else
- public const string FrameworkPublicKeyFull = "00000000000000000400000000000000";
- public const string FrameworkPublicKeyFull2 = "00000000000000000400000000000000";
-#endif
- public const string MicrosoftPublicKey = "b03f5f7f11d50a3a";
-
- public const string MicrosoftJScript = Consts.AssemblyMicrosoft_JScript;
- public const string MicrosoftVSDesigner = Consts.AssemblyMicrosoft_VSDesigner;
- public const string SystemData = Consts.AssemblySystem_Data;
- public const string SystemDesign = Consts.AssemblySystem_Design;
- public const string SystemDrawing = Consts.AssemblySystem_Drawing;
- public const string SystemWeb = Consts.AssemblySystem_Web;
- public const string SystemWebExtensions = "System.Web.Extensions, Version=" + Consts.FxVersion + ", Culture=neutral, PublicKeyToken=31bf3856ad364e35";
- public const string SystemWindowsForms = Consts.AssemblySystem_Windows_Forms;
-}
-
static partial class SR
{
internal static string GetString(string name, params object[] args)
System.XML \
System Mono.Security \
Mono.Posix \
- System.Core
+ System.Core \
+ Mono.Cecil \
+ Mono.Cecil.Mdb
pcl_facade_dirs := Facades
public void Dispose ()
{
- WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
+ if (submissions.Count > 0)
+ WaitHandle.WaitAll (submissions.Select (s => s.WaitHandle).ToArray ());
BuildNodeManager.Stop ();
}
};
var requestData = new BuildRequestData (this, targets ?? DefaultTargets.ToArray ());
var result = manager.Build (parameters, requestData);
+ manager.Dispose ();
targetOutputs = result.ResultsByTarget;
return result.OverallResult == BuildResultCode.Success;
}
public BuildNodeManager (BuildManager buildManager)
{
BuildManager = buildManager;
- new Thread (RunLoop).Start ();
+ new Thread (RunLoop) {
+ IsBackground = true,
+ Name = "xbuild request handler"
+ }.Start ();
}
~BuildNodeManager ()
#
# Update this comment to trigger a build in System
-# +2
+# +3
#
*/
public virtual bool InvokeSystemCertificateValidator (
ICertificateValidator validator, string targetHost, bool serverMode,
- X509CertificateCollection certificates, X509Chain chain, out bool success,
+ X509CertificateCollection certificates, ref X509Chain chain, out bool success,
ref MonoSslPolicyErrors errors, ref int status11)
{
success = false;
[assembly: ComCompatibleVersion (1, 0, 3300, 0)]
[assembly: SecurityCritical (SecurityCriticalScope.Explicit)]
#endif
-[assembly: InternalsVisibleTo ("System.Runtime.Serialization, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull)]
[assembly: InternalsVisibleTo ("System.IdentityModel, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull)]
[assembly: InternalsVisibleTo ("System.IdentityModel.Selectors, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull)]
[assembly: InternalsVisibleTo ("System.ServiceModel, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull)]
Assembly/AssemblyInfo.cs
../../build/common/Consts.cs
../../build/common/SR.cs
+../../build/common/AssemblyRef.cs
EntityRes.cs
EntityResCategoryAttribute.cs
EntityResDescriptionAttribute.cs
../../build/common/Locale.cs
../../build/common/SR.cs
../../build/common/MonoTODOAttribute.cs
+../../build/common/AssemblyRef.cs
ReferenceSources/NativeOledbWrapper.cs
ReferenceSources/Res.cs
../../build/common/Locale.cs
../../build/common/SR.cs
../../build/common/MonoTODOAttribute.cs
+../../build/common/AssemblyRef.cs
ReferenceSources/NativeOledbWrapper.cs
ReferenceSources/Res.cs
LIBRARY = System.IO.Compression.FileSystem.dll
LIB_REFS = System System.IO.Compression
LIB_MCS_FLAGS =
-TEST_MCS_FLAGS = /r:System /r:System.Core /r:System.IO.Compression.dll
+TEST_MCS_FLAGS = /r:System.dll /r:System.Core.dll /r:System.IO.Compression.dll
include ../../build/library.make
LIBRARY = System.IO.Compression.dll
LIB_REFS = System System.Core
LIB_MCS_FLAGS = /unsafe
-TEST_MCS_FLAGS = /r:System /r:System.Core
+TEST_MCS_FLAGS = /r:System.dll /r:System.Core.dll
include ../../build/library.make
const int WaitTimeout = 5000;
- string port, TestHost, LocalServer;
+ string TestHost, LocalServer;
+ int port;
[SetUp]
public void SetupFixture ()
{
if (Environment.OSVersion.Platform == PlatformID.Win32NT) {
- port = "810";
+ port = 810;
} else {
- port = "8810";
+ port = 8810;
}
TestHost = "localhost:" + port;
var response = l.Response;
response.StatusCode = (int)HttpStatusCode.Moved;
- response.RedirectLocation = "http://xamarin.com/";
+ response.RedirectLocation = "http://localhost:8811/";
});
+ var listener2 = CreateListener (l => {
+ var response = l.Response;
+
+ response.StatusCode = (int)HttpStatusCode.OK;
+ response.OutputStream.WriteByte (0x68);
+ response.OutputStream.WriteByte (0x65);
+ response.OutputStream.WriteByte (0x6c);
+ response.OutputStream.WriteByte (0x6c);
+ response.OutputStream.WriteByte (0x6f);
+ }, 8811);
+
try {
var chandler = new HttpClientHandler ();
chandler.AllowAutoRedirect = true;
var r = client.GetAsync (LocalServer);
Assert.IsTrue (r.Wait (WaitTimeout), "#1");
var resp = r.Result;
- Assert.AreEqual ("http://xamarin.com/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
+ Assert.AreEqual ("http://localhost:8811/", resp.RequestMessage.RequestUri.AbsoluteUri, "#2");
+ Assert.AreEqual ("hello", resp.Content.ReadAsStringAsync ().Result, "#3");
} finally {
listener.Abort ();
listener.Close ();
+ listener2.Abort ();
+ listener2.Close ();
}
}
}
HttpListener CreateListener (Action<HttpListenerContext> contextAssert)
+ {
+ return CreateListener (contextAssert, port);
+ }
+
+ HttpListener CreateListener (Action<HttpListenerContext> contextAssert, int port)
{
var l = new HttpListener ();
l.Prefixes.Add (string.Format ("http://+:{0}/", port));
LIBRARY = System.Runtime.Remoting.dll
-LIB_REFS = System System.Web System.Xml System.Runtime.Serialization.Formatters.Soap
+LIB_REFS = System System.Xml System.Runtime.Serialization.Formatters.Soap
LIB_MCS_FLAGS = /r:$(corlib)
+ifndef NO_SYSTEM_WEB_DEPENDENCY
+LIB_REFS += System.Web
+endif
+
TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:618 /r:System.Runtime.Remoting.dll
TEST_MONO_PATH = .
--- /dev/null
+Assembly/AssemblyInfo.cs
+../../build/common/Consts.cs
+../../build/common/Locale.cs
+../../build/common/MonoTODOAttribute.cs
+System.Runtime.Remoting.Channels/BinaryClientFormatterSink.cs
+System.Runtime.Remoting.Channels/BinaryClientFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/BinaryCore.cs
+System.Runtime.Remoting.Channels/BinaryServerFormatterSink.cs
+System.Runtime.Remoting.Channels/BinaryServerFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/ChannelCore.cs
+System.Runtime.Remoting.Channels/CommonTransportKeys.cs
+System.Runtime.Remoting.Channels/IAuthorizeRemotingConnection.cs
+System.Runtime.Remoting.Channels/RemotingThreadPool.cs
+System.Runtime.Remoting.Channels/SoapClientFormatterSink.cs
+System.Runtime.Remoting.Channels/SoapCore.cs
+System.Runtime.Remoting.Channels/SoapServerFormatterSink.cs
+System.Runtime.Remoting.Channels/SoapClientFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/SoapServerFormatterSinkProvider.cs
+System.Runtime.Remoting.Channels/SoapMessageFormatter.cs
+System.Runtime.Remoting.Channels/SocketCachePolicy.cs
+System.Runtime.Remoting.Channels.Ipc/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcTransport.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcChannelHelper.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeClient.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeException.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeHelper.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeListener.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeSocket.cs
+System.Runtime.Remoting.Channels.Ipc.Win32/NamedPipeStream.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcClientChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/IpcServerChannel.cs
+System.Runtime.Remoting.Channels.Ipc.Unix/UnixChannelLoader.cs
+System.Runtime.Remoting.Channels.Tcp/TcpChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpMessageIO.cs
+System.Runtime.Remoting.Channels.Tcp/TcpServerChannel.cs
+System.Runtime.Remoting.Channels.Tcp/TcpServerTransportSink.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSinkProvider.cs
+System.Runtime.Remoting.Channels.Tcp/TcpClientTransportSink.cs
+System.Runtime.Remoting.Channels.Tcp/TcpConnectionPool.cs
+System.Runtime.Remoting.MetadataServices/MetaData.cs
+System.Runtime.Remoting.MetadataServices/MetaDataExporter.cs
+System.Runtime.Remoting.MetadataServices/MetaDataCodeGenerator.cs
+System.Runtime.Remoting.MetadataServices/SdlChannelSinkProvider.cs
+System.Runtime.Remoting.MetadataServices/ServiceType.cs
+System.Runtime.Remoting.MetadataServices/SUDSParserException.cs
+System.Runtime.Remoting.MetadataServices/SdlChannelSink.cs
+System.Runtime.Remoting.MetadataServices/SdlType.cs
+System.Runtime.Remoting.MetadataServices/SUDSGeneratorException.cs
+System.Runtime.Remoting.Services/RemotingClientProxy.cs
../../build/common/Consts.cs
../../build/common/SR.cs
+../../build/common/AssemblyRef.cs
EventLogEntryType.cs
InternalSR.cs
Assembly/AssemblyInfo.cs
../../build/common/Consts.cs
../../build/common/SR.cs
+../../build/common/AssemblyRef.cs
EventLogEntryType.cs
InternalSR.cs
MobileStubs.cs
#if NET_2_1
[assembly: InternalsVisibleTo ("System.ServiceModel.Web, PublicKey=00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB")]
- // System.Xml.Serialization (from Microsoft Silverlight 2.0 SDK) requires access to System.Xml internals
- [assembly: InternalsVisibleTo ("System.Xml.Serialization, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull)]
#else
[assembly: AllowPartiallyTrustedCallers]
#endif
- [assembly: InternalsVisibleTo ("System.Runtime.Serialization, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull, AllInternalsVisible = false)]
[assembly: InternalsVisibleTo ("System.Xml.Linq, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull, AllInternalsVisible = false)]
[assembly: AssemblyFileVersion (Consts.FxFileVersion)]
Assembly/AssemblyInfo.cs
../../build/common/Consts.cs
../../build/common/SR.cs
+../../build/common/AssemblyRef.cs
ReferenceSources/Res.cs
ReferenceSources/LocalAppContextSwitches.cs
ReferenceSources/ThisAssembly.cs
../../build/common/Consts.cs
../../build/common/MonoTODOAttribute.cs
../../build/common/SR.cs
+../../build/common/AssemblyRef.cs
ReferenceSources/Res.cs
ReferenceSources/LocalAppContextSwitches.cs
ReferenceSources/ThisAssembly.cs
if (provider != null && provider.HasCustomSystemCertificateValidator) {
var xerrors = (MonoSslPolicyErrors)errors;
var xchain = (XX509Chain)(object)chain;
- providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, xchain, out result, ref xerrors, ref status11);
+ providerValidated = provider.InvokeSystemCertificateValidator (this, host, server, certs, ref xchain, out result, ref xerrors, ref status11);
+ chain = (X509Chain)(object)xchain;
errors = (SslPolicyErrors)xerrors;
}
static bool CheckUsage (XX509CertificateCollection certs, string host, ref SslPolicyErrors errors, ref int status11)
{
#if !MONOTOUCH
- var leaf = (X509Certificate2)certs[0];
+ var leaf = certs[0] as X509Certificate2;
+ if (leaf == null)
+ leaf = new X509Certificate2 (certs[0]);
// for OSX and iOS we're using the native API to check for the SSL server policy and host names
if (!is_macosx) {
if (!CheckCertificateUsage (leaf)) {
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
[MonitoringDescription ("The session ID for this process.")]
public int SessionId {
- get { throw new NotImplementedException (); }
+ get { return 0; }
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
}
public bool IsLocal {
- get { return IPAddress.IsLoopback (RemoteEndPoint.Address); }
+ get { return LocalEndPoint.Address.Equals (RemoteEndPoint.Address); }
}
public bool IsSecureConnection {
X500DistinguishedNameFlags.UseT61Encoding | X500DistinguishedNameFlags.ForceUTF8Encoding;
private string name;
+ private byte[] canonEncoding;
public X500DistinguishedName (AsnEncodedData encodedDistinguishedName)
name = distinguishedName.name;
}
+ internal X500DistinguishedName (byte[] encoded, byte[] canonEncoding, string name)
+ : this (encoded)
+ {
+ this.canonEncoding = canonEncoding;
+ this.name = name;
+
+ Oid = new Oid ();
+ RawData = encoded;
+ }
+
+ internal byte[] CanonicalEncoding {
+ get { return canonEncoding; }
+ }
+
public string Name {
get { return name; }
if (name2 == null)
return false;
+ if (name1.canonEncoding != null && name2.canonEncoding != null) {
+ if (name1.canonEncoding.Length != name2.canonEncoding.Length)
+ return false;
+ for (int i = 0; i < name1.canonEncoding.Length; i++) {
+ if (name1.canonEncoding[i] != name2.canonEncoding[2])
+ return false;
+ }
+ return true;
+ }
+
X500DistinguishedNameFlags flags = X500DistinguishedNameFlags.UseNewLines | X500DistinguishedNameFlags.DoNotUseQuotes;
string[] split = new string[] { Environment.NewLine };
string[] parts1 = name1.Decode (flags).Split (split, StringSplitOptions.RemoveEmptyEntries);
using System.IO;
using System.Text;
+using System.Collections;
namespace System.Security.Cryptography.X509Certificates {
[Serializable]
public class X509Certificate2 : X509Certificate {
+
#if !SECURITY_DEP
// Used in Mono.Security HttpsClientStream
public X509Certificate2 (byte[] rawData)
}
#endif
#if SECURITY_DEP
- private bool _archived;
- private X509ExtensionCollection _extensions;
- private string _name = String.Empty;
- private string _serial;
- private PublicKey _publicKey;
- private X500DistinguishedName issuer_name;
- private X500DistinguishedName subject_name;
- private Oid signature_algorithm;
-
- private MX.X509Certificate _cert;
+ new internal X509Certificate2Impl Impl {
+ get {
+ var impl2 = base.Impl as X509Certificate2Impl;
+ X509Helper2.ThrowIfContextInvalid (impl2);
+ return impl2;
+ }
+ }
- private static string empty_error = Locale.GetText ("Certificate instance is empty.");
+ string friendlyName = string.Empty;
// constructors
public X509Certificate2 ()
{
- _cert = null;
}
public X509Certificate2 (byte[] rawData)
public X509Certificate2 (IntPtr handle) : base (handle)
{
- _cert = new MX.X509Certificate (base.GetRawCertData ());
+ throw new NotImplementedException ();
}
public X509Certificate2 (X509Certificate certificate)
- : base (certificate)
+ : base (X509Helper2.Import (certificate))
+ {
+ }
+
+ internal X509Certificate2 (X509Certificate2Impl impl)
+ : base (impl)
{
- _cert = new MX.X509Certificate (base.GetRawCertData ());
}
// properties
public bool Archived {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _archived;
- }
- set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- _archived = value;
- }
+ get { return Impl.Archived; }
+ set { Impl.Archived = true; }
}
public X509ExtensionCollection Extensions {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- if (_extensions == null)
- _extensions = new X509ExtensionCollection (_cert);
- return _extensions;
- }
+ get { return Impl.Extensions; }
}
public string FriendlyName {
get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _name;
+ ThrowIfContextInvalid ();
+ return friendlyName;
}
set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- _name = value;
+ ThrowIfContextInvalid ();
+ friendlyName = value;
}
}
- // FIXME - Could be more efficient
public bool HasPrivateKey {
- get { return PrivateKey != null; }
+ get { return Impl.HasPrivateKey; }
}
public X500DistinguishedName IssuerName {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- if (issuer_name == null)
- issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
- return issuer_name;
- }
+ get { return Impl.IssuerName; }
}
public DateTime NotAfter {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.ValidUntil.ToLocalTime ();
- }
+ get { return Impl.GetValidUntil ().ToLocalTime (); }
}
public DateTime NotBefore {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.ValidFrom.ToLocalTime ();
- }
+ get { return Impl.GetValidFrom ().ToLocalTime (); }
}
public AsymmetricAlgorithm PrivateKey {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- try {
- if (_cert.RSA != null) {
- RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
- if (rcsp != null)
- return rcsp.PublicOnly ? null : rcsp;
-
- RSAManaged rsam = _cert.RSA as RSAManaged;
- if (rsam != null)
- return rsam.PublicOnly ? null : rsam;
-
- _cert.RSA.ExportParameters (true);
- return _cert.RSA;
- } else if (_cert.DSA != null) {
- DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
- if (dcsp != null)
- return dcsp.PublicOnly ? null : dcsp;
-
- _cert.DSA.ExportParameters (true);
- return _cert.DSA;
- }
- }
- catch {
- }
- return null;
- }
- set {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- // allow NULL so we can "forget" the key associated to the certificate
- // e.g. in case we want to export it in another format (see bug #396620)
- if (value == null) {
- _cert.RSA = null;
- _cert.DSA = null;
- } else if (value is RSA)
- _cert.RSA = (RSA) value;
- else if (value is DSA)
- _cert.DSA = (DSA) value;
- else
- throw new NotSupportedException ();
- }
+ get { return Impl.PrivateKey; }
+ set { Impl.PrivateKey = value; }
}
public PublicKey PublicKey {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (_publicKey == null) {
- try {
- _publicKey = new PublicKey (_cert);
- }
- catch (Exception e) {
- string msg = Locale.GetText ("Unable to decode public key.");
- throw new CryptographicException (msg, e);
- }
- }
- return _publicKey;
- }
+ get { return Impl.PublicKey; }
}
public byte[] RawData {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- return base.GetRawCertData ();
- }
- }
+ get { return GetRawCertData (); }
+ }
public string SerialNumber {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (_serial == null) {
- StringBuilder sb = new StringBuilder ();
- byte[] serial = _cert.SerialNumber;
- for (int i=serial.Length - 1; i >= 0; i--)
- sb.Append (serial [i].ToString ("X2"));
- _serial = sb.ToString ();
- }
- return _serial;
- }
+ get { return GetSerialNumberString (); }
}
public Oid SignatureAlgorithm {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (signature_algorithm == null)
- signature_algorithm = new Oid (_cert.SignatureAlgorithm);
- return signature_algorithm;
- }
+ get { return Impl.SignatureAlgorithm; }
}
public X500DistinguishedName SubjectName {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- if (subject_name == null)
- subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
- return subject_name;
- }
+ get { return Impl.SubjectName; }
}
public string Thumbprint {
- get { return base.GetCertHashString (); }
+ get { return GetCertHashString (); }
}
public int Version {
- get {
- if (_cert == null)
- throw new CryptographicException (empty_error);
- return _cert.Version;
- }
+ get { return Impl.Version; }
}
// methods
[MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
public string GetNameInfo (X509NameType nameType, bool forIssuer)
{
- switch (nameType) {
- case X509NameType.SimpleName:
- if (_cert == null)
- throw new CryptographicException (empty_error);
- // return CN= or, if missing, the first part of the DN
- ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
- ASN1 dn = Find (commonName, sn);
- if (dn != null)
- return GetValueAsString (dn);
- if (sn.Count == 0)
- return String.Empty;
- ASN1 last_entry = sn [sn.Count - 1];
- if (last_entry.Count == 0)
- return String.Empty;
- return GetValueAsString (last_entry [0]);
- case X509NameType.EmailName:
- // return the E= part of the DN (if present)
- ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
- if (e != null)
- return GetValueAsString (e);
- return String.Empty;
- case X509NameType.UpnName:
- // FIXME - must find/create test case
- return String.Empty;
- case X509NameType.DnsName:
- // return the CN= part of the DN (if present)
- ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
- if (cn != null)
- return GetValueAsString (cn);
- return String.Empty;
- case X509NameType.DnsFromAlternativeName:
- // FIXME - must find/create test case
- return String.Empty;
- case X509NameType.UrlName:
- // FIXME - must find/create test case
- return String.Empty;
- default:
- throw new ArgumentException ("nameType");
- }
- }
-
- static byte[] commonName = { 0x55, 0x04, 0x03 };
- static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
-
- private ASN1 Find (byte[] oid, ASN1 dn)
- {
- if (dn.Count == 0)
- return null;
-
- // process SET
- for (int i = 0; i < dn.Count; i++) {
- ASN1 set = dn [i];
- for (int j = 0; j < set.Count; j++) {
- ASN1 pair = set [j];
- if (pair.Count != 2)
- continue;
-
- ASN1 poid = pair [0];
- if (poid == null)
- continue;
-
- if (poid.CompareValue (oid))
- return pair;
- }
- }
- return null;
- }
-
- private string GetValueAsString (ASN1 pair)
- {
- if (pair.Count != 2)
- return String.Empty;
-
- ASN1 value = pair [1];
- if ((value.Value == null) || (value.Length == 0))
- return String.Empty;
-
- if (value.Tag == 0x1E) {
- // BMPSTRING
- StringBuilder sb = new StringBuilder ();
- for (int j = 1; j < value.Value.Length; j += 2)
- sb.Append ((char)value.Value [j]);
- return sb.ToString ();
- } else {
- return Encoding.UTF8.GetString (value.Value);
- }
- }
-
- private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
- {
- MX.PKCS12 pfx = null;
- if (string.IsNullOrEmpty (password)) {
- try {
- // Support both unencrypted PKCS#12..
- pfx = new MX.PKCS12 (rawData, (string)null);
- } catch {
- // ..and PKCS#12 encrypted with an empty password
- pfx = new MX.PKCS12 (rawData, string.Empty);
- }
- } else {
- pfx = new MX.PKCS12 (rawData, password);
- }
-
- if (pfx.Certificates.Count == 0) {
- // no certificate was found
- return null;
- } else if (pfx.Keys.Count == 0) {
- // no key were found - pick the first certificate
- return pfx.Certificates [0];
- } else {
- // find the certificate that match the first key
- MX.X509Certificate cert = null;
- var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
- string pubkey = keypair.ToXmlString (false);
- foreach (var c in pfx.Certificates) {
- if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
- ((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
- cert = c;
- break;
- }
- }
- if (cert == null) {
- cert = pfx.Certificates [0]; // no match, pick first certificate without keys
- } else {
- cert.RSA = (keypair as RSA);
- cert.DSA = (keypair as DSA);
- }
- return cert;
- }
+ return Impl.GetNameInfo (nameType, forIssuer);
}
public override void Import (byte[] rawData)
[MonoTODO ("missing KeyStorageFlags support")]
public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
{
- MX.X509Certificate cert = null;
- if (password == null) {
- try {
- cert = new MX.X509Certificate (rawData);
- }
- catch (Exception e) {
- try {
- cert = ImportPkcs12 (rawData, null);
- }
- catch {
- string msg = Locale.GetText ("Unable to decode certificate.");
- // inner exception is the original (not second) exception
- throw new CryptographicException (msg, e);
- }
- }
- } else {
- // try PKCS#12
- try {
- cert = ImportPkcs12 (rawData, password);
- }
- catch {
- // it's possible to supply a (unrequired/unusued) password
- // fix bug #79028
- cert = new MX.X509Certificate (rawData);
- }
- }
- // we do not have to fully re-decode the certificate since X509Certificate does not deal with keys
- if (cert != null) {
- base.Import (cert.RawData, (string) null, keyStorageFlags);
- _cert = cert; // becuase base call will call Reset!
- }
+ var impl = X509Helper2.Import (rawData, password, keyStorageFlags);
+ ImportHandle (impl);
}
[MonoTODO ("SecureString is incomplete")]
[MonoTODO ("X509ContentType.SerializedCert is not supported")]
public override byte[] Export (X509ContentType contentType, string password)
{
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- switch (contentType) {
- case X509ContentType.Cert:
- return _cert.RawData;
- case X509ContentType.Pfx: // this includes Pkcs12
- return ExportPkcs12 (password);
- case X509ContentType.SerializedCert:
- // TODO
- throw new NotSupportedException ();
- default:
- string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
- throw new CryptographicException (msg);
- }
- }
-
- byte[] ExportPkcs12 (string password)
- {
- var pfx = new MX.PKCS12 ();
- try {
- if (password != null)
- pfx.Password = password;
- pfx.AddCertificate (_cert);
- var privateKey = PrivateKey;
- if (privateKey != null)
- pfx.AddPkcs8ShroudedKeyBag (privateKey);
- return pfx.GetBytes ();
- } finally {
- pfx.Password = null;
- }
+ return Impl.Export (contentType, password);
}
public override void Reset ()
{
- _cert = null;
- _archived = false;
- _extensions = null;
- _name = String.Empty;
- _serial = null;
- _publicKey = null;
- issuer_name = null;
- subject_name = null;
- signature_algorithm = null;
+ friendlyName = string.Empty;
base.Reset ();
}
public override string ToString ()
{
- if (_cert == null)
+ if (!IsValid)
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
-
return base.ToString (true);
}
public override string ToString (bool verbose)
{
- if (_cert == null)
+ if (!IsValid)
return "System.Security.Cryptography.X509Certificates.X509Certificate2";
// the non-verbose X509Certificate2 == verbose X509Certificate
[MonoTODO ("by default this depends on the incomplete X509Chain")]
public bool Verify ()
{
- if (_cert == null)
- throw new CryptographicException (empty_error);
-
- X509Chain chain = X509Chain.Create ();
- if (!chain.Build (this))
- return false;
- // TODO - check chain and other stuff ???
- return true;
+ return Impl.Verify (this);
}
// static methods
// internal stuff because X509Certificate2 isn't complete enough
// (maybe X509Certificate3 will be better?)
+ [Obsolete ("KILL")]
internal MX.X509Certificate MonoCertificate {
- get { return _cert; }
+ get {
+ var monoImpl = Impl as X509Certificate2ImplMono;
+ if (monoImpl == null)
+ throw new NotSupportedException ();
+ return monoImpl.MonoCertificate;
+ }
}
#else
--- /dev/null
+//
+// X509Certificate2Impl.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal abstract class X509Certificate2Impl : X509CertificateImpl
+ {
+#if SECURITY_DEP
+
+ public abstract bool Archived {
+ get; set;
+ }
+
+ public abstract X509ExtensionCollection Extensions {
+ get;
+ }
+
+ public abstract bool HasPrivateKey {
+ get;
+ }
+
+ public abstract X500DistinguishedName IssuerName {
+ get;
+ }
+
+ public abstract AsymmetricAlgorithm PrivateKey {
+ get; set;
+ }
+
+ public abstract PublicKey PublicKey {
+ get;
+ }
+
+ public abstract Oid SignatureAlgorithm {
+ get;
+ }
+
+ public abstract X500DistinguishedName SubjectName {
+ get;
+ }
+
+ public abstract int Version {
+ get;
+ }
+
+ public abstract string GetNameInfo (X509NameType nameType, bool forIssuer);
+
+ public abstract void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags);
+
+ public abstract byte[] Export (X509ContentType contentType, string password);
+
+ public abstract bool Verify (X509Certificate2 thisCertificate);
+
+ public abstract void Reset ();
+
+#endif
+ }
+}
--- /dev/null
+//
+// X509Certificate2ImplMono
+//
+// Authors:
+// Sebastien Pouliot <sebastien@xamarin.com>
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+// Copyright (C) 2015-2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if SECURITY_DEP
+
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+using MonoSecurity::Mono.Security;
+using MonoSecurity::Mono.Security.Cryptography;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using Mono.Security;
+using Mono.Security.Cryptography;
+using MX = Mono.Security.X509;
+#endif
+
+using System.IO;
+using System.Text;
+using System.Collections;
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal class X509Certificate2ImplMono : X509Certificate2Impl
+ {
+ bool _archived;
+ X509ExtensionCollection _extensions;
+ string _serial;
+ PublicKey _publicKey;
+ X500DistinguishedName issuer_name;
+ X500DistinguishedName subject_name;
+ Oid signature_algorithm;
+
+ MX.X509Certificate _cert;
+
+ static string empty_error = Locale.GetText ("Certificate instance is empty.");
+
+ public override bool IsValid {
+ get {
+ return _cert != null;
+ }
+ }
+
+ public override IntPtr Handle {
+ get { return IntPtr.Zero; }
+ }
+
+ internal X509Certificate2ImplMono (MX.X509Certificate cert)
+ {
+ this._cert = cert;
+ }
+
+ public override X509CertificateImpl Clone ()
+ {
+ ThrowIfContextInvalid ();
+ return new X509Certificate2ImplMono (_cert);
+ }
+
+ #region Implemented X509CertificateImpl members
+
+ public override string GetIssuerName (bool legacyV1Mode)
+ {
+ ThrowIfContextInvalid ();
+ if (legacyV1Mode)
+ return _cert.IssuerName;
+ else
+ return MX.X501.ToString (_cert.GetIssuerName (), true, ", ", true);
+ }
+
+ public override string GetSubjectName (bool legacyV1Mode)
+ {
+ ThrowIfContextInvalid ();
+ if (legacyV1Mode)
+ return _cert.SubjectName;
+ else
+ return MX.X501.ToString (_cert.GetSubjectName (), true, ", ", true);
+ }
+
+ public override byte[] GetRawCertData ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.RawData;
+ }
+
+ protected override byte[] GetCertHash (bool lazy)
+ {
+ ThrowIfContextInvalid ();
+ SHA1 sha = SHA1.Create ();
+ return sha.ComputeHash (_cert.RawData);
+ }
+
+ public override DateTime GetValidFrom ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.ValidFrom;
+ }
+
+ public override DateTime GetValidUntil ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.ValidUntil;
+ }
+
+ public override bool Equals (X509CertificateImpl other, out bool result)
+ {
+ // Use default implementation
+ result = false;
+ return false;
+ }
+
+ public override string GetKeyAlgorithm ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.KeyAlgorithm;
+ }
+
+ public override byte[] GetKeyAlgorithmParameters ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.KeyAlgorithmParameters;
+ }
+
+ public override byte[] GetPublicKey ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.PublicKey;
+ }
+
+ public override byte[] GetSerialNumber ()
+ {
+ ThrowIfContextInvalid ();
+ return _cert.SerialNumber;
+ }
+
+ public override byte[] Export (X509ContentType contentType, byte[] password)
+ {
+ ThrowIfContextInvalid ();
+
+ switch (contentType) {
+ case X509ContentType.Cert:
+ return GetRawCertData ();
+ case X509ContentType.Pfx: // this includes Pkcs12
+ // TODO
+ throw new NotSupportedException ();
+ case X509ContentType.SerializedCert:
+ // TODO
+ throw new NotSupportedException ();
+ default:
+ string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+ throw new CryptographicException (msg);
+ }
+ }
+
+ #endregion
+
+ // constructors
+
+ public X509Certificate2ImplMono ()
+ {
+ _cert = null;
+ }
+
+ // properties
+
+ public override bool Archived {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ return _archived;
+ }
+ set {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ _archived = value;
+ }
+ }
+
+ public override X509ExtensionCollection Extensions {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ if (_extensions == null)
+ _extensions = new X509ExtensionCollection (_cert);
+ return _extensions;
+ }
+ }
+
+ // FIXME - Could be more efficient
+ public override bool HasPrivateKey {
+ get { return PrivateKey != null; }
+ }
+
+ public override X500DistinguishedName IssuerName {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ if (issuer_name == null)
+ issuer_name = new X500DistinguishedName (_cert.GetIssuerName ().GetBytes ());
+ return issuer_name;
+ }
+ }
+
+ public override AsymmetricAlgorithm PrivateKey {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ try {
+ if (_cert.RSA != null) {
+ RSACryptoServiceProvider rcsp = _cert.RSA as RSACryptoServiceProvider;
+ if (rcsp != null)
+ return rcsp.PublicOnly ? null : rcsp;
+
+ RSAManaged rsam = _cert.RSA as RSAManaged;
+ if (rsam != null)
+ return rsam.PublicOnly ? null : rsam;
+
+ _cert.RSA.ExportParameters (true);
+ return _cert.RSA;
+ } else if (_cert.DSA != null) {
+ DSACryptoServiceProvider dcsp = _cert.DSA as DSACryptoServiceProvider;
+ if (dcsp != null)
+ return dcsp.PublicOnly ? null : dcsp;
+
+ _cert.DSA.ExportParameters (true);
+ return _cert.DSA;
+ }
+ }
+ catch {
+ }
+ return null;
+ }
+ set {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ // allow NULL so we can "forget" the key associated to the certificate
+ // e.g. in case we want to export it in another format (see bug #396620)
+ if (value == null) {
+ _cert.RSA = null;
+ _cert.DSA = null;
+ } else if (value is RSA)
+ _cert.RSA = (RSA) value;
+ else if (value is DSA)
+ _cert.DSA = (DSA) value;
+ else
+ throw new NotSupportedException ();
+ }
+ }
+
+ public override PublicKey PublicKey {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (_publicKey == null) {
+ try {
+ _publicKey = new PublicKey (_cert);
+ }
+ catch (Exception e) {
+ string msg = Locale.GetText ("Unable to decode public key.");
+ throw new CryptographicException (msg, e);
+ }
+ }
+ return _publicKey;
+ }
+ }
+
+ public override Oid SignatureAlgorithm {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (signature_algorithm == null)
+ signature_algorithm = new Oid (_cert.SignatureAlgorithm);
+ return signature_algorithm;
+ }
+ }
+
+ public override X500DistinguishedName SubjectName {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ if (subject_name == null)
+ subject_name = new X500DistinguishedName (_cert.GetSubjectName ().GetBytes ());
+ return subject_name;
+ }
+ }
+
+ public override int Version {
+ get {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ return _cert.Version;
+ }
+ }
+
+ // methods
+
+ [MonoTODO ("always return String.Empty for UpnName, DnsFromAlternativeName and UrlName")]
+ public override string GetNameInfo (X509NameType nameType, bool forIssuer)
+ {
+ switch (nameType) {
+ case X509NameType.SimpleName:
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+ // return CN= or, if missing, the first part of the DN
+ ASN1 sn = forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ();
+ ASN1 dn = Find (commonName, sn);
+ if (dn != null)
+ return GetValueAsString (dn);
+ if (sn.Count == 0)
+ return String.Empty;
+ ASN1 last_entry = sn [sn.Count - 1];
+ if (last_entry.Count == 0)
+ return String.Empty;
+ return GetValueAsString (last_entry [0]);
+ case X509NameType.EmailName:
+ // return the E= part of the DN (if present)
+ ASN1 e = Find (email, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
+ if (e != null)
+ return GetValueAsString (e);
+ return String.Empty;
+ case X509NameType.UpnName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ case X509NameType.DnsName:
+ // return the CN= part of the DN (if present)
+ ASN1 cn = Find (commonName, forIssuer ? _cert.GetIssuerName () : _cert.GetSubjectName ());
+ if (cn != null)
+ return GetValueAsString (cn);
+ return String.Empty;
+ case X509NameType.DnsFromAlternativeName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ case X509NameType.UrlName:
+ // FIXME - must find/create test case
+ return String.Empty;
+ default:
+ throw new ArgumentException ("nameType");
+ }
+ }
+
+ static byte[] commonName = { 0x55, 0x04, 0x03 };
+ static byte[] email = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 };
+
+ private ASN1 Find (byte[] oid, ASN1 dn)
+ {
+ if (dn.Count == 0)
+ return null;
+
+ // process SET
+ for (int i = 0; i < dn.Count; i++) {
+ ASN1 set = dn [i];
+ for (int j = 0; j < set.Count; j++) {
+ ASN1 pair = set [j];
+ if (pair.Count != 2)
+ continue;
+
+ ASN1 poid = pair [0];
+ if (poid == null)
+ continue;
+
+ if (poid.CompareValue (oid))
+ return pair;
+ }
+ }
+ return null;
+ }
+
+ private string GetValueAsString (ASN1 pair)
+ {
+ if (pair.Count != 2)
+ return String.Empty;
+
+ ASN1 value = pair [1];
+ if ((value.Value == null) || (value.Length == 0))
+ return String.Empty;
+
+ if (value.Tag == 0x1E) {
+ // BMPSTRING
+ StringBuilder sb = new StringBuilder ();
+ for (int j = 1; j < value.Value.Length; j += 2)
+ sb.Append ((char)value.Value [j]);
+ return sb.ToString ();
+ } else {
+ return Encoding.UTF8.GetString (value.Value);
+ }
+ }
+
+ private MX.X509Certificate ImportPkcs12 (byte[] rawData, string password)
+ {
+ MX.PKCS12 pfx = null;
+ if (string.IsNullOrEmpty (password)) {
+ try {
+ // Support both unencrypted PKCS#12..
+ pfx = new MX.PKCS12 (rawData, (string)null);
+ } catch {
+ // ..and PKCS#12 encrypted with an empty password
+ pfx = new MX.PKCS12 (rawData, string.Empty);
+ }
+ } else {
+ pfx = new MX.PKCS12 (rawData, password);
+ }
+
+ if (pfx.Certificates.Count == 0) {
+ // no certificate was found
+ return null;
+ } else if (pfx.Keys.Count == 0) {
+ // no key were found - pick the first certificate
+ return pfx.Certificates [0];
+ } else {
+ // find the certificate that match the first key
+ MX.X509Certificate cert = null;
+ var keypair = (pfx.Keys [0] as AsymmetricAlgorithm);
+ string pubkey = keypair.ToXmlString (false);
+ foreach (var c in pfx.Certificates) {
+ if (((c.RSA != null) && (pubkey == c.RSA.ToXmlString (false))) ||
+ ((c.DSA != null) && (pubkey == c.DSA.ToXmlString (false)))) {
+ cert = c;
+ break;
+ }
+ }
+ if (cert == null) {
+ cert = pfx.Certificates [0]; // no match, pick first certificate without keys
+ } else {
+ cert.RSA = (keypair as RSA);
+ cert.DSA = (keypair as DSA);
+ }
+ return cert;
+ }
+ }
+
+ [MonoTODO ("missing KeyStorageFlags support")]
+ public override void Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ MX.X509Certificate cert = null;
+ if (password == null) {
+ try {
+ cert = new MX.X509Certificate (rawData);
+ }
+ catch (Exception e) {
+ try {
+ cert = ImportPkcs12 (rawData, null);
+ }
+ catch {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ // inner exception is the original (not second) exception
+ throw new CryptographicException (msg, e);
+ }
+ }
+ } else {
+ // try PKCS#12
+ try {
+ cert = ImportPkcs12 (rawData, password);
+ }
+ catch {
+ // it's possible to supply a (unrequired/unusued) password
+ // fix bug #79028
+ cert = new MX.X509Certificate (rawData);
+ }
+ }
+ _cert = cert;
+ }
+
+ [MonoTODO ("X509ContentType.SerializedCert is not supported")]
+ public override byte[] Export (X509ContentType contentType, string password)
+ {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ switch (contentType) {
+ case X509ContentType.Cert:
+ return _cert.RawData;
+ case X509ContentType.Pfx: // this includes Pkcs12
+ return ExportPkcs12 (password);
+ case X509ContentType.SerializedCert:
+ // TODO
+ throw new NotSupportedException ();
+ default:
+ string msg = Locale.GetText ("This certificate format '{0}' cannot be exported.", contentType);
+ throw new CryptographicException (msg);
+ }
+ }
+
+ byte[] ExportPkcs12 (string password)
+ {
+ var pfx = new MX.PKCS12 ();
+ try {
+ var attrs = new Hashtable ();
+ var localKeyId = new ArrayList ();
+ localKeyId.Add (new byte[] { 1, 0, 0, 0 });
+ attrs.Add (MX.PKCS9.localKeyId, localKeyId);
+
+ if (password != null)
+ pfx.Password = password;
+ pfx.AddCertificate (_cert, attrs);
+ var privateKey = PrivateKey;
+ if (privateKey != null)
+ pfx.AddPkcs8ShroudedKeyBag (privateKey, attrs);
+ return pfx.GetBytes ();
+ } finally {
+ pfx.Password = null;
+ }
+ }
+
+ public override void Reset ()
+ {
+ _cert = null;
+ _archived = false;
+ _extensions = null;
+ _serial = null;
+ _publicKey = null;
+ issuer_name = null;
+ subject_name = null;
+ signature_algorithm = null;
+ }
+
+ public override string ToString ()
+ {
+ if (_cert == null)
+ return "System.Security.Cryptography.X509Certificates.X509Certificate2";
+
+ return ToString (true);
+ }
+
+ public override string ToString (bool verbose)
+ {
+ if (_cert == null)
+ return "System.Security.Cryptography.X509Certificates.X509Certificate2";
+
+ string nl = Environment.NewLine;
+ StringBuilder sb = new StringBuilder ();
+
+ // the non-verbose X509Certificate2 == verbose X509Certificate
+ if (!verbose) {
+ sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
+ sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
+ sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+ sb.Append (nl);
+ return sb.ToString ();
+ }
+
+ sb.AppendFormat ("[Version]{0} V{1}{0}{0}", nl, Version);
+ sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
+ sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
+ sb.AppendFormat ("[Serial Number]{0} {1}{0}{0}", nl, GetSerialNumber ());
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
+ sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
+ sb.AppendFormat ("[Signature Algorithm]{0} {1}({2}){0}{0}", nl, SignatureAlgorithm.FriendlyName,
+ SignatureAlgorithm.Value);
+
+ AsymmetricAlgorithm key = PublicKey.Key;
+ sb.AppendFormat ("[Public Key]{0} Algorithm: ", nl);
+ if (key is RSA)
+ sb.Append ("RSA");
+ else if (key is DSA)
+ sb.Append ("DSA");
+ else
+ sb.Append (key.ToString ());
+ sb.AppendFormat ("{0} Length: {1}{0} Key Blob: ", nl, key.KeySize);
+ AppendBuffer (sb, PublicKey.EncodedKeyValue.RawData);
+ sb.AppendFormat ("{0} Parameters: ", nl);
+ AppendBuffer (sb, PublicKey.EncodedParameters.RawData);
+ sb.Append (nl);
+
+ return sb.ToString ();
+ }
+
+ private static void AppendBuffer (StringBuilder sb, byte[] buffer)
+ {
+ if (buffer == null)
+ return;
+ for (int i=0; i < buffer.Length; i++) {
+ sb.Append (buffer [i].ToString ("x2"));
+ if (i < buffer.Length - 1)
+ sb.Append (" ");
+ }
+ }
+
+ [MonoTODO ("by default this depends on the incomplete X509Chain")]
+ public override bool Verify (X509Certificate2 thisCertificate)
+ {
+ if (_cert == null)
+ throw new CryptographicException (empty_error);
+
+ X509Chain chain = X509Chain.Create ();
+ if (!chain.Build (thisCertificate))
+ return false;
+ // TODO - check chain and other stuff ???
+ return true;
+ }
+
+ // static methods
+
+ private static byte[] signedData = new byte[] { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 };
+
+ [MonoTODO ("Detection limited to Cert, Pfx, Pkcs12, Pkcs7 and Unknown")]
+ public static X509ContentType GetCertContentType (byte[] rawData)
+ {
+ if ((rawData == null) || (rawData.Length == 0))
+ throw new ArgumentException ("rawData");
+
+ X509ContentType type = X509ContentType.Unknown;
+ try {
+ ASN1 data = new ASN1 (rawData);
+ if (data.Tag != 0x30) {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ throw new CryptographicException (msg);
+ }
+
+ if (data.Count == 0)
+ return type;
+
+ if (data.Count == 3) {
+ switch (data [0].Tag) {
+ case 0x30:
+ // SEQUENCE / SEQUENCE / BITSTRING
+ if ((data [1].Tag == 0x30) && (data [2].Tag == 0x03))
+ type = X509ContentType.Cert;
+ break;
+ case 0x02:
+ // INTEGER / SEQUENCE / SEQUENCE
+ if ((data [1].Tag == 0x30) && (data [2].Tag == 0x30))
+ type = X509ContentType.Pkcs12;
+ // note: Pfx == Pkcs12
+ break;
+ }
+ }
+ // check for PKCS#7 (count unknown but greater than 0)
+ // SEQUENCE / OID (signedData)
+ if ((data [0].Tag == 0x06) && data [0].CompareValue (signedData))
+ type = X509ContentType.Pkcs7;
+ }
+ catch (Exception e) {
+ string msg = Locale.GetText ("Unable to decode certificate.");
+ throw new CryptographicException (msg, e);
+ }
+
+ return type;
+ }
+
+ [MonoTODO ("Detection limited to Cert, Pfx, Pkcs12 and Unknown")]
+ public static X509ContentType GetCertContentType (string fileName)
+ {
+ if (fileName == null)
+ throw new ArgumentNullException ("fileName");
+ if (fileName.Length == 0)
+ throw new ArgumentException ("fileName");
+
+ byte[] data = File.ReadAllBytes (fileName);
+ return GetCertContentType (data);
+ }
+
+ // internal stuff because X509Certificate2 isn't complete enough
+ // (maybe X509Certificate3 will be better?)
+
+ internal MX.X509Certificate MonoCertificate {
+ get { return _cert; }
+ }
+ }
+}
+
+#endif
namespace System.Security.Cryptography.X509Certificates {
- public class X509Chain {
+ public class X509Chain : IDisposable {
- private StoreLocation location;
- private X509ChainElementCollection elements;
- private X509ChainPolicy policy;
- private X509ChainStatus[] status;
+ X509ChainImpl impl;
static X509ChainStatus[] Empty = new X509ChainStatus [0];
- // RFC3280 variables
- private int max_path_length;
- private X500DistinguishedName working_issuer_name;
-// private string working_public_key_algorithm;
- private AsymmetricAlgorithm working_public_key;
+ internal X509ChainImpl Impl {
+ get {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ return impl;
+ }
+ }
- // other flags
- private X509ChainElement bce_restriction;
+ internal bool IsValid {
+ get { return X509Helper2.IsValid (impl); }
+ }
+
+ internal void ThrowIfContextInvalid ()
+ {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ }
// constructors
public X509Chain (bool useMachineContext)
{
- location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
- elements = new X509ChainElementCollection ();
- policy = new X509ChainPolicy ();
+ impl = X509Helper2.CreateChainImpl (useMachineContext);
+ }
+
+ internal X509Chain (X509ChainImpl impl)
+ {
+ X509Helper2.ThrowIfContextInvalid (impl);
+ this.impl = impl;
}
[MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
[MonoTODO ("Mono's X509Chain is fully managed. Always returns IntPtr.Zero.")]
public IntPtr ChainContext {
- get { return IntPtr.Zero; }
+ get {
+ if (impl != null && impl.IsValid)
+ return impl.Handle;
+ return IntPtr.Zero;
+ }
}
public X509ChainElementCollection ChainElements {
- get { return elements; }
+ get { return Impl.ChainElements; }
}
public X509ChainPolicy ChainPolicy {
- get { return policy; }
- set { policy = value; }
+ get { return Impl.ChainPolicy; }
+ set { Impl.ChainPolicy = value; }
}
public X509ChainStatus[] ChainStatus {
- get {
- if (status == null)
- return Empty;
- return status;
- }
- }
+ get { return Impl.ChainStatus; }
+ }
// methods
[MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
public bool Build (X509Certificate2 certificate)
{
- if (certificate == null)
- throw new ArgumentException ("certificate");
-
- Reset ();
- X509ChainStatusFlags flag;
- try {
- flag = BuildChainFrom (certificate);
- ValidateChain (flag);
- }
- catch (CryptographicException ce) {
- throw new ArgumentException ("certificate", ce);
- }
-
- X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
- ArrayList list = new ArrayList ();
- // build "global" ChainStatus from the ChainStatus of every ChainElements
- foreach (X509ChainElement ce in elements) {
- foreach (X509ChainStatus cs in ce.ChainElementStatus) {
- // we MUST avoid duplicates in the "global" list
- if ((total & cs.Status) != cs.Status) {
- list.Add (cs);
- total |= cs.Status;
- }
- }
- }
- // and if required add some
- if (flag != X509ChainStatusFlags.NoError) {
- list.Insert (0, new X509ChainStatus (flag));
- }
- status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
-
- // (fast path) this ignore everything we have checked
- if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
- return true;
-
- bool result = true;
- // now check if exclude some verification for the "end result" (boolean)
- foreach (X509ChainStatus cs in status) {
- switch (cs.Status) {
- case X509ChainStatusFlags.UntrustedRoot:
- case X509ChainStatusFlags.PartialChain:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
- break;
- case X509ChainStatusFlags.NotTimeValid:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
- break;
- // FIXME - from here we needs new test cases for all cases
- case X509ChainStatusFlags.NotTimeNested:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
- break;
- case X509ChainStatusFlags.InvalidBasicConstraints:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
- break;
- case X509ChainStatusFlags.InvalidPolicyConstraints:
- case X509ChainStatusFlags.NoIssuanceChainPolicy:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
- break;
- case X509ChainStatusFlags.InvalidNameConstraints:
- case X509ChainStatusFlags.HasNotSupportedNameConstraint:
- case X509ChainStatusFlags.HasNotPermittedNameConstraint:
- case X509ChainStatusFlags.HasExcludedNameConstraint:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
- break;
- case X509ChainStatusFlags.InvalidExtension:
- // not sure ?!?
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
- break;
- //
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
- case X509ChainStatusFlags.CtlNotTimeValid:
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
- break;
- case X509ChainStatusFlags.CtlNotSignatureValid:
- // ?
- break;
- // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
- case X509ChainStatusFlags.CtlNotValidForUsage:
- // FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
- result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
- break;
- default:
- result = false;
- break;
- }
- // once we have one failure there's no need to check further
- if (!result)
- return false;
- }
-
- // every "problem" was excluded
- return true;
+ return Impl.Build (certificate);
}
public void Reset ()
{
- // note: this call doesn't Reset the X509ChainPolicy
- if ((status != null) && (status.Length != 0))
- status = null;
- if (elements.Count > 0)
- elements.Clear ();
- if (user_root_store != null) {
- user_root_store.Close ();
- user_root_store = null;
- }
- if (root_store != null) {
- root_store.Close ();
- root_store = null;
- }
- if (user_ca_store != null) {
- user_ca_store.Close ();
- user_ca_store = null;
- }
- if (ca_store != null) {
- ca_store.Close ();
- ca_store = null;
- }
- roots = null;
- cas = null;
- collection = null;
- bce_restriction = null;
- working_public_key = null;
+ Impl.Reset ();
}
// static methods
#endif
}
- // private stuff
-
- private X509Certificate2Collection roots;
- private X509Certificate2Collection cas;
- private X509Store root_store;
- private X509Store ca_store;
- private X509Store user_root_store;
- private X509Store user_ca_store;
-
- private X509Certificate2Collection Roots {
- get {
- if (roots == null) {
- X509Certificate2Collection c = new X509Certificate2Collection ();
- X509Store store = LMRootStore;
- if (location == StoreLocation.CurrentUser)
- c.AddRange (UserRootStore.Certificates);
- c.AddRange (store.Certificates);
- roots = c;
- }
- return roots;
- }
- }
-
- private X509Certificate2Collection CertificateAuthorities {
- get {
- if (cas == null) {
- X509Certificate2Collection c = new X509Certificate2Collection ();
- X509Store store = LMCAStore;
- if (location == StoreLocation.CurrentUser)
- c.AddRange (UserCAStore.Certificates);
- c.AddRange (store.Certificates);
- cas = c;
- }
- return cas;
- }
- }
-
- private X509Store LMRootStore {
- get {
- if (root_store == null) {
- root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
- try {
- root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return root_store;
- }
- }
-
- private X509Store UserRootStore {
- get {
- if (user_root_store == null) {
- user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
- try {
- user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return user_root_store;
- }
- }
-
- private X509Store LMCAStore {
- get {
- if (ca_store == null) {
- ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
- try {
- ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return ca_store;
- }
- }
-
- private X509Store UserCAStore {
- get {
- if (user_ca_store == null) {
- user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
- try {
- user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
- } catch {
- }
- }
- return user_ca_store;
- }
- }
- // *** certificate chain/path building stuff ***
-
- private X509Certificate2Collection collection;
-
- // we search local user (default) or machine certificate store
- // and in the extra certificate supplied in ChainPolicy.ExtraStore
- private X509Certificate2Collection CertificateCollection {
- get {
- if (collection == null) {
- collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
- collection.AddRange (Roots);
- collection.AddRange (CertificateAuthorities);
- }
- return collection;
- }
- }
-
- // This is a non-recursive chain/path building algorithm.
- //
- // At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
- // affect the path building (other errors are verification errors).
- //
- // Note that the order match the one we need to match MS and not the one defined in RFC3280,
- // we also include the trusted root certificate (trust anchor in RFC3280) in the list.
- // (this isn't an issue, just keep that in mind if you look at the source and the RFC)
- private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
- {
- elements.Add (certificate);
-
- while (!IsChainComplete (certificate)) {
- certificate = FindParent (certificate);
-
- if (certificate == null)
- return X509ChainStatusFlags.PartialChain;
-
- if (elements.Contains (certificate))
- return X509ChainStatusFlags.Cyclic;
-
- elements.Add (certificate);
- }
-
- // roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
- // trustiness (what a cute word) in the trusted root collection
- if (!Roots.Contains (certificate))
- elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
-
- return X509ChainStatusFlags.NoError;
- }
-
-
- private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
- {
- switch (c.Count) {
- case 0:
- return null;
- case 1:
- return c [0];
- default:
- // multiple candidate, keep only the ones that are still valid
- X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
- switch (time_valid.Count) {
- case 0:
- // that's too restrictive, let's revert and try another thing...
- time_valid = c;
- break;
- case 1:
- return time_valid [0];
- default:
- break;
- }
-
- // again multiple candidates, let's find the AKI that match the SKI (if we have one)
- string aki = GetAuthorityKeyIdentifier (child);
- if (String.IsNullOrEmpty (aki)) {
- return time_valid [0]; // FIXME: out of luck, you get the first one
- }
- foreach (X509Certificate2 parent in time_valid) {
- string ski = GetSubjectKeyIdentifier (parent);
- // if both id are available then they must match
- if (aki == ski)
- return parent;
- }
- return time_valid [0]; // FIXME: out of luck, you get the first one
- }
- }
-
- private X509Certificate2 FindParent (X509Certificate2 certificate)
- {
- X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
- string aki = GetAuthorityKeyIdentifier (certificate);
- if ((aki != null) && (aki.Length > 0)) {
- subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
- }
- X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
- // if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
- return certificate.Equals (parent) ? null : parent;
- }
-
- private bool IsChainComplete (X509Certificate2 certificate)
+ public void Dispose ()
{
- // the chain is complete if we have a self-signed certificate
- if (!IsSelfIssued (certificate))
- return false;
-
- // we're very limited to what we can do without certificate extensions
- if (certificate.Version < 3)
- return true;
-
- // check that Authority Key Identifier == Subject Key Identifier
- // e.g. it will be different if a self-signed certificate is part (not the end) of the chain
- string ski = GetSubjectKeyIdentifier (certificate);
- if (String.IsNullOrEmpty (ski))
- return true;
- string aki = GetAuthorityKeyIdentifier (certificate);
- if (String.IsNullOrEmpty (aki))
- return true;
- // if both id are available then they must match
- return (aki == ski);
+ Dispose (true);
+ GC.SuppressFinalize (this);
}
- // check for "self-issued" certificate - without verifying the signature
- // note that self-issued doesn't always mean it's a root certificate!
- private bool IsSelfIssued (X509Certificate2 certificate)
+ protected virtual void Dispose (bool disposing)
{
- return (certificate.Issuer == certificate.Subject);
- }
-
-
- // *** certificate chain/path validation stuff ***
-
- // Currently a subset of RFC3280 (hopefully a full implementation someday)
- private void ValidateChain (X509ChainStatusFlags flag)
- {
- // 'n' should be the root certificate...
- int n = elements.Count - 1;
- X509Certificate2 certificate = elements [n].Certificate;
-
- // ... and, if so, must be treated outside the chain...
- if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
- Process (n);
- // deal with the case where the chain == the root certificate
- // (which isn't for RFC3280) part of the chain
- if (n == 0) {
- elements [0].UncompressFlags ();
- return;
- }
- // skip the root certificate when processing the chain (in 6.1.3)
- n--;
- }
- // ... unless the chain is a partial one (then we start with that one)
-
- // 6.1.1 - Inputs
- // 6.1.1.a - a prospective certificate path of length n (i.e. elements)
- // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
- // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
- // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
- // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
- // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
- // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
-
- // 6.1.2 - Initialization (incomplete)
- // 6.1.2.a-f - policy stuff, some TODO, some not supported
- // 6.1.2.g - working public key algorithm
-// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
- // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
- working_public_key = certificate.PublicKey.Key;
- // 6.1.2.j - working issuer name
- working_issuer_name = certificate.IssuerName;
- // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
- // may be reduced to the value in the path length constraint field
- max_path_length = n;
-
- // 6.1.3 - Basic Certificate Processing
- // note: loop looks reversed (the list is) but we process this part just like RFC3280 does
- for (int i = n; i > 0; i--) {
- Process (i);
- // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
- PrepareForNextCertificate (i);
+ if (impl != null) {
+ impl.Dispose ();
+ impl = null;
}
- Process (0);
-
- // 6.1.3.a.3 - revocation checks
- CheckRevocationOnChain (flag);
-
- // 6.1.5 - Wrap-up procedure
- WrapUp ();
}
- private void Process (int n)
+ ~X509Chain ()
{
- X509ChainElement element = elements [n];
- X509Certificate2 certificate = element.Certificate;
-
- // pre-step: DSA certificates may inherit the parameters of their CA
- if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
- if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
- X509Certificate2 parent = elements [n+1].Certificate;
- certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
- }
- }
-
- bool root = (working_public_key == null);
- // 6.1.3.a.1 - check signature (with special case to deal with root certificates)
- if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
- // another special case where only an end-entity is available and can't be verified.
- // In this case we do not report an invalid signature (since this is unknown)
- if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
- element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
- }
- }
-
- // 6.1.3.a.2 - check validity period
- if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
- (ChainPolicy.VerificationTime > certificate.NotAfter)) {
- element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
- }
- // TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
-
- // note: most of them don't apply to the root certificate
- if (root) {
- return;
- }
-
- // 6.1.3.a.3 - revocation check (we're doing at the last stage)
- // note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
-
- // 6.1.3.a.4 - check certificate issuer name
- if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
- // NOTE: this is not the "right" error flag, but it's the closest one defined
- element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
- }
-
- if (!IsSelfIssued (certificate) && (n != 0)) {
- // TODO 6.1.3.b - subject name in the permitted_subtrees ...
- // TODO 6.1.3.c - subject name not within excluded_subtrees...
-
- // TODO - check for X509ChainStatusFlags.InvalidNameConstraint
- // TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
- // TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
- // TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
- }
-
- // TODO 6.1.3.d - check if certificate policies extension is present
- //if (false) {
- // TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
- // using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
-
- // TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
-
- //} else {
- // TODO 6.1.3.e - set valid_policy_tree to NULL
- //}
-
- // TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
- }
-
- // CTL == Certificate Trust List / NOT SUPPORTED
- // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
- // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
- // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
-
- private void PrepareForNextCertificate (int n)
- {
- X509ChainElement element = elements [n];
- X509Certificate2 certificate = element.Certificate;
-
- // TODO 6.1.4.a-b
-
- // 6.1.4.c
- working_issuer_name = certificate.SubjectName;
- // 6.1.4.d-e - our key includes both the public key and it's parameters
- working_public_key = certificate.PublicKey.Key;
- // 6.1.4.f
-// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
-
- // TODO 6.1.4.g-j
-
- // 6.1.4.k - Verify that the certificate is a CA certificate
- X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
- if (bce != null) {
- if (!bce.CertificateAuthority) {
- element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
- } else if (certificate.Version >= 3) {
- // recent (v3+) CA certificates must include BCE
- element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
-
- // 6.1.4.l - if the certificate isn't self-issued...
- if (!IsSelfIssued (certificate)) {
- // ... verify that max_path_length > 0
- if (max_path_length > 0) {
- max_path_length--;
- } else {
- // to match MS the reported status must be against the certificate
- // with the BCE and not where the path is too long. It also means
- // that this condition has to be reported only once
- if (bce_restriction != null) {
- bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
- }
- }
- }
-
- // 6.1.4.m - if pathLengthConstraint is present...
- if ((bce != null) && (bce.HasPathLengthConstraint)) {
- // ... and is less that max_path_length, set max_path_length to it's value
- if (bce.PathLengthConstraint < max_path_length) {
- max_path_length = bce.PathLengthConstraint;
- bce_restriction = element;
- }
- }
-
- // 6.1.4.n - if key usage extension is present...
- X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
- if (kue != null) {
- // ... verify keyCertSign is set
- X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
- if ((kue.KeyUsages & success) != success)
- element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
- }
-
- // 6.1.4.o - recognize and process other critical extension present in the certificate
- ProcessCertificateExtensions (element);
- }
-
- private void WrapUp ()
- {
- X509ChainElement element = elements [0];
- X509Certificate2 certificate = element.Certificate;
-
- // 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
- if (IsSelfIssued (certificate)) {
- // TODO... decrement explicit_policy by 1
- }
-
- // 6.1.5.b - TODO
-
- // 6.1.5.c,d,e - not required by the X509Chain implementation
-
- // 6.1.5.f - recognize and process other critical extension present in the certificate
- ProcessCertificateExtensions (element);
-
- // 6.1.5.g - TODO
-
- // uncompressed the flags into several elements
- for (int i = elements.Count - 1; i >= 0; i--) {
- elements [i].UncompressFlags ();
- }
- }
-
- private void ProcessCertificateExtensions (X509ChainElement element)
- {
- foreach (X509Extension ext in element.Certificate.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid.Value) {
- case "2.5.29.15": // X509KeyUsageExtension
- case "2.5.29.19": // X509BasicConstraintsExtension
- // we processed this extension
- break;
- default:
- // note: Under Windows XP MS implementation seems to ignore
- // certificate with unknown critical extensions.
- element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
- break;
- }
- }
- }
- }
-
- private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
- {
- if (pubkey == null)
- return false;
- // Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
- MX.X509Certificate mx = signed.MonoCertificate;
- return (mx.VerifySignature (pubkey));
- }
-
- private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
- {
- X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
- return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
- }
-
- // System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
- static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
- {
- return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
- }
-
- // but anyway System.dll v2 doesn't expose CRL in any way so...
- static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
- {
- return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
- }
-
- static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
- {
- if (ext == null)
- return String.Empty;
- MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
- byte[] id = aki.Identifier;
- if (id == null)
- return String.Empty;
- StringBuilder sb = new StringBuilder ();
- foreach (byte b in id)
- sb.Append (b.ToString ("X02"));
- return sb.ToString ();
- }
-
- // we check the revocation only once we have built the complete chain
- private void CheckRevocationOnChain (X509ChainStatusFlags flag)
- {
- bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
- bool online;
-
- switch (ChainPolicy.RevocationMode) {
- case X509RevocationMode.Online:
- // default
- online = true;
- break;
- case X509RevocationMode.Offline:
- online = false;
- break;
- case X509RevocationMode.NoCheck:
- return;
- default:
- throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
- }
-
- bool unknown = partial;
- // from the root down to the end-entity
- for (int i = elements.Count - 1; i >= 0; i--) {
- bool check = true;
-
- switch (ChainPolicy.RevocationFlag) {
- case X509RevocationFlag.EndCertificateOnly:
- check = (i == 0);
- break;
- case X509RevocationFlag.EntireChain:
- check = true;
- break;
- case X509RevocationFlag.ExcludeRoot:
- // default
- check = (i != (elements.Count - 1));
- // anyway, who's gonna sign that the root is invalid ?
- break;
- }
-
- X509ChainElement element = elements [i];
-
- // we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
- if (!unknown)
- unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
-
- if (unknown) {
- // we can skip the revocation checks as we can't be sure of them anyway
- element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
- element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
- } else if (check && !partial && !IsSelfIssued (element.Certificate)) {
- // check for revocation (except for the trusted root and self-issued certs)
- element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
- // if revoked, then all others following in the chain are unknown...
- unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
- }
- }
- }
-
- // This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
- private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
- {
- X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
- X509ChainElement element = elements [ca];
- X509Certificate2 ca_cert = element.Certificate;
-
- // find the CRL from the "right" CA
- while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
- // try with this self-issued
- result = CheckRevocation (certificate, ca_cert, online);
- if (result != X509ChainStatusFlags.RevocationStatusUnknown)
- break;
- ca++;
- element = elements [ca];
- ca_cert = element.Certificate;
- }
- if (result == X509ChainStatusFlags.RevocationStatusUnknown)
- result = CheckRevocation (certificate, ca_cert, online);
- return result;
- }
-
- private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
- {
- // change this if/when we support OCSP
- X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
- if (kue != null) {
- // ... verify CrlSign is set
- X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
- if ((kue.KeyUsages & success) != success) {
- // FIXME - we should try to find an alternative CA that has the CrlSign bit
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
- }
-
- MX.X509Crl crl = FindCrl (ca_cert);
-
- if ((crl == null) && online) {
- // FIXME - download and install new CRL
- // then you get a second chance
- // crl = FindCrl (ca_cert, ref valid, ref out_of_date);
-
- // We need to get the subjectAltName and an URI from there (or use OCSP)
- // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
- }
-
- if (crl != null) {
- // validate the digital signature on the CRL using the CA public key
- // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
- // checks and we loose the "why" of the failure
- // note #2: we do this before other tests as an invalid signature could be a hacked CRL
- // (so anything within can't be trusted)
- if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
-
- MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
- if (entry != null) {
- // We have an entry for this CRL that includes an unknown CRITICAL extension
- // See [X.509 7.3] NOTE 4
- if (!ProcessCrlEntryExtensions (entry))
- return X509ChainStatusFlags.Revoked;
-
- // FIXME - a little more is involved
- if (entry.RevocationDate <= ChainPolicy.VerificationTime)
- return X509ChainStatusFlags.Revoked;
- }
-
- // are we overdue for a CRL update ? if so we can't be sure of any certificate status
- if (crl.NextUpdate < ChainPolicy.VerificationTime)
- return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
-
- // we have a CRL that includes an unknown CRITICAL extension
- // we put this check at the end so we do not "hide" any Revoked flags
- if (!ProcessCrlExtensions (crl)) {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
- } else {
- return X509ChainStatusFlags.RevocationStatusUnknown;
- }
-
- return X509ChainStatusFlags.NoError;
- }
-
- static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
- {
- if (store == null)
- return null;
-
- var crls = store.Crls;
- foreach (MX.X509Crl crl in crls) {
- if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
- return crl;
- }
- return null; // No CRL found
- }
-
- private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
- {
- string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
- string ski = GetSubjectKeyIdentifier (caCertificate);
-
- // consider that the LocalMachine directories could not exists... and cannot be created by the user
- MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
- if (result != null)
- return result;
- if (location == StoreLocation.CurrentUser) {
- result = CheckCrls (subject, ski, UserCAStore.Store);
- if (result != null)
- return result;
- }
-
- // consider that the LocalMachine directories could not exists... and cannot be created by the user
- result = CheckCrls (subject, ski, LMRootStore.Store);
- if (result != null)
- return result;
- if (location == StoreLocation.CurrentUser) {
- result = CheckCrls (subject, ski, UserRootStore.Store);
- if (result != null)
- return result;
- }
- return null;
- }
-
- private bool ProcessCrlExtensions (MX.X509Crl crl)
- {
- foreach (MX.X509Extension ext in crl.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid) {
- case "2.5.29.20": // cRLNumber
- case "2.5.29.35": // authorityKeyIdentifier
- // we processed/know about this extension
- break;
- default:
- return false;
- }
- }
- }
- return true;
- }
-
- private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
- {
- foreach (MX.X509Extension ext in entry.Extensions) {
- if (ext.Critical) {
- switch (ext.Oid) {
- case "2.5.29.21": // cRLReason
- // we processed/know about this extension
- break;
- default:
- return false;
- }
- }
- }
- return true;
+ Dispose (false);
}
}
}
--- /dev/null
+//
+// X509ChainImpl.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if SECURITY_DEP
+
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal abstract class X509ChainImpl : IDisposable
+ {
+ public abstract bool IsValid {
+ get;
+ }
+
+ public abstract IntPtr Handle {
+ get;
+ }
+
+ protected void ThrowIfContextInvalid ()
+ {
+ if (!IsValid)
+ throw X509Helper2.GetInvalidChainContextException ();
+ }
+
+ public abstract X509ChainElementCollection ChainElements {
+ get;
+ }
+
+ public abstract X509ChainPolicy ChainPolicy {
+ get; set;
+ }
+
+ public abstract X509ChainStatus[] ChainStatus {
+ get;
+ }
+
+ public abstract bool Build (X509Certificate2 certificate);
+
+ public abstract void Reset ();
+
+ public void Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ }
+
+ ~X509ChainImpl ()
+ {
+ Dispose (false);
+ }
+ }
+}
+
+#endif
--- /dev/null
+//
+// System.Security.Cryptography.X509Certificates.X509ChainImplMono
+//
+// Author:
+// Sebastien Pouliot <sebastien@ximian.com>
+//
+// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
+// Copyright (C) 2004-2006 Novell Inc. (http://www.novell.com)
+// Copyright (C) 2011 Xamarin Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+#if SECURITY_DEP
+
+#if MONO_SECURITY_ALIAS
+extern alias MonoSecurity;
+using MX = MonoSecurity::Mono.Security.X509;
+#else
+using MX = Mono.Security.X509;
+#endif
+
+using System.Collections;
+using System.Text;
+
+namespace System.Security.Cryptography.X509Certificates {
+
+ internal class X509ChainImplMono : X509ChainImpl
+ {
+ private StoreLocation location;
+ private X509ChainElementCollection elements;
+ private X509ChainPolicy policy;
+ private X509ChainStatus[] status;
+
+ static X509ChainStatus[] Empty = new X509ChainStatus [0];
+
+ // RFC3280 variables
+ private int max_path_length;
+ private X500DistinguishedName working_issuer_name;
+// private string working_public_key_algorithm;
+ private AsymmetricAlgorithm working_public_key;
+
+ // other flags
+ private X509ChainElement bce_restriction;
+
+ // constructors
+
+ public X509ChainImplMono ()
+ : this (false)
+ {
+ }
+
+ public X509ChainImplMono (bool useMachineContext)
+ {
+ location = useMachineContext ? StoreLocation.LocalMachine : StoreLocation.CurrentUser;
+ elements = new X509ChainElementCollection ();
+ policy = new X509ChainPolicy ();
+ }
+
+ [MonoTODO ("Mono's X509Chain is fully managed. All handles are invalid.")]
+ public X509ChainImplMono (IntPtr chainContext)
+ {
+ // CryptoAPI compatibility (unmanaged handle)
+ throw new NotSupportedException ();
+ }
+
+ public override bool IsValid {
+ get { return true; }
+ }
+
+ public override IntPtr Handle {
+ get { return IntPtr.Zero; }
+ }
+
+ // properties
+
+ public override X509ChainElementCollection ChainElements {
+ get { return elements; }
+ }
+
+ public override X509ChainPolicy ChainPolicy {
+ get { return policy; }
+ set { policy = value; }
+ }
+
+ public override X509ChainStatus[] ChainStatus {
+ get {
+ if (status == null)
+ return Empty;
+ return status;
+ }
+ }
+
+ // methods
+
+ [MonoTODO ("Not totally RFC3280 compliant, but neither is MS implementation...")]
+ public override bool Build (X509Certificate2 certificate)
+ {
+ if (certificate == null)
+ throw new ArgumentException ("certificate");
+
+ Reset ();
+ X509ChainStatusFlags flag;
+ try {
+ flag = BuildChainFrom (certificate);
+ ValidateChain (flag);
+ }
+ catch (CryptographicException ce) {
+ throw new ArgumentException ("certificate", ce);
+ }
+
+ X509ChainStatusFlags total = X509ChainStatusFlags.NoError;
+ ArrayList list = new ArrayList ();
+ // build "global" ChainStatus from the ChainStatus of every ChainElements
+ foreach (X509ChainElement ce in elements) {
+ foreach (X509ChainStatus cs in ce.ChainElementStatus) {
+ // we MUST avoid duplicates in the "global" list
+ if ((total & cs.Status) != cs.Status) {
+ list.Add (cs);
+ total |= cs.Status;
+ }
+ }
+ }
+ // and if required add some
+ if (flag != X509ChainStatusFlags.NoError) {
+ list.Insert (0, new X509ChainStatus (flag));
+ }
+ status = (X509ChainStatus[]) list.ToArray (typeof (X509ChainStatus));
+
+ // (fast path) this ignore everything we have checked
+ if ((status.Length == 0) || (ChainPolicy.VerificationFlags == X509VerificationFlags.AllFlags))
+ return true;
+
+ bool result = true;
+ // now check if exclude some verification for the "end result" (boolean)
+ foreach (X509ChainStatus cs in status) {
+ switch (cs.Status) {
+ case X509ChainStatusFlags.UntrustedRoot:
+ case X509ChainStatusFlags.PartialChain:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.AllowUnknownCertificateAuthority) != 0);
+ break;
+ case X509ChainStatusFlags.NotTimeValid:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeValid) != 0);
+ break;
+ // FIXME - from here we needs new test cases for all cases
+ case X509ChainStatusFlags.NotTimeNested:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreNotTimeNested) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidBasicConstraints:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidBasicConstraints) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidPolicyConstraints:
+ case X509ChainStatusFlags.NoIssuanceChainPolicy:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidPolicy) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidNameConstraints:
+ case X509ChainStatusFlags.HasNotSupportedNameConstraint:
+ case X509ChainStatusFlags.HasNotPermittedNameConstraint:
+ case X509ChainStatusFlags.HasExcludedNameConstraint:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreInvalidName) != 0);
+ break;
+ case X509ChainStatusFlags.InvalidExtension:
+ // not sure ?!?
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
+ break;
+ //
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreRootRevocationUnknown) != 0)
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreEndRevocationUnknown) != 0)
+ case X509ChainStatusFlags.CtlNotTimeValid:
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlNotTimeValid) != 0);
+ break;
+ case X509ChainStatusFlags.CtlNotSignatureValid:
+ // ?
+ break;
+ // ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreCtlSignerRevocationUnknown) != 0);
+ case X509ChainStatusFlags.CtlNotValidForUsage:
+ // FIXME - does IgnoreWrongUsage apply to CTL (it doesn't have Ctl in it's name like the others)
+ result &= ((ChainPolicy.VerificationFlags & X509VerificationFlags.IgnoreWrongUsage) != 0);
+ break;
+ default:
+ result = false;
+ break;
+ }
+ // once we have one failure there's no need to check further
+ if (!result)
+ return false;
+ }
+
+ // every "problem" was excluded
+ return true;
+ }
+
+ public override void Reset ()
+ {
+ // note: this call doesn't Reset the X509ChainPolicy
+ if ((status != null) && (status.Length != 0))
+ status = null;
+ if (elements.Count > 0)
+ elements.Clear ();
+ if (user_root_store != null) {
+ user_root_store.Close ();
+ user_root_store = null;
+ }
+ if (root_store != null) {
+ root_store.Close ();
+ root_store = null;
+ }
+ if (user_ca_store != null) {
+ user_ca_store.Close ();
+ user_ca_store = null;
+ }
+ if (ca_store != null) {
+ ca_store.Close ();
+ ca_store = null;
+ }
+ roots = null;
+ cas = null;
+ collection = null;
+ bce_restriction = null;
+ working_public_key = null;
+ }
+
+ // private stuff
+
+ private X509Certificate2Collection roots;
+ private X509Certificate2Collection cas;
+ private X509Store root_store;
+ private X509Store ca_store;
+ private X509Store user_root_store;
+ private X509Store user_ca_store;
+
+ private X509Certificate2Collection Roots {
+ get {
+ if (roots == null) {
+ X509Certificate2Collection c = new X509Certificate2Collection ();
+ X509Store store = LMRootStore;
+ if (location == StoreLocation.CurrentUser)
+ c.AddRange (UserRootStore.Certificates);
+ c.AddRange (store.Certificates);
+ roots = c;
+ }
+ return roots;
+ }
+ }
+
+ private X509Certificate2Collection CertificateAuthorities {
+ get {
+ if (cas == null) {
+ X509Certificate2Collection c = new X509Certificate2Collection ();
+ X509Store store = LMCAStore;
+ if (location == StoreLocation.CurrentUser)
+ c.AddRange (UserCAStore.Certificates);
+ c.AddRange (store.Certificates);
+ cas = c;
+ }
+ return cas;
+ }
+ }
+
+ private X509Store LMRootStore {
+ get {
+ if (root_store == null) {
+ root_store = new X509Store (StoreName.Root, StoreLocation.LocalMachine);
+ try {
+ root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return root_store;
+ }
+ }
+
+ private X509Store UserRootStore {
+ get {
+ if (user_root_store == null) {
+ user_root_store = new X509Store (StoreName.Root, StoreLocation.CurrentUser);
+ try {
+ user_root_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return user_root_store;
+ }
+ }
+
+ private X509Store LMCAStore {
+ get {
+ if (ca_store == null) {
+ ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.LocalMachine);
+ try {
+ ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return ca_store;
+ }
+ }
+
+ private X509Store UserCAStore {
+ get {
+ if (user_ca_store == null) {
+ user_ca_store = new X509Store (StoreName.CertificateAuthority, StoreLocation.CurrentUser);
+ try {
+ user_ca_store.Open (OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
+ } catch {
+ }
+ }
+ return user_ca_store;
+ }
+ }
+ // *** certificate chain/path building stuff ***
+
+ private X509Certificate2Collection collection;
+
+ // we search local user (default) or machine certificate store
+ // and in the extra certificate supplied in ChainPolicy.ExtraStore
+ private X509Certificate2Collection CertificateCollection {
+ get {
+ if (collection == null) {
+ collection = new X509Certificate2Collection (ChainPolicy.ExtraStore);
+ collection.AddRange (Roots);
+ collection.AddRange (CertificateAuthorities);
+ }
+ return collection;
+ }
+ }
+
+ // This is a non-recursive chain/path building algorithm.
+ //
+ // At this stage we only checks for PartialChain, Cyclic and UntrustedRoot errors are they
+ // affect the path building (other errors are verification errors).
+ //
+ // Note that the order match the one we need to match MS and not the one defined in RFC3280,
+ // we also include the trusted root certificate (trust anchor in RFC3280) in the list.
+ // (this isn't an issue, just keep that in mind if you look at the source and the RFC)
+ private X509ChainStatusFlags BuildChainFrom (X509Certificate2 certificate)
+ {
+ elements.Add (certificate);
+
+ while (!IsChainComplete (certificate)) {
+ certificate = FindParent (certificate);
+
+ if (certificate == null)
+ return X509ChainStatusFlags.PartialChain;
+
+ if (elements.Contains (certificate))
+ return X509ChainStatusFlags.Cyclic;
+
+ elements.Add (certificate);
+ }
+
+ // roots may be supplied (e.g. in the ExtraStore) so we need to confirm their
+ // trustiness (what a cute word) in the trusted root collection
+ if (!Roots.Contains (certificate))
+ elements [elements.Count - 1].StatusFlags |= X509ChainStatusFlags.UntrustedRoot;
+
+ return X509ChainStatusFlags.NoError;
+ }
+
+
+ private X509Certificate2 SelectBestFromCollection (X509Certificate2 child, X509Certificate2Collection c)
+ {
+ switch (c.Count) {
+ case 0:
+ return null;
+ case 1:
+ return c [0];
+ default:
+ // multiple candidate, keep only the ones that are still valid
+ X509Certificate2Collection time_valid = c.Find (X509FindType.FindByTimeValid, ChainPolicy.VerificationTime, false);
+ switch (time_valid.Count) {
+ case 0:
+ // that's too restrictive, let's revert and try another thing...
+ time_valid = c;
+ break;
+ case 1:
+ return time_valid [0];
+ default:
+ break;
+ }
+
+ // again multiple candidates, let's find the AKI that match the SKI (if we have one)
+ string aki = GetAuthorityKeyIdentifier (child);
+ if (String.IsNullOrEmpty (aki)) {
+ return time_valid [0]; // FIXME: out of luck, you get the first one
+ }
+ foreach (X509Certificate2 parent in time_valid) {
+ string ski = GetSubjectKeyIdentifier (parent);
+ // if both id are available then they must match
+ if (aki == ski)
+ return parent;
+ }
+ return time_valid [0]; // FIXME: out of luck, you get the first one
+ }
+ }
+
+ private X509Certificate2 FindParent (X509Certificate2 certificate)
+ {
+ X509Certificate2Collection subset = CertificateCollection.Find (X509FindType.FindBySubjectDistinguishedName, certificate.Issuer, false);
+ string aki = GetAuthorityKeyIdentifier (certificate);
+ if ((aki != null) && (aki.Length > 0)) {
+ subset.AddRange (CertificateCollection.Find (X509FindType.FindBySubjectKeyIdentifier, aki, false));
+ }
+ X509Certificate2 parent = SelectBestFromCollection (certificate, subset);
+ // if parent==certificate we're looping but it's not (probably) a bug and not a true cyclic (over n certs)
+ return certificate.Equals (parent) ? null : parent;
+ }
+
+ private bool IsChainComplete (X509Certificate2 certificate)
+ {
+ // the chain is complete if we have a self-signed certificate
+ if (!IsSelfIssued (certificate))
+ return false;
+
+ // we're very limited to what we can do without certificate extensions
+ if (certificate.Version < 3)
+ return true;
+
+ // check that Authority Key Identifier == Subject Key Identifier
+ // e.g. it will be different if a self-signed certificate is part (not the end) of the chain
+ string ski = GetSubjectKeyIdentifier (certificate);
+ if (String.IsNullOrEmpty (ski))
+ return true;
+ string aki = GetAuthorityKeyIdentifier (certificate);
+ if (String.IsNullOrEmpty (aki))
+ return true;
+ // if both id are available then they must match
+ return (aki == ski);
+ }
+
+ // check for "self-issued" certificate - without verifying the signature
+ // note that self-issued doesn't always mean it's a root certificate!
+ private bool IsSelfIssued (X509Certificate2 certificate)
+ {
+ return (certificate.Issuer == certificate.Subject);
+ }
+
+
+ // *** certificate chain/path validation stuff ***
+
+ // Currently a subset of RFC3280 (hopefully a full implementation someday)
+ private void ValidateChain (X509ChainStatusFlags flag)
+ {
+ // 'n' should be the root certificate...
+ int n = elements.Count - 1;
+ X509Certificate2 certificate = elements [n].Certificate;
+
+ // ... and, if so, must be treated outside the chain...
+ if (((flag & X509ChainStatusFlags.PartialChain) == 0)) {
+ Process (n);
+ // deal with the case where the chain == the root certificate
+ // (which isn't for RFC3280) part of the chain
+ if (n == 0) {
+ elements [0].UncompressFlags ();
+ return;
+ }
+ // skip the root certificate when processing the chain (in 6.1.3)
+ n--;
+ }
+ // ... unless the chain is a partial one (then we start with that one)
+
+ // 6.1.1 - Inputs
+ // 6.1.1.a - a prospective certificate path of length n (i.e. elements)
+ // 6.1.1.b - the current date/time (i.e. ChainPolicy.VerificationTime)
+ // 6.1.1.c - user-initial-policy-set (i.e. ChainPolicy.CertificatePolicy)
+ // 6.1.1.d - the trust anchor information (i.e. certificate, unless it's a partial chain)
+ // 6.1.1.e - initial-policy-mapping-inhibit (NOT SUPPORTED BY THE API)
+ // 6.1.1.f - initial-explicit-policy (NOT SUPPORTED BY THE API)
+ // 6.1.1.g - initial-any-policy-inhibit (NOT SUPPORTED BY THE API)
+
+ // 6.1.2 - Initialization (incomplete)
+ // 6.1.2.a-f - policy stuff, some TODO, some not supported
+ // 6.1.2.g - working public key algorithm
+// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
+ // 6.1.2.h-i - our key contains both the "working public key" and "working public key parameters" data
+ working_public_key = certificate.PublicKey.Key;
+ // 6.1.2.j - working issuer name
+ working_issuer_name = certificate.IssuerName;
+ // 6.1.2.k - this integer is initialized to n, is decremented for each non-self-issued, certificate and
+ // may be reduced to the value in the path length constraint field
+ max_path_length = n;
+
+ // 6.1.3 - Basic Certificate Processing
+ // note: loop looks reversed (the list is) but we process this part just like RFC3280 does
+ for (int i = n; i > 0; i--) {
+ Process (i);
+ // 6.1.4 - preparation for certificate i+1 (for not with i+1, or i-1 in our loop)
+ PrepareForNextCertificate (i);
+ }
+ Process (0);
+
+ // 6.1.3.a.3 - revocation checks
+ CheckRevocationOnChain (flag);
+
+ // 6.1.5 - Wrap-up procedure
+ WrapUp ();
+ }
+
+ private void Process (int n)
+ {
+ X509ChainElement element = elements [n];
+ X509Certificate2 certificate = element.Certificate;
+
+ // pre-step: DSA certificates may inherit the parameters of their CA
+ if ((n != elements.Count - 1) && (certificate.MonoCertificate.KeyAlgorithm == "1.2.840.10040.4.1")) {
+ if (certificate.MonoCertificate.KeyAlgorithmParameters == null) {
+ X509Certificate2 parent = elements [n+1].Certificate;
+ certificate.MonoCertificate.KeyAlgorithmParameters = parent.MonoCertificate.KeyAlgorithmParameters;
+ }
+ }
+
+ bool root = (working_public_key == null);
+ // 6.1.3.a.1 - check signature (with special case to deal with root certificates)
+ if (!IsSignedWith (certificate, root ? certificate.PublicKey.Key : working_public_key)) {
+ // another special case where only an end-entity is available and can't be verified.
+ // In this case we do not report an invalid signature (since this is unknown)
+ if (root || (n != elements.Count - 1) || IsSelfIssued (certificate)) {
+ element.StatusFlags |= X509ChainStatusFlags.NotSignatureValid;
+ }
+ }
+
+ // 6.1.3.a.2 - check validity period
+ if ((ChainPolicy.VerificationTime < certificate.NotBefore) ||
+ (ChainPolicy.VerificationTime > certificate.NotAfter)) {
+ element.StatusFlags |= X509ChainStatusFlags.NotTimeValid;
+ }
+ // TODO - for X509ChainStatusFlags.NotTimeNested (needs global structure)
+
+ // note: most of them don't apply to the root certificate
+ if (root) {
+ return;
+ }
+
+ // 6.1.3.a.3 - revocation check (we're doing at the last stage)
+ // note: you revoke a trusted root by removing it from your trusted store (i.e. no CRL can do this job)
+
+ // 6.1.3.a.4 - check certificate issuer name
+ if (!X500DistinguishedName.AreEqual (certificate.IssuerName, working_issuer_name)) {
+ // NOTE: this is not the "right" error flag, but it's the closest one defined
+ element.StatusFlags |= X509ChainStatusFlags.InvalidNameConstraints;
+ }
+
+ if (!IsSelfIssued (certificate) && (n != 0)) {
+ // TODO 6.1.3.b - subject name in the permitted_subtrees ...
+ // TODO 6.1.3.c - subject name not within excluded_subtrees...
+
+ // TODO - check for X509ChainStatusFlags.InvalidNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasNotSupportedNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasNotPermittedNameConstraint
+ // TODO - check for X509ChainStatusFlags.HasExcludedNameConstraint
+ }
+
+ // TODO 6.1.3.d - check if certificate policies extension is present
+ //if (false) {
+ // TODO - for X509ChainStatusFlags.InvalidPolicyConstraints
+ // using X509ChainPolicy.ApplicationPolicy and X509ChainPolicy.CertificatePolicy
+
+ // TODO - check for X509ChainStatusFlags.NoIssuanceChainPolicy
+
+ //} else {
+ // TODO 6.1.3.e - set valid_policy_tree to NULL
+ //}
+
+ // TODO 6.1.3.f - verify explict_policy > 0 if valid_policy_tree != NULL
+ }
+
+ // CTL == Certificate Trust List / NOT SUPPORTED
+ // TODO - check for X509ChainStatusFlags.CtlNotTimeValid
+ // TODO - check for X509ChainStatusFlags.CtlNotSignatureValid
+ // TODO - check for X509ChainStatusFlags.CtlNotValidForUsage
+
+ private void PrepareForNextCertificate (int n)
+ {
+ X509ChainElement element = elements [n];
+ X509Certificate2 certificate = element.Certificate;
+
+ // TODO 6.1.4.a-b
+
+ // 6.1.4.c
+ working_issuer_name = certificate.SubjectName;
+ // 6.1.4.d-e - our key includes both the public key and it's parameters
+ working_public_key = certificate.PublicKey.Key;
+ // 6.1.4.f
+// working_public_key_algorithm = certificate.PublicKey.Oid.Value;
+
+ // TODO 6.1.4.g-j
+
+ // 6.1.4.k - Verify that the certificate is a CA certificate
+ X509BasicConstraintsExtension bce = (certificate.Extensions["2.5.29.19"] as X509BasicConstraintsExtension);
+ if (bce != null) {
+ if (!bce.CertificateAuthority) {
+ element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+ } else if (certificate.Version >= 3) {
+ // recent (v3+) CA certificates must include BCE
+ element.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+
+ // 6.1.4.l - if the certificate isn't self-issued...
+ if (!IsSelfIssued (certificate)) {
+ // ... verify that max_path_length > 0
+ if (max_path_length > 0) {
+ max_path_length--;
+ } else {
+ // to match MS the reported status must be against the certificate
+ // with the BCE and not where the path is too long. It also means
+ // that this condition has to be reported only once
+ if (bce_restriction != null) {
+ bce_restriction.StatusFlags |= X509ChainStatusFlags.InvalidBasicConstraints;
+ }
+ }
+ }
+
+ // 6.1.4.m - if pathLengthConstraint is present...
+ if ((bce != null) && (bce.HasPathLengthConstraint)) {
+ // ... and is less that max_path_length, set max_path_length to it's value
+ if (bce.PathLengthConstraint < max_path_length) {
+ max_path_length = bce.PathLengthConstraint;
+ bce_restriction = element;
+ }
+ }
+
+ // 6.1.4.n - if key usage extension is present...
+ X509KeyUsageExtension kue = (certificate.Extensions["2.5.29.15"] as X509KeyUsageExtension);
+ if (kue != null) {
+ // ... verify keyCertSign is set
+ X509KeyUsageFlags success = X509KeyUsageFlags.KeyCertSign;
+ if ((kue.KeyUsages & success) != success)
+ element.StatusFlags |= X509ChainStatusFlags.NotValidForUsage;
+ }
+
+ // 6.1.4.o - recognize and process other critical extension present in the certificate
+ ProcessCertificateExtensions (element);
+ }
+
+ private void WrapUp ()
+ {
+ X509ChainElement element = elements [0];
+ X509Certificate2 certificate = element.Certificate;
+
+ // 6.1.5.a - TODO if certificate n (our 0) wasn't self issued and explicit_policy != 0
+ if (IsSelfIssued (certificate)) {
+ // TODO... decrement explicit_policy by 1
+ }
+
+ // 6.1.5.b - TODO
+
+ // 6.1.5.c,d,e - not required by the X509Chain implementation
+
+ // 6.1.5.f - recognize and process other critical extension present in the certificate
+ ProcessCertificateExtensions (element);
+
+ // 6.1.5.g - TODO
+
+ // uncompressed the flags into several elements
+ for (int i = elements.Count - 1; i >= 0; i--) {
+ elements [i].UncompressFlags ();
+ }
+ }
+
+ private void ProcessCertificateExtensions (X509ChainElement element)
+ {
+ foreach (X509Extension ext in element.Certificate.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid.Value) {
+ case "2.5.29.15": // X509KeyUsageExtension
+ case "2.5.29.19": // X509BasicConstraintsExtension
+ // we processed this extension
+ break;
+ default:
+ // note: Under Windows XP MS implementation seems to ignore
+ // certificate with unknown critical extensions.
+ element.StatusFlags |= X509ChainStatusFlags.InvalidExtension;
+ break;
+ }
+ }
+ }
+ }
+
+ private bool IsSignedWith (X509Certificate2 signed, AsymmetricAlgorithm pubkey)
+ {
+ if (pubkey == null)
+ return false;
+ // Sadly X509Certificate2 doesn't expose the signature nor the tbs (to be signed) structure
+ MX.X509Certificate mx = signed.MonoCertificate;
+ return (mx.VerifySignature (pubkey));
+ }
+
+ private string GetSubjectKeyIdentifier (X509Certificate2 certificate)
+ {
+ X509SubjectKeyIdentifierExtension ski = (certificate.Extensions["2.5.29.14"] as X509SubjectKeyIdentifierExtension);
+ return (ski == null) ? String.Empty : ski.SubjectKeyIdentifier;
+ }
+
+ // System.dll v2 doesn't have a class to deal with the AuthorityKeyIdentifier extension
+ static string GetAuthorityKeyIdentifier (X509Certificate2 certificate)
+ {
+ return GetAuthorityKeyIdentifier (certificate.MonoCertificate.Extensions ["2.5.29.35"]);
+ }
+
+ // but anyway System.dll v2 doesn't expose CRL in any way so...
+ static string GetAuthorityKeyIdentifier (MX.X509Crl crl)
+ {
+ return GetAuthorityKeyIdentifier (crl.Extensions ["2.5.29.35"]);
+ }
+
+ static string GetAuthorityKeyIdentifier (MX.X509Extension ext)
+ {
+ if (ext == null)
+ return String.Empty;
+ MX.Extensions.AuthorityKeyIdentifierExtension aki = new MX.Extensions.AuthorityKeyIdentifierExtension (ext);
+ byte[] id = aki.Identifier;
+ if (id == null)
+ return String.Empty;
+ StringBuilder sb = new StringBuilder ();
+ foreach (byte b in id)
+ sb.Append (b.ToString ("X02"));
+ return sb.ToString ();
+ }
+
+ // we check the revocation only once we have built the complete chain
+ private void CheckRevocationOnChain (X509ChainStatusFlags flag)
+ {
+ bool partial = ((flag & X509ChainStatusFlags.PartialChain) != 0);
+ bool online;
+
+ switch (ChainPolicy.RevocationMode) {
+ case X509RevocationMode.Online:
+ // default
+ online = true;
+ break;
+ case X509RevocationMode.Offline:
+ online = false;
+ break;
+ case X509RevocationMode.NoCheck:
+ return;
+ default:
+ throw new InvalidOperationException (Locale.GetText ("Invalid revocation mode."));
+ }
+
+ bool unknown = partial;
+ // from the root down to the end-entity
+ for (int i = elements.Count - 1; i >= 0; i--) {
+ bool check = true;
+
+ switch (ChainPolicy.RevocationFlag) {
+ case X509RevocationFlag.EndCertificateOnly:
+ check = (i == 0);
+ break;
+ case X509RevocationFlag.EntireChain:
+ check = true;
+ break;
+ case X509RevocationFlag.ExcludeRoot:
+ // default
+ check = (i != (elements.Count - 1));
+ // anyway, who's gonna sign that the root is invalid ?
+ break;
+ }
+
+ X509ChainElement element = elements [i];
+
+ // we can't assume the revocation status if the certificate is bad (e.g. invalid signature)
+ if (!unknown)
+ unknown |= ((element.StatusFlags & X509ChainStatusFlags.NotSignatureValid) != 0);
+
+ if (unknown) {
+ // we can skip the revocation checks as we can't be sure of them anyway
+ element.StatusFlags |= X509ChainStatusFlags.RevocationStatusUnknown;
+ element.StatusFlags |= X509ChainStatusFlags.OfflineRevocation;
+ } else if (check && !partial && !IsSelfIssued (element.Certificate)) {
+ // check for revocation (except for the trusted root and self-issued certs)
+ element.StatusFlags |= CheckRevocation (element.Certificate, i+1, online);
+ // if revoked, then all others following in the chain are unknown...
+ unknown |= ((element.StatusFlags & X509ChainStatusFlags.Revoked) != 0);
+ }
+ }
+ }
+
+ // This isn't how RFC3280 (section 6.3) deals with CRL, but then we don't (yet) support DP, deltas...
+ private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, int ca, bool online)
+ {
+ X509ChainStatusFlags result = X509ChainStatusFlags.RevocationStatusUnknown;
+ X509ChainElement element = elements [ca];
+ X509Certificate2 ca_cert = element.Certificate;
+
+ // find the CRL from the "right" CA
+ while (IsSelfIssued (ca_cert) && (ca < elements.Count - 1)) {
+ // try with this self-issued
+ result = CheckRevocation (certificate, ca_cert, online);
+ if (result != X509ChainStatusFlags.RevocationStatusUnknown)
+ break;
+ ca++;
+ element = elements [ca];
+ ca_cert = element.Certificate;
+ }
+ if (result == X509ChainStatusFlags.RevocationStatusUnknown)
+ result = CheckRevocation (certificate, ca_cert, online);
+ return result;
+ }
+
+ private X509ChainStatusFlags CheckRevocation (X509Certificate2 certificate, X509Certificate2 ca_cert, bool online)
+ {
+ // change this if/when we support OCSP
+ X509KeyUsageExtension kue = (ca_cert.Extensions["2.5.29.15"] as X509KeyUsageExtension);
+ if (kue != null) {
+ // ... verify CrlSign is set
+ X509KeyUsageFlags success = X509KeyUsageFlags.CrlSign;
+ if ((kue.KeyUsages & success) != success) {
+ // FIXME - we should try to find an alternative CA that has the CrlSign bit
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+ }
+
+ MX.X509Crl crl = FindCrl (ca_cert);
+
+ if ((crl == null) && online) {
+ // FIXME - download and install new CRL
+ // then you get a second chance
+ // crl = FindCrl (ca_cert, ref valid, ref out_of_date);
+
+ // We need to get the subjectAltName and an URI from there (or use OCSP)
+ // X509KeyUsageExtension subjectAltName = (ca_cert.Extensions["2.5.29.17"] as X509KeyUsageExtension);
+ }
+
+ if (crl != null) {
+ // validate the digital signature on the CRL using the CA public key
+ // note #1: we can't use X509Crl.VerifySignature(X509Certificate) because it duplicates
+ // checks and we loose the "why" of the failure
+ // note #2: we do this before other tests as an invalid signature could be a hacked CRL
+ // (so anything within can't be trusted)
+ if (!crl.VerifySignature (ca_cert.PublicKey.Key)) {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+
+ MX.X509Crl.X509CrlEntry entry = crl.GetCrlEntry (certificate.MonoCertificate);
+ if (entry != null) {
+ // We have an entry for this CRL that includes an unknown CRITICAL extension
+ // See [X.509 7.3] NOTE 4
+ if (!ProcessCrlEntryExtensions (entry))
+ return X509ChainStatusFlags.Revoked;
+
+ // FIXME - a little more is involved
+ if (entry.RevocationDate <= ChainPolicy.VerificationTime)
+ return X509ChainStatusFlags.Revoked;
+ }
+
+ // are we overdue for a CRL update ? if so we can't be sure of any certificate status
+ if (crl.NextUpdate < ChainPolicy.VerificationTime)
+ return X509ChainStatusFlags.RevocationStatusUnknown | X509ChainStatusFlags.OfflineRevocation;
+
+ // we have a CRL that includes an unknown CRITICAL extension
+ // we put this check at the end so we do not "hide" any Revoked flags
+ if (!ProcessCrlExtensions (crl)) {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+ } else {
+ return X509ChainStatusFlags.RevocationStatusUnknown;
+ }
+
+ return X509ChainStatusFlags.NoError;
+ }
+
+ static MX.X509Crl CheckCrls (string subject, string ski, MX.X509Store store)
+ {
+ if (store == null)
+ return null;
+
+ var crls = store.Crls;
+ foreach (MX.X509Crl crl in crls) {
+ if (crl.IssuerName == subject && (ski.Length == 0 || ski == GetAuthorityKeyIdentifier (crl)))
+ return crl;
+ }
+ return null; // No CRL found
+ }
+
+ private MX.X509Crl FindCrl (X509Certificate2 caCertificate)
+ {
+ string subject = caCertificate.SubjectName.Decode (X500DistinguishedNameFlags.None);
+ string ski = GetSubjectKeyIdentifier (caCertificate);
+
+ // consider that the LocalMachine directories could not exists... and cannot be created by the user
+ MX.X509Crl result = CheckCrls (subject, ski, LMCAStore.Store);
+ if (result != null)
+ return result;
+ if (location == StoreLocation.CurrentUser) {
+ result = CheckCrls (subject, ski, UserCAStore.Store);
+ if (result != null)
+ return result;
+ }
+
+ // consider that the LocalMachine directories could not exists... and cannot be created by the user
+ result = CheckCrls (subject, ski, LMRootStore.Store);
+ if (result != null)
+ return result;
+ if (location == StoreLocation.CurrentUser) {
+ result = CheckCrls (subject, ski, UserRootStore.Store);
+ if (result != null)
+ return result;
+ }
+ return null;
+ }
+
+ private bool ProcessCrlExtensions (MX.X509Crl crl)
+ {
+ foreach (MX.X509Extension ext in crl.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid) {
+ case "2.5.29.20": // cRLNumber
+ case "2.5.29.35": // authorityKeyIdentifier
+ // we processed/know about this extension
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private bool ProcessCrlEntryExtensions (MX.X509Crl.X509CrlEntry entry)
+ {
+ foreach (MX.X509Extension ext in entry.Extensions) {
+ if (ext.Critical) {
+ switch (ext.Oid) {
+ case "2.5.29.21": // cRLReason
+ // we processed/know about this extension
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
+#endif
--- /dev/null
+//
+// X509Helper2.cs
+//
+// Authors:
+// Martin Baulig <martin.baulig@xamarin.com>
+//
+// Copyright (C) 2016 Xamarin, Inc. (http://www.xamarin.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+#if SECURITY_DEP
+namespace System.Security.Cryptography.X509Certificates
+{
+ internal static class X509Helper2
+ {
+ internal static void ThrowIfContextInvalid (X509CertificateImpl impl)
+ {
+ X509Helper.ThrowIfContextInvalid (impl);
+ }
+
+ internal static X509Certificate2Impl Import (byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
+ {
+ var impl = new X509Certificate2ImplMono ();
+ impl.Import (rawData, password, keyStorageFlags);
+ return impl;
+ }
+
+ internal static X509Certificate2Impl Import (X509Certificate cert)
+ {
+ var impl2 = cert.Impl as X509Certificate2Impl;
+ if (impl2 != null)
+ return (X509Certificate2Impl)impl2.Clone ();
+ return Import (cert.GetRawCertData (), null, X509KeyStorageFlags.DefaultKeySet);
+ }
+
+ internal static X509ChainImpl CreateChainImpl (bool useMachineContext)
+ {
+ return new X509ChainImplMono (useMachineContext);
+ }
+
+ public static bool IsValid (X509ChainImpl impl)
+ {
+ return impl != null && impl.IsValid;
+ }
+
+ internal static void ThrowIfContextInvalid (X509ChainImpl impl)
+ {
+ if (!IsValid (impl))
+ throw GetInvalidChainContextException ();
+ }
+
+ internal static Exception GetInvalidChainContextException ()
+ {
+ return new CryptographicException (Locale.GetText ("Chain instance is empty."));
+ }
+ }
+}
+#endif
namespace System.Security.Cryptography.X509Certificates {
- public sealed class X509Store : IDisposable {
+ public sealed class X509Store {
private string _name;
private StoreLocation _location;
_location = storeLocation;
}
- public void Dispose ()
- {
- }
-
// properties
public X509Certificate2Collection Certificates {
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
System.Security.Cryptography.X509Certificates/X509Chain.cs
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
+System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
+System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
System.Security.Cryptography.X509Certificates/X509FindType.cs
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
+System.Security.Cryptography.X509Certificates/X509Helper2.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
System.Security.Cryptography.X509Certificates/X509NameType.cs
public static MyNetworkStream CreateNS (int port)
{
- return CreateNS (port, 5000);
+ return CreateNS (IPAddress.Loopback, port, 5000);
}
public static MyNetworkStream CreateNS (int port, int timeout_ms)
+ {
+ return CreateNS (IPAddress.Loopback, port, timeout_ms);
+ }
+
+ public static MyNetworkStream CreateNS (IPAddress ip, int port)
+ {
+ return CreateNS (ip, port, 5000);
+ }
+
+ public static MyNetworkStream CreateNS (IPAddress ip, int port, int timeout_ms)
{
Socket sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- sock.Connect (new IPEndPoint (IPAddress.Loopback, port));
+ sock.Connect (new IPEndPoint (ip, port));
sock.SendTimeout = timeout_ms;
sock.ReceiveTimeout = timeout_ms;
return new MyNetworkStream (sock);
using System.Net;
using System.Net.Sockets;
using System.Text;
+using System.Collections.Generic;
using NUnit.Framework;
listener.Close ();
}
+ [Test]
+ public void HttpRequestIsLocal ()
+ {
+ var ips = new List<IPAddress> (Dns.GetHostAddresses (Dns.GetHostName ()));
+ ips.Add (IPAddress.Loopback);
+ foreach (var ip in ips) {
+ if (ip.AddressFamily != AddressFamily.InterNetwork)
+ continue;
+
+ HttpListener listener = HttpListener2Test.CreateAndStartListener (
+ "http://" + ip + ":9000/HttpRequestIsLocal/");
+ NetworkStream ns = HttpListener2Test.CreateNS (ip, 9000);
+ HttpListener2Test.Send (ns, "GET /HttpRequestIsLocal/ HTTP/1.0\r\n\r\n");
+ HttpListenerContext ctx = listener.GetContext ();
+ HttpListenerRequest request = ctx.Request;
+ Assert.AreEqual (true, request.IsLocal, "IP " + ip + " is not local");
+ listener.Close ();
+ }
+ }
+
[Test] // #29927
public void HttpRequestUriUnescape ()
{
}
[Test]
- [ExpectedException (typeof (ArgumentException))]
public void GetNameInfo_Invalid_True ()
{
- new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, true);
+ try {
+ // MS throws ArgumentException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, true);
+ Assert.Fail ("Expected exception.");
+ } catch (ArgumentException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'ArgumentException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
- [ExpectedException (typeof (ArgumentException))]
public void GetNameInfo_Invalid_False ()
{
- new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, false);
+ try {
+ // MS throws ArgumentException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo ((X509NameType) Int32.MinValue, false);
+ Assert.Fail ("Expected exception.");
+ } catch (ArgumentException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'ArgumentException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
}
[Test]
- [ExpectedException (typeof (NullReferenceException))]
public void Empty_GetNameInfo_DnsName ()
{
- new X509Certificate2 ().GetNameInfo (X509NameType.DnsName, true);
+ try {
+ // MS throws NullReferenceException, Mono's new implementation throws
+ // CryptographicException, which is consistent with other "certificate
+ // instance is empty" situations.
+ new X509Certificate2 ().GetNameInfo (X509NameType.DnsName, true);
+ Assert.Fail ("Expected exception.");
+ } catch (NullReferenceException) {
+ } catch (CryptographicException) {
+ } catch (Exception ex) {
+ Assert.Fail ("Expected 'NullReferenceException' or 'CryptographicException', got '{0}'", ex.GetType ());
+ }
}
[Test]
System.Security.Cryptography.X509Certificates/X509Certificate2.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Collection.cs
System.Security.Cryptography.X509Certificates/X509Certificate2Enumerator.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2Impl.cs
+System.Security.Cryptography.X509Certificates/X509Certificate2ImplMono.cs
System.Security.Cryptography.X509Certificates/X509CertificateCollection.cs
System.Security.Cryptography.X509Certificates/X509Chain.cs
System.Security.Cryptography.X509Certificates/X509ChainElement.cs
System.Security.Cryptography.X509Certificates/X509ChainElementCollection.cs
System.Security.Cryptography.X509Certificates/X509ChainElementEnumerator.cs
+System.Security.Cryptography.X509Certificates/X509ChainImpl.cs
+System.Security.Cryptography.X509Certificates/X509ChainImplMono.cs
System.Security.Cryptography.X509Certificates/X509ChainPolicy.cs
System.Security.Cryptography.X509Certificates/X509ChainStatus.cs
System.Security.Cryptography.X509Certificates/X509ChainStatusFlags.cs
System.Security.Cryptography.X509Certificates/X509ExtensionEnumerator.cs
System.Security.Cryptography.X509Certificates/X509FindType.cs
System.Security.Cryptography.X509Certificates/X509IncludeOption.cs
+System.Security.Cryptography.X509Certificates/X509Helper2.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageExtension.cs
System.Security.Cryptography.X509Certificates/X509KeyUsageFlags.cs
System.Security.Cryptography.X509Certificates/X509NameType.cs
[assembly: DefaultDependency (LoadHint.Always)]
[assembly: StringFreezing]
-#if NET_2_1
-[assembly: InternalsVisibleTo ("System, PublicKey=00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB")]
-[assembly: InternalsVisibleTo ("System.Core, PublicKey=00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB")]
-#else
-[assembly: InternalsVisibleTo ("System, PublicKey=00000000000000000400000000000000")]
-[assembly: InternalsVisibleTo ("System.Core, PublicKey=00000000000000000400000000000000")]
-#endif
+[assembly: InternalsVisibleTo ("System, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull2)]
+[assembly: InternalsVisibleTo ("System.Core, PublicKey=" + AssemblyRef.FrameworkPublicKeyFull2)]
+
[assembly: InternalsVisibleTo ("System.Numerics, PublicKey=00000000000000000400000000000000")]
#if MONOTOUCH
public sealed class FileInfo : FileSystemInfo
{
private bool exists;
+ private string displayPath;
public FileInfo (string fileName)
{
OriginalPath = fileName;
FullPath = Path.GetFullPath (fileName);
+
+ displayPath = OriginalPath;
}
private FileInfo (SerializationInfo info, StreamingContext context)
: base (info, context)
{
+ displayPath = OriginalPath;
}
internal override void InternalRefresh ()
File.Move (FullPath, destFullPath);
this.FullPath = destFullPath;
+
+ displayPath = destFileName;
}
public FileInfo CopyTo (string destFileName)
public override string ToString ()
{
- return OriginalPath;
+ return displayPath;
}
#if !MOBILE
impl = X509Helper.InitFromHandle (handle);
}
+ internal X509Certificate (X509CertificateImpl impl)
+ {
+ if (impl == null)
+ throw new ArgumentNullException ("impl");
+
+ this.impl = X509Helper.InitFromCertificate (impl);
+ }
+
public X509Certificate (System.Security.Cryptography.X509Certificates.X509Certificate cert)
{
if (cert == null)
hideDates = false;
}
+ internal void ImportHandle (X509CertificateImpl impl)
+ {
+ Reset ();
+ this.impl = impl;
+ }
+
+ internal X509CertificateImpl Impl {
+ get {
+ X509Helper.ThrowIfContextInvalid (impl);
+ return impl;
+ }
+ }
+
+ internal bool IsValid {
+ get { return X509Helper.IsValid (impl); }
+ }
+
+ internal void ThrowIfContextInvalid ()
+ {
+ X509Helper.ThrowIfContextInvalid (impl);
+ }
// public methods
return null;
X509Helper.ThrowIfContextInvalid (impl);
- return impl.GetEffectiveDateString ().ToString ();
+ return impl.GetValidFrom ().ToLocalTime ().ToString ();
}
// strangly there are no DateTime returning function
return null;
X509Helper.ThrowIfContextInvalid (impl);
- return impl.GetExpirationDateString ().ToString ();
+ return impl.GetValidUntil ().ToLocalTime ().ToString ();
}
// well maybe someday there'll be support for PGP or SPKI ?
public abstract X509CertificateImpl Clone ();
- public abstract string GetSubjectSummary ();
-
public abstract string GetIssuerName (bool legacyV1Mode);
public abstract string GetSubjectName (bool legacyV1Mode);
public abstract byte[] GetRawCertData ();
- public abstract DateTime GetEffectiveDateString ();
+ public abstract DateTime GetValidFrom ();
- public abstract DateTime GetExpirationDateString ();
+ public abstract DateTime GetValidUntil ();
byte[] cachedCertificateHash;
return MX.X501.ToString (x509.GetIssuerName (), true, ", ", true);
}
- public override string GetSubjectSummary ()
- {
- ThrowIfContextInvalid ();
- return x509.SubjectName;
- }
-
public override string GetSubjectName (bool legacyV1Mode)
{
ThrowIfContextInvalid ();
return sha.ComputeHash (x509.RawData);
}
- public override DateTime GetEffectiveDateString ()
+ public override DateTime GetValidFrom ()
{
ThrowIfContextInvalid ();
- return x509.ValidFrom.ToLocalTime ();
+ return x509.ValidFrom;
}
- public override DateTime GetExpirationDateString ()
+ public override DateTime GetValidUntil ()
{
ThrowIfContextInvalid ();
- return x509.ValidUntil.ToLocalTime ();
+ return x509.ValidUntil;
}
public override bool Equals (X509CertificateImpl other, out bool result)
StringBuilder sb = new StringBuilder ();
sb.AppendFormat ("[Subject]{0} {1}{0}{0}", nl, GetSubjectName (false));
sb.AppendFormat ("[Issuer]{0} {1}{0}{0}", nl, GetIssuerName (false));
- sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetEffectiveDateString ());
- sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetExpirationDateString ());
+ sb.AppendFormat ("[Not Before]{0} {1}{0}{0}", nl, GetValidFrom ().ToLocalTime ());
+ sb.AppendFormat ("[Not After]{0} {1}{0}{0}", nl, GetValidUntil ().ToLocalTime ());
sb.AppendFormat ("[Thumbprint]{0} {1}{0}", nl, X509Helper.ToHexString (GetCertHash ()));
sb.Append (nl);
return sb.ToString ();
}
}
+ [Test] //Covers #38796
+ public void ToStringAfterMoveTo ()
+ {
+ string name1 = "FIT.ToStringAfterMoveTo.Test";
+ string name2 = "FIT.ToStringAfterMoveTo.Test.Alt";
+ string path1 = TempFolder + DSC + name1;
+ string path2 = TempFolder + DSC + name2;
+ DeleteFile (path1);
+ DeleteFile (path2);
+
+ try {
+ File.Create (path1).Close ();
+ FileInfo info = new FileInfo (path1);
+ Assert.AreEqual (path1, info.ToString (), "#A");
+
+ info.MoveTo (path2);
+ Assert.AreEqual (path2, info.ToString (), "#B");
+ } finally {
+ DeleteFile (path1);
+ DeleteFile (path2);
+ }
+ }
+
#if !MOBILE
[Test]
public void Replace1 ()
Assembly/AssemblyInfo.cs
../../build/common/Consts.cs
../../build/common/Locale.cs
+../../build/common/AssemblyRef.cs
Microsoft.Win32/IRegistryApi.cs
Microsoft.Win32/RegistryKey.cs
Microsoft.Win32/RegistryKeyPermissionCheck.cs
return IsLeftResolvedExpressionValid (dmb.Arguments [0].Expr);
}
- if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is This)
+ if (expr is ConstantExpr || expr is TypeExpr || expr is NamespaceExpression || expr is VariableReference)
return true;
return false;
public static event Action Act = null;
public static dynamic BBB = null;
+ void ParameterTest (Person ParPerson)
+ {
+ Console.WriteLine (nameof (ParPerson.MyCar.Year));
+ }
+
public static int Main ()
{
string name;
if (name != "ToString")
return 7;
+ Person LocPerson = null;
+ name = nameof (LocPerson.MyCar.Year);
+ if (name != "Year")
+ return 8;
+
return 0;
}
}
<size>40</size>
</method>
<method name="Int32 Main()" attrs="150">
- <size>213</size>
+ <size>244</size>
</method>
<method name="Void .ctor()" attrs="6278">
<size>7</size>
<size>7</size>
</method>
</type>
+ <type name="MainClass">
+ <method name="Void ParameterTest(Person)" attrs="129">
+ <size>12</size>
+ </method>
+ </type>
</test>
<test name="test-null-operator-01.cs">
<type name="S">
PROGRAM = cil-stringreplacer.exe
NO_INSTALL = yes
-LOCAL_MCS_FLAGS = -r:System.dll
+LOCAL_MCS_FLAGS = -r:System.dll -r:Mono.Cecil.dll
include ../../build/executable.make
static void RewriteAssembly (string assemblyLocation, Dictionary<string, string> resourcesStrings, CmdOptions options)
{
- var assembly = AssemblyDefinition.ReadAssembly (assemblyLocation);
+ var readerParameters = new ReaderParameters { ReadSymbols = true };
+ var assembly = AssemblyDefinition.ReadAssembly (assemblyLocation, readerParameters);
foreach (var module in assembly.Modules) {
foreach (var type in module.GetTypes ()) {
foreach (var method in type.Methods) {
}
}
- assembly.Write (assemblyLocation);
+ var writerParameters = new WriterParameters { WriteSymbols = true };
+ assembly.Write (assemblyLocation, writerParameters);
}
static bool LoadGetResourceStrings (Dictionary<string, string> resourcesStrings, CmdOptions options)
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>\r
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
+ <PropertyGroup>\r
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>\r
+ <ProjectGuid>{7A08A2B6-5AC3-4268-8566-B07648B50D01}</ProjectGuid>\r
+ <OutputType>Exe</OutputType>\r
+ <RootNamespace>cilstringreplacer</RootNamespace>\r
+ <AssemblyName>cilstringreplacer</AssemblyName>\r
+ <TargetFrameworkVersion>v4.6</TargetFrameworkVersion>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">\r
+ <DebugSymbols>true</DebugSymbols>\r
+ <DebugType>full</DebugType>\r
+ <Optimize>false</Optimize>\r
+ <OutputPath>bin\Debug</OutputPath>\r
+ <DefineConstants>DEBUG;</DefineConstants>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <WarningLevel>4</WarningLevel>\r
+ <ExternalConsole>false</ExternalConsole>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ <Commandlineparameters>--resourcestrings:/Users/marek/git/mono/external/referencesource/mscorlib/mscorlib.txt /Users/marek/git/mono/mcs/class/lib/net_4_x/mscorlib.dll</Commandlineparameters>\r
+ <ConsolePause>false</ConsolePause>\r
+ </PropertyGroup>\r
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
+ <Optimize>true</Optimize>\r
+ <OutputPath>bin\Release</OutputPath>\r
+ <ErrorReport>prompt</ErrorReport>\r
+ <WarningLevel>4</WarningLevel>\r
+ <ExternalConsole>true</ExternalConsole>\r
+ <PlatformTarget>x86</PlatformTarget>\r
+ </PropertyGroup>\r
+ <ItemGroup>\r
+ <Reference Include="System" />\r
+ <Reference Include="Mono.Cecil">\r
+ <HintPath>..\..\class\lib\net_4_x\Mono.Cecil.dll</HintPath>\r
+ </Reference>\r
+ </ItemGroup>\r
+ <ItemGroup>\r
+ <Compile Include="cil-stringreplacer.cs">\r
+ <Link>cil-stringreplacer.cs</Link>\r
+ </Compile>\r
+ <Compile Include="..\..\class\Mono.Options\Mono.Options\Options.cs">\r
+ <Link>Options.cs</Link>\r
+ </Compile>\r
+ </ItemGroup>\r
+ <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />\r
+</Project>
\ No newline at end of file
cil-stringreplacer.cs
../../class/Mono.Options/Mono.Options/Options.cs
-../../../external/cecil/Mono.Cecil/*.cs
-../../../external/cecil/Mono.Cecil.Cil/*.cs
-../../../external/cecil/Mono.Cecil.Metadata/*.cs
-../../../external/cecil/Mono.Cecil.PE/*.cs
-../../../external/cecil/Mono.Collections.Generic/*.cs
-../../../external/cecil/Mono/Empty.cs
-../../../external/cecil/Mono.Security.Cryptography/*.cs
static bool TryToMatchErrorMessage (string actual, string expected)
{
+ actual = actual.Replace ("\\", "/");
var path_mask_start = expected.IndexOf ("*PATH*");
if (path_mask_start > 0 && actual.Length > path_mask_start) {
var path_mask_continue = expected.Substring (path_mask_start + 6);
SUBDIRS =
include ../../build/rules.make
-ALL_PROGRAMS = mono-api-info.exe
-
-COMMON_SOURCES = \
- AssemblyResolver.cs \
- Util.cs \
- WellFormedXmlWriter.cs
+ALL_PROGRAMS = mono-api-info.exe mono-api-html.exe
PROGRAM_INSTALL_DIR = $(mono_libdir)/mono/$(FRAMEWORK_VERSION)
APIINFO_SOURCES = \
mono-api-info.cs \
- ../../class/Mono.Options/Mono.Options/Options.cs \
- $(COMMON_SOURCES)
+ AssemblyResolver.cs \
+ Util.cs \
+ WellFormedXmlWriter.cs \
+ ../../class/Mono.Options/Mono.Options/Options.cs
+
+APIHTML_SOURCES = \
+ mono-api-html/ApiChange.cs \
+ mono-api-html/ApiDiff.cs \
+ mono-api-html/AssemblyComparer.cs \
+ mono-api-html/ClassComparer.cs \
+ mono-api-html/Comparer.cs \
+ mono-api-html/ConstructorComparer.cs \
+ mono-api-html/EventComparer.cs \
+ mono-api-html/FieldComparer.cs \
+ mono-api-html/Helpers.cs \
+ mono-api-html/InterfaceComparer.cs \
+ mono-api-html/MemberComparer.cs \
+ mono-api-html/MethodComparer.cs \
+ mono-api-html/NamespaceComparer.cs \
+ mono-api-html/PropertyComparer.cs \
+ ../../class/Mono.Options/Mono.Options/Options.cs
-DISTFILES= $(COMMON_SOURCES) $(APIINFO_SOURCES)
+
+DISTFILES= $(APIINFO_SOURCES) $(APIHTML_SOURCES)
all-local: $(ALL_PROGRAMS)
dist-local: dist-default
-mono-api-info.exe: $(APIINFO_SOURCES) ../../class/Mono.Options/Mono.Options/Options.cs
+mono-api-info.exe: $(APIINFO_SOURCES)
$(CSCOMPILE) -r:Mono.Cecil.dll -r:System.Xml.dll -r:System.Core.dll -r:System.dll -out:$@ $^
+
+mono-api-html.exe: $(APIHTML_SOURCES)
+ $(CSCOMPILE) -r:Mono.Cecil.dll -r:System.Xml.dll -r:System.Core.dll -r:System.dll -r:System.Xml.Linq.dll -out:$@ $^
Copy (name, asmb_path, true);
+ var name_pdb = Path.ChangeExtension (name, ".pdb");
+ if (File.Exists (name_pdb)) {
+ Copy (name_pdb, Path.ChangeExtension (asmb_path, ".pdb"), true);
+ }
+
foreach (string ext in siblings) {
string sibling = String.Concat (name, ext);
if (File.Exists (sibling))
string pkg_path = AbsoluteToRelativePath (ref_dir, pkg_path_abs);
symlink (pkg_path, ref_path);
+ var pdb_pkg_path = Path.ChangeExtension (pkg_path, ".pdb");
+ var pdb_ref_path = Path.ChangeExtension (ref_path, ".pdb");
+
+ if (File.Exists (pdb_pkg_path)) {
+ symlink (pdb_pkg_path, pdb_ref_path);
+ } else {
+ try {
+ File.Delete (pdb_ref_path);
+ } catch {
+ // Ignore error, just delete files that should not be there.
+ }
+ }
+
foreach (string ext in siblings) {
string sibling = String.Concat (pkg_path, ext);
string sref = String.Concat (ref_path, ext);
+
if (File.Exists (sibling))
symlink (sibling, sref);
else {
static void
mono_class_setup_vtable_full (MonoClass *klass, GList *in_setup)
{
+ MonoError error;
MonoMethod **overrides;
MonoGenericContext *context;
guint32 type_token;
* This is true since we don't do layout all over again for them, we simply inflate
* the layout of the parent.
*/
- mono_reflection_get_dynamic_overrides (klass, &overrides, &onum);
+ mono_reflection_get_dynamic_overrides (klass, &overrides, &onum, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ g_list_remove (in_setup, klass);
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, g_strdup_printf("Could not load list of method overrides due to %s", mono_error_get_message (&error)));
+ mono_error_cleanup (&error);
+ return;
+ }
} else {
/* The following call fails if there are missing methods in the type */
/* FIXME it's probably a good idea to avoid this for generic instances. */
gboolean
mono_class_is_assignable_from (MonoClass *klass, MonoClass *oklass)
{
+ MonoError error;
/*FIXME this will cause a lot of irrelevant stuff to be loaded.*/
if (!klass->inited)
mono_class_init (klass);
}
/* interface_offsets might not be set for dynamic classes */
- if (oklass->ref_info_handle && !oklass->interface_bitmap)
+ if (oklass->ref_info_handle && !oklass->interface_bitmap) {
/*
* oklass might be a generic type parameter but they have
* interface_offsets set.
*/
- return mono_reflection_call_is_assignable_to (oklass, klass);
+ gboolean result = mono_reflection_call_is_assignable_to (oklass, klass, &error);
+ if (!is_ok (&error)) {
+ mono_error_cleanup (&error);
+ return FALSE;
+ }
+ return result;
+ }
if (!oklass->interface_bitmap)
/* Happens with generic instances of not-yet created dynamic types */
return FALSE;
return TRUE;
if (mono_class_has_variant_generic_params (klass)) {
- MonoError error;
int i;
mono_class_setup_interfaces (oklass, &error);
if (!mono_error_ok (&error)) {
mono_loader_cleanup ();
mono_classes_cleanup ();
mono_assemblies_cleanup ();
- mono_images_cleanup ();
mono_debug_cleanup ();
+ mono_images_cleanup ();
mono_metadata_cleanup ();
mono_native_tls_free (appdomain_thread_id);
return mono_handle_arena_elevate (mono_handle_arena_current (), handle);
}
-#ifndef CHECKED_BUILD
+#ifndef ENABLE_CHECKED_BUILD
#define mono_handle_obj(handle) ((handle)->__private_obj)
ICALL(ASSEMB_2, "basic_init", mono_image_basic_init)
ICALL_TYPE(CATTRB, "System.Reflection.Emit.CustomAttributeBuilder", CATTRB_1)
-ICALL(CATTRB_1, "GetBlob", mono_reflection_get_custom_attrs_blob)
+ICALL(CATTRB_1, "GetBlob", ves_icall_System_Reflection_Emit_CustomAttributeBuilder_GetBlob)
#ifndef DISABLE_REFLECTION_EMIT
ICALL_TYPE(DERIVEDTYPE, "System.Reflection.Emit.DerivedType", DERIVEDTYPE_1)
return result;
}
+ICALL_EXPORT MonoArray*
+ves_icall_System_Reflection_Emit_CustomAttributeBuilder_GetBlob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
+{
+ MonoError error;
+ MonoArray *result = mono_reflection_get_custom_attrs_blob_checked (assembly, ctor, ctorArgs, properties, propValues, fields, fieldValues, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
static gboolean
get_caller (MonoMethod *m, gint32 no, gint32 ilo, gboolean managed, gpointer data)
{
types [i] = t->type;
}
- geninst = mono_reflection_bind_generic_parameters (type, count, types);
+ geninst = mono_reflection_bind_generic_parameters (type, count, types, &error);
g_free (types);
- if (!geninst)
+ if (!geninst) {
+ mono_error_set_pending_exception (&error);
return NULL;
+ }
klass = mono_class_from_mono_type (geninst);
if (!exportedOnly || mono_module_type_is_visible (tdef, image, i + 1)) {
klass = mono_class_get_checked (image, (i + 1) | MONO_TOKEN_TYPE_DEF, error);
mono_loader_assert_no_error (); /* Plug any leaks */
- mono_error_assert_ok (error);
if (klass) {
rt = mono_type_get_object_checked (domain, &klass->byval_arg, error);
i = ((MonoImageLoader*)image->loader)->load_tables (image);
g_assert (image->heap_guid.data);
- g_assert (image->heap_guid.size >= 16);
- image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
+ if (!image->metadata_only) {
+ g_assert (image->heap_guid.size >= 16);
+
+ image->guid = mono_guid_to_string ((guint8*)image->heap_guid.data);
+ } else {
+ /* PPDB files have no guid */
+ guint8 empty_guid [16];
+
+ memset (empty_guid, 0, sizeof (empty_guid));
+
+ image->guid = mono_guid_to_string (empty_guid);
+ }
return i;
}
goto done;
}
- if (image->loader == &pe_loader && !mono_verifier_verify_cli_data (image, &errors))
+ if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_cli_data (image, &errors))
goto invalid_image;
if (!mono_image_load_cli_data (image))
goto invalid_image;
- if (image->loader == &pe_loader && !mono_verifier_verify_table_data (image, &errors))
+ if (image->loader == &pe_loader && !image->metadata_only && !mono_verifier_verify_table_data (image, &errors))
goto invalid_image;
mono_image_load_names (image);
if (delegate->method_is_virtual)
method = mono_object_get_virtual_method (delegate->target, method);
- if (mono_method_signature (method)->pinvoke) {
+ if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
const char *exc_class, *exc_arg;
gpointer ftnptr;
EmitMarshalContext m;
g_assert (method != NULL);
- g_assert (!mono_method_signature (method)->pinvoke);
+ g_assert (!(method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL));
/*
* FIXME: Should cache the method+delegate type pair, since the same method
MonoReflectionType* mono_reflection_create_runtime_class (MonoReflectionTypeBuilder *tb);
-void mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides);
+void mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error);
void mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *m);
void mono_reflection_destroy_dynamic_method (MonoReflectionDynamicMethod *mb);
MonoClass*
mono_class_bind_generic_parameters (MonoClass *klass, int type_argc, MonoType **types, gboolean is_dynamic);
MonoType*
-mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types);
+mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error);
MonoReflectionMethod*
mono_reflection_bind_generic_method_parameters (MonoReflectionMethod *method, MonoArray *types);
void
mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context);
gboolean
-mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass);
+mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, MonoError *error);
gboolean
mono_reflection_is_valid_dynamic_token (MonoDynamicImage *image, guint32 token);
MonoArray*
mono_reflection_get_custom_attrs_data_checked (MonoObject *obj, MonoError *error);
+MonoArray*
+mono_reflection_get_custom_attrs_blob_checked (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues, MonoError *error);
+
MonoCustomAttrInfo*
mono_custom_attrs_from_index_checked (MonoImage *image, uint32_t idx, MonoError *error);
MonoCustomAttrInfo*
static guint32 mono_image_get_ctorbuilder_token (MonoDynamicImage *assembly, MonoReflectionCtorBuilder *cb, MonoError *error);
static guint32 mono_image_get_sighelper_token (MonoDynamicImage *assembly, MonoReflectionSigHelper *helper, MonoError *error);
static gboolean ensure_runtime_vtable (MonoClass *klass, MonoError *error);
-static gpointer resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context);
+static gpointer resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error);
static guint32 mono_image_get_methodref_token_for_methodbuilder (MonoDynamicImage *assembly, MonoReflectionMethodBuilder *method, MonoError *error);
static guint32 encode_generic_method_sig (MonoDynamicImage *assembly, MonoGenericContext *context);
static gpointer register_assembly (MonoDomain *domain, MonoReflectionAssembly *res, MonoAssembly *assembly);
{
MonoError error;
MonoReflectionMethodBody *result = mono_method_body_get_object_checked (domain, method, &error);
- mono_error_cleanup (&error); /* FIXME new API that doesn't swallow the error */
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
return result;
}
/* for compatibility with .net */
if (method_is_dynamic (method)) {
- mono_error_set_exception_instance (error, mono_get_exception_invalid_operation (NULL));
+ mono_error_set_generic_error (error, "System", "InvalidOperationException", "");
return NULL;
}
local_var_sig_token = 0; //FIXME
ret = (MonoReflectionMethodBody*)mono_object_new_checked (domain, mono_class_get_method_body_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
ret->init_locals = header->init_locals;
ret->max_stack = header->max_stack;
MONO_OBJECT_SETREF (ret, locals, mono_array_new_cached (domain, mono_class_get_local_variable_info_class (), header->num_locals));
for (i = 0; i < header->num_locals; ++i) {
MonoReflectionLocalVariableInfo *info = (MonoReflectionLocalVariableInfo*)mono_object_new_checked (domain, mono_class_get_local_variable_info_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
rt = mono_type_get_object_checked (domain, header->locals [i], error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MONO_OBJECT_SETREF (info, local_type, rt);
MONO_OBJECT_SETREF (ret, clauses, mono_array_new_cached (domain, mono_class_get_exception_handling_clause_class (), header->num_clauses));
for (i = 0; i < header->num_clauses; ++i) {
MonoReflectionExceptionHandlingClause *info = (MonoReflectionExceptionHandlingClause*)mono_object_new_checked (domain, mono_class_get_exception_handling_clause_class (), error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MonoExceptionClause *clause = &header->clauses [i];
info->flags = clause->flags;
info->filter_offset = clause->data.filter_offset;
else if (clause->data.catch_class) {
rt = mono_type_get_object_checked (mono_domain_get (), &clause->data.catch_class->byval_arg, error);
- return_val_if_nok (error, NULL);
+ if (!is_ok (error))
+ goto fail;
MONO_OBJECT_SETREF (info, catch_type, rt);
}
mono_metadata_free_mh (header);
CACHE_OBJECT (MonoReflectionMethodBody *, method, ret, NULL);
return ret;
+
+fail:
+ mono_metadata_free_mh (header);
+ return NULL;
}
/**
return NULL;
instance = mono_reflection_bind_generic_parameters (
- the_type, info->type_arguments->len, type_args);
+ the_type, info->type_arguments->len, type_args, error);
g_free (type_args);
if (!instance)
}
}
- res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types);
+ res = mono_reflection_bind_generic_parameters (gclass->generic_type, count, types, error);
g_free (types);
g_assert (res);
gclass->type.type = res;
mono_error_set_pending_exception (&error);
}
-void
-mono_reflection_register_with_runtime (MonoReflectionType *type)
+static gboolean
+reflection_register_with_runtime (MonoReflectionType *type, MonoError *error)
{
- MonoError error;
- MonoType *res = mono_reflection_type_get_handle (type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
MonoDomain *domain = mono_object_domain ((MonoObject*)type);
MonoClass *klass;
- if (!res)
- mono_raise_exception (mono_get_exception_argument (NULL, "Invalid generic instantiation, one or more arguments are not proper user types"));
+ mono_error_init (error);
+
+ MonoType *res = mono_reflection_type_get_handle (type, error);
+
+ if (!res && is_ok (error)) {
+ mono_error_set_argument (error, NULL, "Invalid generic instantiation, one or more arguments are not proper user types");
+ }
+ return_val_if_nok (error, FALSE);
klass = mono_class_from_mono_type (res);
}
mono_domain_unlock (domain);
mono_loader_unlock ();
+
+ return TRUE;
+}
+
+void
+mono_reflection_register_with_runtime (MonoReflectionType *type)
+{
+ MonoError error;
+ (void) reflection_register_with_runtime (type, &error);
+ mono_error_set_pending_exception (&error);
}
/**
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-parameters_to_signature (MonoImage *image, MonoArray *parameters) {
- MonoError error;
+parameters_to_signature (MonoImage *image, MonoArray *parameters, MonoError *error) {
MonoMethodSignature *sig;
int count, i;
+ mono_error_init (error);
+
count = parameters? mono_array_length (parameters): 0;
sig = (MonoMethodSignature *)image_g_malloc0 (image, MONO_SIZEOF_METHOD_SIGNATURE + sizeof (MonoType*) * count);
sig->param_count = count;
sig->sentinelpos = -1; /* FIXME */
for (i = 0; i < count; ++i) {
- sig->params [i] = mono_type_array_get_and_resolve (parameters, i, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->params [i] = mono_type_array_get_and_resolve (parameters, i, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
}
return sig;
}
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-ctor_builder_to_signature (MonoImage *image, MonoReflectionCtorBuilder *ctor) {
+ctor_builder_to_signature (MonoImage *image, MonoReflectionCtorBuilder *ctor, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (image, ctor->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (image, ctor->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = ctor->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
sig->ret = &mono_defaults.void_class->byval_arg;
return sig;
* LOCKING: Assumes the loader lock is held.
*/
static MonoMethodSignature*
-method_builder_to_signature (MonoImage *image, MonoReflectionMethodBuilder *method) {
- MonoError error;
+method_builder_to_signature (MonoImage *image, MonoReflectionMethodBuilder *method, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (image, method->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (image, method->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
if (method->rtype) {
- sig->ret = mono_reflection_type_get_handle ((MonoReflectionType*)method->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->ret = mono_reflection_type_get_handle ((MonoReflectionType*)method->rtype, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
} else {
sig->ret = &mono_defaults.void_class->byval_arg;
}
}
static MonoMethodSignature*
-dynamic_method_to_signature (MonoReflectionDynamicMethod *method) {
- MonoError error;
+dynamic_method_to_signature (MonoReflectionDynamicMethod *method, MonoError *error) {
MonoMethodSignature *sig;
- sig = parameters_to_signature (NULL, method->parameters);
+ mono_error_init (error);
+
+ sig = parameters_to_signature (NULL, method->parameters, error);
+ return_val_if_nok (error, NULL);
sig->hasthis = method->attrs & METHOD_ATTRIBUTE_STATIC? 0: 1;
if (method->rtype) {
- sig->ret = mono_reflection_type_get_handle (method->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->ret = mono_reflection_type_get_handle (method->rtype, error);
+ if (!is_ok (error)) {
+ g_free (sig);
+ return NULL;
+ }
} else {
sig->ret = &mono_defaults.void_class->byval_arg;
}
}
static void
-get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type)
+get_prop_name_and_type (MonoObject *prop, char **name, MonoType **type, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (prop);
if (strcmp (klass->name, "PropertyBuilder") == 0) {
MonoReflectionPropertyBuilder *pb = (MonoReflectionPropertyBuilder *)prop;
*name = mono_string_to_utf8 (pb->name);
- *type = mono_reflection_type_get_handle ((MonoReflectionType*)pb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ *type = mono_reflection_type_get_handle ((MonoReflectionType*)pb->type, error);
} else {
MonoReflectionProperty *p = (MonoReflectionProperty *)prop;
*name = g_strdup (p->property->name);
}
static void
-get_field_name_and_type (MonoObject *field, char **name, MonoType **type)
+get_field_name_and_type (MonoObject *field, char **name, MonoType **type, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (field);
if (strcmp (klass->name, "FieldBuilder") == 0) {
MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)field;
*name = mono_string_to_utf8 (fb->name);
- *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
} else {
MonoReflectionField *f = (MonoReflectionField *)field;
*name = g_strdup (mono_field_get_name (f->field));
return type;
}
-/*
+/**
+ * encode_cattr_value:
* Encode a value in a custom attribute stream of bytes.
* The value to encode is either supplied as an object in argument val
* (valuetypes are boxed), or as a pointer to the data in the
* @buflen contains the size of the buffer and is used to return the new buffer size
* if this needs to be realloced.
* @retbuffer and @retp return the start and the position of the buffer
+ * @error set on error.
*/
static void
-encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg, char *argval)
+encode_cattr_value (MonoAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, MonoObject *arg, char *argval, MonoError *error)
{
- MonoError error;
MonoTypeEnum simple_type;
+ mono_error_init (error);
if ((p-buffer) + 10 >= *buflen) {
char *newbuf;
*buflen *= 2;
break;
}
handle_type:
- arg_type = mono_reflection_type_get_handle ((MonoReflectionType*)arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ arg_type = mono_reflection_type_get_handle ((MonoReflectionType*)arg, error);
+ return_if_nok (error);
+
str = type_get_qualified_name (arg_type, NULL);
slen = strlen (str);
if ((p-buffer) + 10 + slen >= *buflen) {
char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
int elsize = mono_class_array_element_size (arg_eclass);
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &arg_eclass->byval_arg, NULL, elptr);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &arg_eclass->byval_arg, NULL, elptr, error);
+ return_if_nok (error);
elptr += elsize;
}
} else if (eclass->valuetype && arg_eclass->valuetype) {
char *elptr = mono_array_addr ((MonoArray*)arg, char, 0);
int elsize = mono_class_array_element_size (eclass);
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, NULL, elptr);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, NULL, elptr, error);
+ return_if_nok (error);
elptr += elsize;
}
} else {
for (i = 0; i < len; ++i) {
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, mono_array_get ((MonoArray*)arg, MonoObject*, i), NULL);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &eclass->byval_arg, mono_array_get ((MonoArray*)arg, MonoObject*, i), NULL, error);
+ return_if_nok (error);
}
}
break;
*p++ = 0x51;
else
*p++ = klass->element_class->byval_arg.type;
- encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &klass->byval_arg, arg, NULL);
+ encode_cattr_value (assembly, buffer, p, &buffer, &p, buflen, &klass->byval_arg, arg, NULL, error);
+ return_if_nok (error);
break;
} else if (klass->byval_arg.type >= MONO_TYPE_BOOLEAN && klass->byval_arg.type <= MONO_TYPE_R8) {
*p++ = simple_type = klass->byval_arg.type;
#ifndef DISABLE_REFLECTION_EMIT
static void
-encode_named_val (MonoReflectionAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, char *name, MonoObject *value)
+encode_named_val (MonoReflectionAssembly *assembly, char *buffer, char *p, char **retbuffer, char **retp, guint32 *buflen, MonoType *type, char *name, MonoObject *value, MonoError *error)
{
int len;
+
+ mono_error_init (error);
+
/* Preallocate a large enough buffer */
if (type->type == MONO_TYPE_VALUETYPE && type->data.klass->enumtype) {
char *str = type_get_qualified_name (type, NULL);
mono_metadata_encode_value (len, p, &p);
memcpy (p, name, len);
p += len;
- encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, buflen, type, value, NULL);
+ encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, buflen, type, value, NULL, error);
+ return_if_nok (error);
*retp = p;
*retbuffer = buffer;
}
-/*
+/**
* mono_reflection_get_custom_attrs_blob:
* @ctor: custom attribute constructor
* @ctorArgs: arguments o the constructor
MonoArray*
mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues)
{
- MonoArray *result;
+ MonoError error;
+ MonoArray *result = mono_reflection_get_custom_attrs_blob_checked (assembly, ctor, ctorArgs, properties, propValues, fields, fieldValues, &error);
+ mono_error_cleanup (&error); /* FIXME better API that doesn't swallow the error */
+ return result;
+}
+
+/**
+ * mono_reflection_get_custom_attrs_blob_checked:
+ * @ctor: custom attribute constructor
+ * @ctorArgs: arguments o the constructor
+ * @properties:
+ * @propValues:
+ * @fields:
+ * @fieldValues:
+ * @error: set on error
+ *
+ * Creates the blob of data that needs to be saved in the metadata and that represents
+ * the custom attributed described by @ctor, @ctorArgs etc.
+ * Returns: a Byte array representing the blob of data. On failure returns NULL and sets @error.
+ */
+MonoArray*
+mono_reflection_get_custom_attrs_blob_checked (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *propValues, MonoArray *fields, MonoArray* fieldValues, MonoError *error)
+{
+ MonoArray *result = NULL;
MonoMethodSignature *sig;
MonoObject *arg;
char *buffer, *p;
guint32 buflen, i;
+ mono_error_init (error);
+
if (strcmp (ctor->vtable->klass->name, "MonoCMethod")) {
/* sig is freed later so allocate it in the heap */
- sig = ctor_builder_to_signature (NULL, (MonoReflectionCtorBuilder*)ctor);
+ sig = ctor_builder_to_signature (NULL, (MonoReflectionCtorBuilder*)ctor, error);
+ if (!is_ok (error)) {
+ g_free (sig);
+ return NULL;
+ }
} else {
sig = mono_method_signature (((MonoReflectionMethod*)ctor)->method);
}
*p++ = 0;
for (i = 0; i < sig->param_count; ++i) {
arg = mono_array_get (ctorArgs, MonoObject*, i);
- encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, &buflen, sig->params [i], arg, NULL);
+ encode_cattr_value (assembly->assembly, buffer, p, &buffer, &p, &buflen, sig->params [i], arg, NULL, error);
+ if (!is_ok (error)) goto leave;
}
i = 0;
if (properties)
char *pname;
prop = (MonoObject *)mono_array_get (properties, gpointer, i);
- get_prop_name_and_type (prop, &pname, &ptype);
+ get_prop_name_and_type (prop, &pname, &ptype, error);
+ if (!is_ok (error)) goto leave;
*p++ = 0x54; /* PROPERTY signature */
- encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ptype, pname, (MonoObject*)mono_array_get (propValues, gpointer, i));
+ encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ptype, pname, (MonoObject*)mono_array_get (propValues, gpointer, i), error);
g_free (pname);
+ if (!is_ok (error)) goto leave;
}
}
char *fname;
field = (MonoObject *)mono_array_get (fields, gpointer, i);
- get_field_name_and_type (field, &fname, &ftype);
+ get_field_name_and_type (field, &fname, &ftype, error);
+ if (!is_ok (error)) goto leave;
*p++ = 0x53; /* FIELD signature */
- encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ftype, fname, (MonoObject*)mono_array_get (fieldValues, gpointer, i));
+ encode_named_val (assembly, buffer, p, &buffer, &p, &buflen, ftype, fname, (MonoObject*)mono_array_get (fieldValues, gpointer, i), error);
g_free (fname);
+ if (!is_ok (error)) goto leave;
}
}
result = mono_array_new (mono_domain_get (), mono_defaults.byte_class, buflen);
p = mono_array_addr (result, char, 0);
memcpy (p, buffer, buflen);
+leave:
g_free (buffer);
if (strcmp (ctor->vtable->klass->name, "MonoCMethod"))
g_free (sig);
return result;
}
-/*
- * mono_reflection_setup_internal_class:
+/**
+ * reflection_setup_internal_class:
* @tb: a TypeBuilder object
+ * @error: set on error
*
* Creates a MonoClass that represents the TypeBuilder.
* This is a trick that lets us simplify a lot of reflection code
* (and will allow us to support Build and Run assemblies easier).
+ *
+ * Returns TRUE on success. On failure, returns FALSE and sets @error.
*/
-void
-mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
+static gboolean
+reflection_setup_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error)
{
- MonoError error;
MonoClass *klass, *parent;
- RESOLVE_TYPE (tb->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_init (error);
+ RESOLVE_TYPE (tb->parent, error);
+ return_val_if_nok (error, FALSE);
mono_loader_lock ();
if (tb->parent) {
- MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, &error);
- if (!is_ok (&error)) {
+ MonoType *parent_type = mono_reflection_type_get_handle ((MonoReflectionType*)tb->parent, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
/* check so we can compile corlib correctly */
if (strcmp (mono_object_class (tb->parent)->name, "TypeBuilder") == 0) {
mono_class_setup_parent (klass, parent);
mono_class_setup_mono_type (klass);
mono_loader_unlock ();
- return;
+ return TRUE;
}
klass = (MonoClass *)mono_image_alloc0 (&tb->module->dynamic_image->image, sizeof (MonoClass));
klass->image = &tb->module->dynamic_image->image;
klass->inited = 1; /* we lie to the runtime */
- klass->name = mono_string_to_utf8_image (klass->image, tb->name, &error);
- if (!mono_error_ok (&error))
+ klass->name = mono_string_to_utf8_image (klass->image, tb->name, error);
+ if (!is_ok (error))
goto failure;
- klass->name_space = mono_string_to_utf8_image (klass->image, tb->nspace, &error);
- if (!mono_error_ok (&error))
+ klass->name_space = mono_string_to_utf8_image (klass->image, tb->nspace, error);
+ if (!is_ok (error))
goto failure;
klass->type_token = MONO_TOKEN_TYPE_DEF | tb->table_idx;
klass->flags = tb->attrs;
if (tb->nesting_type) {
g_assert (tb->nesting_type->type);
- MonoType *nesting_type = mono_reflection_type_get_handle (tb->nesting_type, &error);
- if (!is_ok (&error)) goto failure;
+ MonoType *nesting_type = mono_reflection_type_get_handle (tb->nesting_type, error);
+ if (!is_ok (error)) goto failure;
klass->nested_in = mono_class_from_mono_type (nesting_type);
}
mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
mono_loader_unlock ();
- return;
+ return TRUE;
failure:
mono_loader_unlock ();
- mono_error_raise_exception (&error);
+ return FALSE;
+}
+
+/**
+ * mono_reflection_setup_internal_class:
+ * @tb: a TypeBuilder object
+ *
+ * (icall)
+ * Creates a MonoClass that represents the TypeBuilder.
+ * This is a trick that lets us simplify a lot of reflection code
+ * (and will allow us to support Build and Run assemblies easier).
+ *
+ */
+void
+mono_reflection_setup_internal_class (MonoReflectionTypeBuilder *tb)
+{
+ MonoError error;
+ (void) reflection_setup_internal_class (tb, &error);
+ mono_error_set_pending_exception (&error);
}
/*
klass->generic_container->context.class_inst = mono_get_shared_generic_inst (klass->generic_container);
}
-/*
- * mono_reflection_create_internal_class:
+/**
+ * reflection_create_internal_class:
* @tb: a TypeBuilder object
+ * @error: set on error
*
* Actually create the MonoClass that is associated with the TypeBuilder.
+ * On success returns TRUE, on failure returns FALSE and sets @error.
+ *
*/
-void
-mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
+static gboolean
+reflection_create_internal_class (MonoReflectionTypeBuilder *tb, MonoError *error)
{
- MonoError error;
+
MonoClass *klass;
+ mono_error_init (error);
klass = mono_class_from_mono_type (tb->type.type);
mono_loader_lock ();
fb = mono_array_get (tb->fields, MonoReflectionFieldBuilder*, 0);
- MonoType *field_type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ MonoType *field_type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
if (!mono_type_is_valid_enum_basetype (field_type)) {
mono_loader_unlock ();
- return;
+ return TRUE;
}
- enum_basetype = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ enum_basetype = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
mono_loader_unlock ();
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
klass->element_class = mono_class_from_mono_type (enum_basetype);
if (!klass->element_class)
mono_class_setup_vtable_general (klass, NULL, 0, NULL);
}
mono_loader_unlock ();
+ return TRUE;
+}
+
+/**
+ * mono_reflection_create_internal_class:
+ * @tb: a TypeBuilder object
+ *
+ * (icall)
+ * Actually create the MonoClass that is associated with the TypeBuilder.
+ */
+void
+mono_reflection_create_internal_class (MonoReflectionTypeBuilder *tb)
+{
+ MonoError error;
+ (void) reflection_create_internal_class (tb, &error);
+ mono_error_set_pending_exception (&error);
}
static MonoMarshalSpec*
mono_marshal_spec_from_builder (MonoImage *image, MonoAssembly *assembly,
- MonoReflectionMarshal *minfo)
+ MonoReflectionMarshal *minfo, MonoError *error)
{
- MonoError error;
MonoMarshalSpec *res;
+ mono_error_init (error);
+
res = image_g_new0 (image, MonoMarshalSpec, 1);
res->native = (MonoMarshalNative)minfo->type;
case MONO_NATIVE_CUSTOM:
if (minfo->marshaltyperef) {
- MonoType *marshaltyperef = mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *marshaltyperef = mono_reflection_type_get_handle ((MonoReflectionType*)minfo->marshaltyperef, error);
+ if (!is_ok (error)) {
+ image_g_free (image, res);
+ return NULL;
+ }
res->data.custom_data.custom_name =
type_get_fully_qualified_name (marshaltyperef);
}
if (specs == NULL)
specs = image_g_new0 (image, MonoMarshalSpec*, sig->param_count + 1);
specs [pb->position] =
- mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info);
+ mono_marshal_spec_from_builder (image, klass->image->assembly, pb->marshal_info, &error);
+ if (!is_ok (&error)) {
+ mono_loader_unlock ();
+ image_g_free (image, specs);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ }
}
}
}
MonoMethodSignature *sig;
mono_loader_lock ();
- sig = ctor_builder_to_signature (klass->image, mb);
+ g_assert (klass->image != NULL);
+ sig = ctor_builder_to_signature (klass->image, mb, error);
mono_loader_unlock ();
+ return_val_if_nok (error, NULL);
if (!reflection_methodbuilder_from_ctor_builder (&rmb, mb, error))
return NULL;
mono_error_init (error);
mono_loader_lock ();
- sig = method_builder_to_signature (klass->image, mb);
+ g_assert (klass->image != NULL);
+ sig = method_builder_to_signature (klass->image, mb, error);
mono_loader_unlock ();
+ return_val_if_nok (error, NULL);
if (!reflection_methodbuilder_from_method_builder (&rmb, mb, error))
return NULL;
}
static MonoClassField*
-fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb)
+fieldbuilder_to_mono_class_field (MonoClass *klass, MonoReflectionFieldBuilder* fb, MonoError *error)
{
MonoClassField *field;
MonoType *custom;
- MonoError error;
+
+ mono_error_init (error);
field = g_new0 (MonoClassField, 1);
- field->name = mono_string_to_utf8_image (klass->image, fb->name, &error);
- g_assert (mono_error_ok (&error));
+ field->name = mono_string_to_utf8_image (klass->image, fb->name, error);
+ mono_error_assert_ok (error);
if (fb->attrs || fb->modreq || fb->modopt) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
field->type = mono_metadata_type_dup (NULL, type);
field->type->attrs = fb->attrs;
g_assert (image_is_dynamic (klass->image));
- custom = add_custom_modifiers ((MonoDynamicImage*)klass->image, field->type, fb->modreq, fb->modopt, &error);
+ custom = add_custom_modifiers ((MonoDynamicImage*)klass->image, field->type, fb->modreq, fb->modopt, error);
g_free (field->type);
- if (!is_ok (&error)) {
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
field->type = mono_metadata_type_dup (klass->image, custom);
g_free (custom);
} else {
- field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, &error);
- if (!is_ok (&error)) {
+ field->type = mono_reflection_type_get_handle ((MonoReflectionType*)fb->type, error);
+ if (!is_ok (error)) {
g_free (field);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return NULL;
}
}
if (fb->offset != -1)
}
#endif
+/**
+ * mono_reflection_bind_generic_parameters:
+ * @type: a managed type object (which should be some kind of generic (instance? definition?))
+ * @type_args: the number of type arguments to bind
+ * @types: array of type arguments
+ * @error: set on error
+ *
+ * Given a managed type object for a generic type instance, binds each of its arguments to the specified types.
+ * Returns the MonoType* for the resulting type instantiation. On failure returns NULL and sets @error.
+ */
MonoType*
-mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types)
+mono_reflection_bind_generic_parameters (MonoReflectionType *type, int type_argc, MonoType **types, MonoError *error)
{
- MonoError error;
MonoClass *klass;
MonoReflectionTypeBuilder *tb = NULL;
gboolean is_dynamic = FALSE;
MonoClass *geninst;
+ mono_error_init (error);
+
mono_loader_lock ();
if (is_sre_type_builder (mono_object_class (type))) {
if (tb && tb->generic_container)
mono_reflection_create_generic_class (tb);
- MonoType *t = mono_reflection_type_get_handle (type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *t = mono_reflection_type_get_handle (type, error);
+ if (!is_ok (error)) {
+ mono_loader_unlock ();
+ return NULL;
+ }
klass = mono_class_from_mono_type (t);
if (!klass->generic_container) {
mono_loader_unlock ();
+ mono_error_set_type_load_class (error, klass, "Cannot bind generic parameters of a non-generic type");
return NULL;
}
}
/*TODO avoid saving custom attrs for generic classes as it's enough to have them on the generic type definition.*/
-void
-mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
+static gboolean
+reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields, MonoError *error)
{
- MonoError error;
MonoGenericClass *gclass;
MonoDynamicGenericClass *dgclass;
MonoClass *klass, *gklass;
MonoType *gtype;
int i;
- gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_init (error);
+
+ gtype = mono_reflection_type_get_handle ((MonoReflectionType*)type, error);
+ return_val_if_nok (error, FALSE);
klass = mono_class_from_mono_type (gtype);
g_assert (gtype->type == MONO_TYPE_GENERICINST);
gclass = gtype->data.generic_class;
if (!gclass->is_dynamic)
- return;
+ return TRUE;
dgclass = (MonoDynamicGenericClass *) gclass;
if (dgclass->initialized)
- return;
+ return TRUE;
gklass = gclass->container_class;
mono_class_init (gklass);
dgclass->field_generic_types = mono_image_set_new0 (gclass->owner, MonoType*, dgclass->count_fields);
for (i = 0; i < dgclass->count_fields; i++) {
- MonoError error;
MonoObject *obj = (MonoObject *)mono_array_get (fields, gpointer, i);
MonoClassField *field, *inflated_field = NULL;
- if (!strcmp (obj->vtable->klass->name, "FieldBuilder"))
- inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj);
- else if (!strcmp (obj->vtable->klass->name, "MonoField"))
+ if (!strcmp (obj->vtable->klass->name, "FieldBuilder")) {
+ inflated_field = field = fieldbuilder_to_mono_class_field (klass, (MonoReflectionFieldBuilder *) obj, error);
+ return_val_if_nok (error, FALSE);
+ } else if (!strcmp (obj->vtable->klass->name, "MonoField"))
field = ((MonoReflectionField *) obj)->field;
else {
field = NULL; /* prevent compiler warning */
dgclass->fields [i] = *field;
dgclass->fields [i].parent = klass;
dgclass->fields [i].type = mono_class_inflate_generic_type_checked (
- field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass), &error);
- mono_error_assert_ok (&error); /* FIXME don't swallow the error */
+ field->type, mono_generic_class_get_context ((MonoGenericClass *) dgclass), error);
+ mono_error_assert_ok (error); /* FIXME don't swallow the error */
dgclass->field_generic_types [i] = field->type;
MONO_GC_REGISTER_ROOT_IF_MOVING (dgclass->field_objects [i], MONO_ROOT_SOURCE_REFLECTION, "dynamic generic class field object");
dgclass->field_objects [i] = obj;
}
dgclass->initialized = TRUE;
+ return TRUE;
+}
+
+void
+mono_reflection_generic_class_initialize (MonoReflectionGenericClass *type, MonoArray *fields)
+{
+ MonoError error;
+ (void) reflection_generic_class_initialize (type, fields, &error);
+ mono_error_set_pending_exception (&error);
}
void
}
}
-static void
-fix_partial_generic_class (MonoClass *klass)
+/**
+ * fix_partial_generic_class:
+ * @klass: a generic instantiation MonoClass
+ * @error: set on error
+ *
+ * Assumes that the generic container of @klass has its vtable
+ * initialized, and updates the parent class, insterfaces, methods and
+ * fields of @klass by inflating the types using the generic context.
+ *
+ * On success returns TRUE, on failure returns FALSE and sets @error.
+ *
+ */
+static gboolean
+fix_partial_generic_class (MonoClass *klass, MonoError *error)
{
MonoClass *gklass = klass->generic_class->container_class;
MonoDynamicGenericClass *dgclass;
int i;
+ mono_error_init (error);
+
if (klass->wastypebuilder)
- return;
+ return TRUE;
dgclass = (MonoDynamicGenericClass *) klass->generic_class;
if (klass->parent != gklass->parent) {
- MonoError error;
- MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &klass->generic_class->context, &error);
- if (mono_error_ok (&error)) {
+ MonoType *parent_type = mono_class_inflate_generic_type_checked (&gklass->parent->byval_arg, &klass->generic_class->context, error);
+ if (mono_error_ok (error)) {
MonoClass *parent = mono_class_from_mono_type (parent_type);
mono_metadata_free_type (parent_type);
if (parent != klass->parent) {
mono_class_setup_parent (klass, parent);
}
} else {
- mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- mono_error_cleanup (&error);
if (gklass->wastypebuilder)
klass->wastypebuilder = TRUE;
- return;
+ return FALSE;
}
}
if (!dgclass->initialized)
- return;
+ return TRUE;
if (klass->method.count != gklass->method.count) {
klass->method.count = gklass->method.count;
klass->methods = (MonoMethod **)mono_image_alloc (klass->image, sizeof (MonoMethod*) * (klass->method.count + 1));
for (i = 0; i < klass->method.count; i++) {
- MonoError error;
klass->methods [i] = mono_class_inflate_generic_method_full_checked (
- gklass->methods [i], klass, mono_class_get_context (klass), &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ gklass->methods [i], klass, mono_class_get_context (klass), error);
+ mono_error_assert_ok (error);
}
}
klass->interfaces_packed = NULL; /*make setup_interface_offsets happy*/
for (i = 0; i < gklass->interface_count; ++i) {
- MonoError error;
- MonoType *iface_type = mono_class_inflate_generic_type_checked (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass), &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *iface_type = mono_class_inflate_generic_type_checked (&gklass->interfaces [i]->byval_arg, mono_class_get_context (klass), error);
+ return_val_if_nok (error, FALSE);
klass->interfaces [i] = mono_class_from_mono_type (iface_type);
mono_metadata_free_type (iface_type);
- ensure_runtime_vtable (klass->interfaces [i], &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!ensure_runtime_vtable (klass->interfaces [i], error))
+ return FALSE;
}
klass->interfaces_inited = 1;
}
klass->fields = image_g_new0 (klass->image, MonoClassField, klass->field.count);
for (i = 0; i < klass->field.count; i++) {
- MonoError error;
klass->fields [i] = gklass->fields [i];
klass->fields [i].parent = klass;
- klass->fields [i].type = mono_class_inflate_generic_type_checked (gklass->fields [i].type, mono_class_get_context (klass), &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ klass->fields [i].type = mono_class_inflate_generic_type_checked (gklass->fields [i].type, mono_class_get_context (klass), error);
+ return_val_if_nok (error, FALSE);
}
}
/*We can only finish with this klass once it's parent has as well*/
if (gklass->wastypebuilder)
klass->wastypebuilder = TRUE;
- return;
+ return TRUE;
}
/**
if (!ensure_runtime_vtable (gklass, error))
return FALSE;
- fix_partial_generic_class (klass);
-
- return TRUE;
+ return fix_partial_generic_class (klass, error);
}
/**
klass->interfaces_inited = 1;
}
} else if (klass->generic_class){
- if (!ensure_generic_class_runtime_vtable (klass, error))
+ if (!ensure_generic_class_runtime_vtable (klass, error)) {
+ mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
return FALSE;
+ }
}
if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
}
static MonoMethod*
-mono_reflection_method_get_handle (MonoObject *method)
+mono_reflection_method_get_handle (MonoObject *method, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
MonoClass *klass = mono_object_class (method);
if (is_sr_mono_method (klass) || is_sr_mono_generic_method (klass)) {
MonoReflectionMethod *sr_method = (MonoReflectionMethod*)method;
MonoMethod *result;
/*FIXME move this to a proper method and unify with resolve_object*/
if (m->method_args) {
- result = mono_reflection_method_on_tb_inst_get_handle (m, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_reflection_method_on_tb_inst_get_handle (m, error);
} else {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *mono_method;
}
void
-mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
+mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error)
{
MonoReflectionTypeBuilder *tb;
int i, j, onum;
MonoReflectionMethod *m;
+ mono_error_init (error);
*overrides = NULL;
*num_overrides = 0;
for (j = 0; j < mono_array_length (mb->override_methods); ++j) {
m = mono_array_get (mb->override_methods, MonoReflectionMethod*, j);
- (*overrides) [onum * 2] = mono_reflection_method_get_handle ((MonoObject*)m);
+ (*overrides) [onum * 2] = mono_reflection_method_get_handle ((MonoObject*)m, error);
+ return_if_nok (error);
(*overrides) [onum * 2 + 1] = mb->mhandle;
g_assert (mb->mhandle);
}
}
-MonoReflectionEvent *
-mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
+static MonoReflectionEvent *
+reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
+
MonoEvent *event = g_new0 (MonoEvent, 1);
MonoClass *klass;
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
+ if (!is_ok (error)) {
+ g_free (event);
+ return NULL;
+ }
klass = mono_class_from_mono_type (type);
event->parent = klass;
}
#endif
- MonoReflectionEvent *ev_obj = mono_event_get_object_checked (mono_object_domain (tb), klass, event, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoReflectionEvent *ev_obj = mono_event_get_object_checked (mono_object_domain (tb), klass, event, error);
+ if (!is_ok (error)) {
+#ifndef MONO_SMALL_CONFIG
+ g_free (event->other);
+#endif
+ g_free (event);
+ return NULL;
+ }
return ev_obj;
}
+MonoReflectionEvent *
+mono_reflection_event_builder_get_event_info (MonoReflectionTypeBuilder *tb, MonoReflectionEventBuilder *eb)
+{
+ MonoError error;
+ MonoReflectionEvent *result = reflection_event_builder_get_event_info (tb, eb, &error);
+ mono_error_set_pending_exception (&error);
+ return result;
+}
+
static void
typebuilder_setup_events (MonoClass *klass, MonoError *error)
{
}
}
+struct remove_instantiations_user_data
+{
+ MonoClass *klass;
+ MonoError *error;
+};
+
static gboolean
remove_instantiations_of_and_ensure_contents (gpointer key,
gpointer value,
gpointer user_data)
{
+ struct remove_instantiations_user_data *data = (struct remove_instantiations_user_data*)user_data;
MonoType *type = (MonoType*)key;
- MonoClass *klass = (MonoClass*)user_data;
+ MonoClass *klass = data->klass;
+ gboolean already_failed = !is_ok (data->error);
+ MonoError lerror;
+ MonoError *error = already_failed ? &lerror : data->error;
if ((type->type == MONO_TYPE_GENERICINST) && (type->data.generic_class->container_class == klass)) {
- fix_partial_generic_class (mono_class_from_mono_type (type)); //Ensure it's safe to use it.
+ MonoClass *inst_klass = mono_class_from_mono_type (type);
+ //Ensure it's safe to use it.
+ if (!fix_partial_generic_class (inst_klass, error)) {
+ mono_class_set_failure (inst_klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
+ // Marked the class with failure, but since some other instantiation already failed,
+ // just report that one, and swallow the error from this one.
+ if (already_failed)
+ mono_error_cleanup (error);
+ }
return TRUE;
} else
return FALSE;
MonoReflectionType* res;
int i, j;
+ mono_error_init (&error);
+
domain = mono_object_domain (tb);
klass = mono_class_from_mono_type (tb->type.type);
* Check for user defined Type subclasses.
*/
RESOLVE_TYPE (tb->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (tb->interfaces, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (tb->fields) {
for (i = 0; i < mono_array_length (tb->fields); ++i) {
MonoReflectionFieldBuilder *fb = (MonoReflectionFieldBuilder *)mono_array_get (tb->fields, gpointer, i);
if (fb) {
RESOLVE_TYPE (fb->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (fb->modreq, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (fb->modopt, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (fb->marshal_info && fb->marshal_info->marshaltyperef) {
RESOLVE_TYPE (fb->marshal_info->marshaltyperef, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
MonoReflectionMethodBuilder *mb = (MonoReflectionMethodBuilder *)mono_array_get (tb->methods, gpointer, i);
if (mb) {
RESOLVE_TYPE (mb->rtype, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->return_modreq, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->return_modopt, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
check_array_for_usertypes (mb->parameters, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (mb->param_modreq)
for (j = 0; j < mono_array_length (mb->param_modreq); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
if (mb->param_modopt)
for (j = 0; j < mono_array_length (mb->param_modopt); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
MonoReflectionCtorBuilder *mb = (MonoReflectionCtorBuilder *)mono_array_get (tb->ctors, gpointer, i);
if (mb) {
check_array_for_usertypes (mb->parameters, &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
if (mb->param_modreq)
for (j = 0; j < mono_array_length (mb->param_modreq); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modreq, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
if (mb->param_modopt)
for (j = 0; j < mono_array_length (mb->param_modopt); ++j) {
check_array_for_usertypes (mono_array_get (mb->param_modopt, MonoArray*, j), &error);
- mono_error_raise_exception (&error); /*FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
}
}
}
mono_loader_unlock ();
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_set_pending_exception (&error);
return res;
}
mono_domain_unlock (domain);
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_error_set_pending_exception (&error);
return res;
}
*
* Together with this we must ensure the contents of all instances to match the created type.
*/
- if (domain->type_hash && klass->generic_container)
- mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of_and_ensure_contents, klass);
+ if (domain->type_hash && klass->generic_container) {
+ struct remove_instantiations_user_data data;
+ data.klass = klass;
+ data.error = &error;
+ mono_error_assert_ok (&error);
+ mono_g_hash_table_foreach_remove (domain->type_hash, remove_instantiations_of_and_ensure_contents, &data);
+ if (!is_ok (&error))
+ goto failure;
+ }
mono_domain_unlock (domain);
mono_loader_unlock ();
if (klass->enumtype && !mono_class_is_valid_enum (klass)) {
mono_class_set_failure (klass, MONO_EXCEPTION_TYPE_LOAD, NULL);
- mono_raise_exception (mono_get_exception_type_load (tb->name, NULL));
+ mono_error_set_type_load_class (&error, klass, "Not a valid enumeration");
+ goto failure_unlocked;
}
res = mono_type_get_object_checked (mono_object_domain (tb), &klass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ if (!is_ok (&error))
+ goto failure_unlocked;
g_assert (res != (MonoReflectionType*)tb);
klass->wastypebuilder = TRUE;
mono_domain_unlock (domain);
mono_loader_unlock ();
- mono_error_raise_exception (&error);
+failure_unlocked:
+ mono_error_set_pending_exception (&error);
return NULL;
}
-void
-mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
+static gboolean
+reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam, MonoError *error)
{
MonoGenericParamFull *param;
MonoImage *image;
MonoClass *pklass;
- MonoError error;
+
+ mono_error_init (error);
image = &gparam->tbuilder->module->dynamic_image->image;
param = mono_image_new0 (image, MonoGenericParamFull, 1);
- param->info.name = mono_string_to_utf8_image (image, gparam->name, &error);
- g_assert (mono_error_ok (&error));
+ param->info.name = mono_string_to_utf8_image (image, gparam->name, error);
+ mono_error_assert_ok (error);
param->param.num = gparam->index;
if (gparam->mbuilder) {
if (!gparam->mbuilder->generic_container) {
- MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->mbuilder->type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->mbuilder->type, error);
+ return_val_if_nok (error, FALSE);
MonoClass *klass = mono_class_from_mono_type (tb);
gparam->mbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
param->param.owner = gparam->mbuilder->generic_container;
} else if (gparam->tbuilder) {
if (!gparam->tbuilder->generic_container) {
- MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *tb = mono_reflection_type_get_handle ((MonoReflectionType*)gparam->tbuilder, error);
+ return_val_if_nok (error, FALSE);
MonoClass *klass = mono_class_from_mono_type (tb);
gparam->tbuilder->generic_container = (MonoGenericContainer *)mono_image_alloc0 (klass->image, sizeof (MonoGenericContainer));
gparam->tbuilder->generic_container->owner.klass = klass;
mono_class_set_ref_info (pklass, gparam);
mono_image_append_class_to_reflection_info_set (pklass);
+
+ return TRUE;
}
+void
+mono_reflection_initialize_generic_parameter (MonoReflectionGenericParam *gparam)
+{
+ MonoError error;
+ (void) reflection_initialize_generic_parameter (gparam, &error);
+ mono_error_set_pending_exception (&error);
+}
+
+
MonoArray *
mono_reflection_sighelper_get_signature_local (MonoReflectionSigHelper *sig)
{
g_free (data);
}
-void
-mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
+static gboolean
+reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb, MonoError *error)
{
- MonoError error;
MonoReferenceQueue *queue;
MonoMethod *handle;
DynamicMethodReleaseData *release_data;
GSList *l;
int i;
- if (mono_runtime_is_shutting_down ())
- mono_raise_exception (mono_get_exception_invalid_operation (""));
+ mono_error_init (error);
+
+ if (mono_runtime_is_shutting_down ()) {
+ mono_error_set_generic_error (error, "System", "InvalidOperationException", "");
+ return FALSE;
+ }
if (!(queue = dynamic_method_queue)) {
mono_loader_lock ();
mono_loader_unlock ();
}
- sig = dynamic_method_to_signature (mb);
+ sig = dynamic_method_to_signature (mb, error);
+ return_val_if_nok (error, FALSE);
reflection_methodbuilder_from_dynamic_method (&rmb, mb);
handle_class = mono_defaults.methodhandle_class;
} else {
MonoException *ex = NULL;
- ref = resolve_object (mb->module->image, obj, &handle_class, NULL);
+ ref = resolve_object (mb->module->image, obj, &handle_class, NULL, error);
+ if (!is_ok (error)) {
+ g_free (rmb.refs);
+ return FALSE;
+ }
if (!ref)
ex = mono_get_exception_type_load (NULL, NULL);
else if (mono_security_core_clr_enabled ())
if (ex) {
g_free (rmb.refs);
- mono_raise_exception (ex);
- return;
+ mono_error_set_exception_instance (error, ex);
+ return FALSE;
}
}
}
if (mb->owner) {
- MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, &error);
- if (!is_ok (&error)) {
+ MonoType *owner_type = mono_reflection_type_get_handle ((MonoReflectionType*)mb->owner, error);
+ if (!is_ok (error)) {
g_free (rmb.refs);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return FALSE;
}
klass = mono_class_from_mono_type (owner_type);
} else {
domain->method_to_dyn_method = g_hash_table_new (NULL, NULL);
g_hash_table_insert (domain->method_to_dyn_method, handle, (gpointer)(size_t)mono_gchandle_new_weakref ((MonoObject *)mb, TRUE));
mono_domain_unlock (domain);
+
+ return TRUE;
+}
+
+void
+mono_reflection_create_dynamic_method (MonoReflectionDynamicMethod *mb)
+{
+ MonoError error;
+ (void) reflection_create_dynamic_method (mb, &error);
+ mono_error_set_pending_exception (&error);
}
#endif /* DISABLE_REFLECTION_EMIT */
gpointer
mono_reflection_lookup_dynamic_token (MonoImage *image, guint32 token, gboolean valid_token, MonoClass **handle_class, MonoGenericContext *context)
{
+ MonoError error;
MonoDynamicImage *assembly = (MonoDynamicImage*)image;
MonoObject *obj;
MonoClass *klass;
if (!handle_class)
handle_class = &klass;
- return resolve_object (image, obj, handle_class, context);
+ gpointer result = resolve_object (image, obj, handle_class, context, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
+ return result;
}
/*
* dynamic types.
*/
static void
-ensure_complete_type (MonoClass *klass)
+ensure_complete_type (MonoClass *klass, MonoError *error)
{
- MonoError error;
+ mono_error_init (error);
if (image_is_dynamic (klass->image) && !klass->wastypebuilder && mono_class_get_ref_info (klass)) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder *)mono_class_get_ref_info (klass);
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_if_nok (error);
// Asserting here could break a lot of code
//g_assert (klass->wastypebuilder);
int i;
for (i = 0; i < inst->type_argc; ++i) {
- ensure_complete_type (mono_class_from_mono_type (inst->type_argv [i]));
+ ensure_complete_type (mono_class_from_mono_type (inst->type_argv [i]), error);
+ return_if_nok (error);
}
}
}
static gpointer
-resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context)
+resolve_object (MonoImage *image, MonoObject *obj, MonoClass **handle_class, MonoGenericContext *context, MonoError *error)
{
- MonoError error;
gpointer result = NULL;
+ mono_error_init (error);
+
if (strcmp (obj->vtable->klass->name, "String") == 0) {
- result = mono_string_intern_checked ((MonoString*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_string_intern_checked ((MonoString*)obj, error);
+ return_val_if_nok (error, NULL);
*handle_class = mono_defaults.string_class;
g_assert (result);
} else if (strcmp (obj->vtable->klass->name, "MonoType") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
MonoClass *mc = mono_class_from_mono_type (type);
- if (!mono_class_init (mc))
- mono_raise_exception (mono_class_get_exception_for_failure (mc));
+ if (!mono_class_init (mc)) {
+ mono_error_set_exception_instance (error, mono_class_get_exception_for_failure (mc));
+ return NULL;
+ }
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
strcmp (obj->vtable->klass->name, "MonoGenericMethod") == 0) {
result = ((MonoReflectionMethod*)obj)->method;
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
g_assert (result);
/* Type is not yet created */
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)mb->type;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
/*
* Hopefully this has been filled in by calling CreateType() on the
result = mb->mhandle;
}
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "ConstructorBuilder") == 0) {
if (!result) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)cb->type;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = cb->mhandle;
}
if (context) {
- MonoError error;
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- g_assert (mono_error_ok (&error)); /* FIXME don't swallow the error */
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "MonoField") == 0) {
MonoClassField *field = ((MonoReflectionField*)obj)->field;
- ensure_complete_type (field->parent);
+ ensure_complete_type (field->parent, error);
+ return_val_if_nok (error, NULL);
+
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (&field->parent->byval_arg, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *klass = mono_class_from_mono_type (inflated);
MonoClassField *inflated_field;
if (!result) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)fb->typeb;
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = fb->handle;
}
if (fb->handle && fb->handle->parent->generic_container) {
MonoClass *klass = fb->handle->parent;
- MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_class_inflate_generic_type_checked (&klass->byval_arg, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated = mono_class_from_mono_type (type);
*handle_class = mono_defaults.fieldhandle_class;
} else if (strcmp (obj->vtable->klass->name, "TypeBuilder") == 0) {
MonoReflectionTypeBuilder *tb = (MonoReflectionTypeBuilder*)obj;
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)tb, error);
+ return_val_if_nok (error, NULL);
MonoClass *klass;
klass = type->data.klass;
result = klass;
}
else {
- mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mono_domain_try_type_resolve_checked (mono_domain_get (), NULL, (MonoObject*)tb, error);
+ return_val_if_nok (error, NULL);
result = type->data.klass;
g_assert (result);
}
/* TODO: Copy type ? */
sig->ret = helper->return_type->type;
for (i = 0; i < nargs; ++i) {
- sig->params [i] = mono_type_array_get_and_resolve (helper->arguments, i, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ sig->params [i] = mono_type_array_get_and_resolve (helper->arguments, i, error);
+ if (!is_ok (error)) {
+ image_g_free (image, sig);
+ return NULL;
+ }
}
result = sig;
result = method->mhandle;
*handle_class = mono_defaults.methodhandle_class;
} else if (strcmp (obj->vtable->klass->name, "GenericTypeParameterBuilder") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (type);
*handle_class = mono_defaults.typehandle_class;
g_assert (result);
mono_metadata_free_type (type);
} else if (strcmp (obj->vtable->klass->name, "MonoGenericClass") == 0) {
- MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle ((MonoReflectionType*)obj, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (type);
*handle_class = mono_defaults.typehandle_class;
else
g_error ("resolve_object:: can't handle a FTBI with base_method of type %s", mono_type_get_full_name (mono_object_class (f->fb)));
- MonoType *finst = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- type = mono_class_inflate_generic_type_checked (finst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *finst = mono_reflection_type_get_handle ((MonoReflectionType*)f->inst, error);
+ return_val_if_nok (error, NULL);
+ type = mono_class_inflate_generic_type_checked (finst, context, error);
+ return_val_if_nok (error, NULL);
inflated = mono_class_from_mono_type (type);
result = field = mono_class_get_field_from_name (inflated, mono_field_get_name (field));
- ensure_complete_type (field->parent);
+ ensure_complete_type (field->parent, error);
+ if (!is_ok (error)) {
+ mono_metadata_free_type (type);
+ return NULL;
+ }
+
g_assert (result);
mono_metadata_free_type (type);
*handle_class = mono_defaults.fieldhandle_class;
} else if (strcmp (obj->vtable->klass->name, "ConstructorOnTypeBuilderInst") == 0) {
MonoReflectionCtorOnTypeBuilderInst *c = (MonoReflectionCtorOnTypeBuilderInst*)obj;
- MonoType *cinst = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- MonoType *type = mono_class_inflate_generic_type_checked (cinst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *cinst = mono_reflection_type_get_handle ((MonoReflectionType*)c->inst, error);
+ return_val_if_nok (error, NULL);
+ MonoType *type = mono_class_inflate_generic_type_checked (cinst, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *method;
} else if (strcmp (obj->vtable->klass->name, "MethodOnTypeBuilderInst") == 0) {
MonoReflectionMethodOnTypeBuilderInst *m = (MonoReflectionMethodOnTypeBuilderInst*)obj;
if (m->method_args) {
- result = mono_reflection_method_on_tb_inst_get_handle (m, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ result = mono_reflection_method_on_tb_inst_get_handle (m, error);
+ return_val_if_nok (error, NULL);
if (context) {
- result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, &error);
- mono_error_assert_ok (&error);
+ result = mono_class_inflate_generic_method_checked ((MonoMethod *)result, context, error);
+ mono_error_assert_ok (error);
}
} else {
- MonoType *minst = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
- MonoType *type = mono_class_inflate_generic_type_checked (minst, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *minst = mono_reflection_type_get_handle ((MonoReflectionType*)m->inst, error);
+ return_val_if_nok (error, NULL);
+ MonoType *type = mono_class_inflate_generic_type_checked (minst, context, error);
+ return_val_if_nok (error, NULL);
MonoClass *inflated_klass = mono_class_from_mono_type (type);
MonoMethod *method;
gpointer iter;
char *name;
- mtype = mono_reflection_type_get_handle (m->parent, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ mtype = mono_reflection_type_get_handle (m->parent, error);
+ return_val_if_nok (error, NULL);
klass = mono_class_from_mono_type (mtype);
/* Find the method */
is_sre_byref (mono_object_get_class(obj)) ||
is_sre_pointer (mono_object_get_class(obj))) {
MonoReflectionType *ref_type = (MonoReflectionType *)obj;
- MonoType *type = mono_reflection_type_get_handle (ref_type, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *type = mono_reflection_type_get_handle (ref_type, error);
+ return_val_if_nok (error, NULL);
if (context) {
- MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ MonoType *inflated = mono_class_inflate_generic_type_checked (type, context, error);
+ return_val_if_nok (error, NULL);
result = mono_class_from_mono_type (inflated);
mono_metadata_free_type (inflated);
}
void
-mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides)
+mono_reflection_get_dynamic_overrides (MonoClass *klass, MonoMethod ***overrides, int *num_overrides, MonoError *error)
{
+ mono_error_init (error);
*overrides = NULL;
*num_overrides = 0;
}
}
gboolean
-mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass)
+mono_reflection_call_is_assignable_to (MonoClass *klass, MonoClass *oklass, MonoError *error)
{
- MonoError error;
MonoObject *res, *exc;
void *params [1];
static MonoMethod *method = NULL;
+ mono_error_init (error);
+
if (method == NULL) {
method = mono_class_get_method_from_name (mono_class_get_type_builder_class (), "IsAssignableTo", 1);
g_assert (method);
g_assert (mono_class_get_ref_info (klass));
g_assert (!strcmp (((MonoObject*)(mono_class_get_ref_info (klass)))->vtable->klass->name, "TypeBuilder"));
- params [0] = mono_type_get_object_checked (mono_domain_get (), &oklass->byval_arg, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ params [0] = mono_type_get_object_checked (mono_domain_get (), &oklass->byval_arg, error);
+ return_val_if_nok (error, FALSE);
- res = mono_runtime_try_invoke (method, (MonoObject*)(mono_class_get_ref_info (klass)), params, &exc, &error);
+ res = mono_runtime_try_invoke (method, (MonoObject*)(mono_class_get_ref_info (klass)), params, &exc, error);
- if (exc || !mono_error_ok (&error)) {
- mono_error_cleanup (&error);
+ if (exc || !mono_error_ok (error)) {
+ mono_error_cleanup (error);
return FALSE;
} else
return *(MonoBoolean*)mono_object_unbox (res);
MONO_API MonoArray* mono_reflection_get_custom_attrs (MonoObject *obj);
MONO_RT_EXTERNAL_ONLY
MONO_API MonoArray* mono_reflection_get_custom_attrs_data (MonoObject *obj);
+MONO_RT_EXTERNAL_ONLY
MONO_API MonoArray* mono_reflection_get_custom_attrs_blob (MonoReflectionAssembly *assembly, MonoObject *ctor, MonoArray *ctorArgs, MonoArray *properties, MonoArray *porpValues, MonoArray *fields, MonoArray* fieldValues);
MONO_RT_EXTERNAL_ONLY
bridge_callbacks = *callbacks;
if (!bridge_processor.reset_data)
- sgen_old_bridge_init (&bridge_processor);
+ sgen_new_bridge_init (&bridge_processor);
}
static gboolean
count=100000
mtest=for_loop
monodir=$(top_builddir)
+mono=$(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),mono)
+
+if HOST_WIN32
+PLATFORM_PATH_SEPARATOR=;
+else
+PLATFORM_PATH_SEPARATOR=:
+endif
# This is needed for automake dependency generation
libgc_libs=$(monodir)/libgc/libmonogc.la
RUNTIME_EXECUTABLE = $(if $(BOEHM),$(top_builddir)/mono/mini/mono-boehm,$(top_builddir)/runtime/mono-wrapper)
MINI_RUNTIME = MONO_PATH=$(CLASS) $(RUNTIME_EXECUTABLE)
-RUNTIME_AOTCHECK = MONO_PATH=$(CLASS):. $(RUNTIME_EXECUTABLE)
+RUNTIME_AOTCHECK = MONO_PATH="$(CLASS)$(PLATFORM_PATH_SEPARATOR)." $(RUNTIME_EXECUTABLE)
MCS = $(MINI_RUNTIME) $(mcs_topdir)/class/lib/build/mcs.exe -unsafe -nowarn:0162
ILASM = $(MINI_RUNTIME) $(CLASS)/ilasm.exe
Mono.Simd.dll
# This currently only works on amd64/arm
-fullaotcheck: mono $(fullaot_regtests)
+fullaotcheck: $(mono) $(fullaot_regtests)
rm -rf fullaot-tmp
mkdir fullaot-tmp
$(MAKE) fullaot-libs AOT_FLAGS=full GSHAREDVT=$(GSHAREDVT)
cp $(regtests) $(fullaot_regtests) generics-variant-types.dll TestDriver.dll fullaot-tmp/
MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper $(LLVM_AOT_RUNTIME_OPTS) $(GSHAREDVT_RUNTIME_OPTS) --aot=full fullaot-tmp/{generics-variant-types.dll,TestDriver.dll,*.exe} || exit 1
- ln -s $$PWD/mono fullaot-tmp/
+ ln -s $(if $(MONO_EXECUTABLE),$(MONO_EXECUTABLE),$$PWD/mono) fullaot-tmp/
for i in $(fullaot_regtests); do echo $$i; MONO_PATH=fullaot-tmp $(top_builddir)/runtime/mono-wrapper --full-aot fullaot-tmp/$$i --exclude '!FULLAOT' $(ARCH_FULLAOT_EXCLUDE) || exit 1; done
# This can run in parallel
fullaot-tmp/%.dylib: $(CLASS)/%
cp $(CLASS)/$* fullaot-tmp/
mkdir fullaot-tmp/$*-tmp
- MONO_PATH=fullaot-tmp/:$(CLASS) $(top_builddir)/runtime/mono-wrapper $(if $(GSHAREDVT),-O=gsharedvt) --aot=$(AOT_FLAGS),temp-path=fullaot-tmp/$*-tmp fullaot-tmp/$*
+ MONO_PATH="fullaot-tmp/$(PLATFORM_PATH_SEPARATOR)$(CLASS)" $(top_builddir)/runtime/mono-wrapper $(if $(GSHAREDVT),-O=gsharedvt) --aot=$(AOT_FLAGS),temp-path=fullaot-tmp/$*-tmp fullaot-tmp/$*
rm -rf fullaot-tmp/$*-tmp
llvmfullaotcheck:
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
g_free (err);
- aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, g_path_get_basename (assembly->image->name), MONO_SOLIB_EXT);
+ g_free (aot_name);
+ char *basename = g_path_get_basename (assembly->image->name);
+ aot_name = g_strdup_printf ("%s/mono/aot-cache/%s/%s%s", mono_assembly_getrootdir(), MONO_ARCHITECTURE, basename, MONO_SOLIB_EXT);
+ g_free (basename);
sofile = mono_dl_open (aot_name, MONO_DL_LAZY, &err);
if (!sofile) {
mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_AOT, "AOT module '%s' not found: %s\n", aot_name, err);
return 0;
}
+ interface ISmallArg {
+ T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
+ string s9, string s10, string s11, string s12, string s13, T t);
+ }
+
+ class SmallArgClass : ISmallArg {
+ public T foo<T> (string s1, string s2, string s3, string s4, string s5, string s6, string s7, string s8,
+ string s9, string s10, string s11, string s12, string s13, T t) {
+ return t;
+ }
+ }
+
+ public static int test_1_small_gsharedvt_stack_arg_ios () {
+ ISmallArg o = new SmallArgClass ();
+ return o.foo<int> ("", "", "", "", "", "", "", "", "", "", "", "", "", 1);
+ }
+
// Passing vtype normal arguments on the stack
public static int test_0_arm64_vtype_stack_args () {
IFoo3<EmptyStruct> o = (IFoo3<EmptyStruct>)Activator.CreateInstance (typeof (Foo3<>).MakeGenericType (new Type [] { typeof (EmptyStruct) }));
INLINE_FAILURE ("class init");
if (!mono_runtime_class_init_full (vtable, &cfg->error)) {
mono_cfg_set_exception (cfg, MONO_EXCEPTION_MONO_ERROR);
- g_assert_not_reached ();
goto exception_exit;
}
}
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER4_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
} else {
int creg;
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, creg, ARMREG_SP, (cfg->param_area - 8));
/* This should work for soft-float as well */
+ cfg->param_area = MAX (cfg->param_area, 8);
MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORER8_MEMBASE_REG, ARMREG_SP, (cfg->param_area - 8), in->dreg);
creg = mono_alloc_ireg (cfg);
mono_call_inst_add_outarg_reg (cfg, call, creg, ARMREG_R3, FALSE);
#define __STDC_CONSTANT_MACROS
#endif
-#include "llvm-c/Core.h"
-#include "llvm-c/ExecutionEngine.h"
#include "llvm-c/BitWriter.h"
#include "llvm-c/Analysis.h"
MonoVTable *vtable;
mono_jit_stats.methods_lookups++;
- vtable = mono_class_vtable (domain, method->klass);
+ vtable = mono_class_vtable_full (domain, method->klass, error);
+ if (!is_ok (error))
+ return NULL;
g_assert (vtable);
if (!mono_runtime_class_init_full (vtable, error))
return NULL;
return del (42);
}
+typedef char* (STDCALL *IcallDelegate) (const char *);
+LIBTEST_API int STDCALL
+mono_test_marshal_icall_delegate (IcallDelegate del)
+{
+ char *res = del ("ABC");
+ return strcmp (res, "ABC") == 0 ? 0 : 1;
+}
+
LIBTEST_API int STDCALL
mono_test_marshal_stringbuilder (char *s, int n)
{
[DllImport ("libtest", EntryPoint="mono_test_marshal_virtual_delegate")]
public static extern int mono_test_marshal_virtual_delegate (VirtualDelegate del);
+ [DllImport ("libtest", EntryPoint="mono_test_marshal_icall_delegate")]
+ public static extern int mono_test_marshal_icall_delegate (IcallDelegate del);
+
+ public delegate string IcallDelegate (IntPtr p);
+
public delegate int TestDelegate (int a, ref SimpleStruct ss, int b);
public delegate SimpleStruct SimpleDelegate2 (SimpleStruct ss);
return mono_test_marshal_virtual_delegate (b.get_del ());
}
+
+ public static int test_0_icall_delegate () {
+ var m = typeof (Marshal).GetMethod ("PtrToStringAnsi", new Type[] { typeof (IntPtr) });
+
+ return mono_test_marshal_icall_delegate ((IcallDelegate)Delegate.CreateDelegate (typeof (IcallDelegate), m));
+ }
}
*/
#include <config.h>
-#ifdef CHECKED_BUILD
+#ifdef ENABLE_CHECKED_BUILD
#include <mono/utils/checked-build.h>
#include <mono/utils/mono-threads.h>
#include <execinfo.h>
#endif
+// Selective-enable support
+
+// Returns true for check modes which are allowed by both the current DISABLE_ macros and the MONO_CHECK_MODE env var.
+// Argument may be a bitmask; if so, result is true if at least one specified mode is enabled.
+mono_bool
+mono_check_mode_enabled (MonoCheckMode query)
+{
+ static MonoCheckMode check_mode = MONO_CHECK_MODE_UNKNOWN;
+ if (G_UNLIKELY (check_mode == MONO_CHECK_MODE_UNKNOWN))
+ {
+ MonoCheckMode env_check_mode = MONO_CHECK_MODE_NONE;
+ const gchar *env_string = g_getenv ("MONO_CHECK_MODE");
+
+ if (env_string)
+ {
+ gchar **env_split = g_strsplit (env_string, ",", 0);
+ for (gchar **env_component = env_split; *env_component; env_component++)
+ {
+ mono_bool check_all = g_str_equal (*env_component, "all");
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (check_all || g_str_equal (*env_component, "gc"))
+ env_check_mode |= MONO_CHECK_MODE_GC;
+#endif
+#ifdef ENABLE_CHECKED_BUILD_METADATA
+ if (check_all || g_str_equal (*env_component, "metadata"))
+ env_check_mode |= MONO_CHECK_MODE_METADATA;
+#endif
+#ifdef ENABLE_CHECKED_BUILD_THREAD
+ if (check_all || g_str_equal (*env_component, "thread"))
+ env_check_mode |= MONO_CHECK_MODE_THREAD;
+#endif
+ }
+ g_strfreev (env_split);
+ }
+
+ check_mode = env_check_mode;
+ }
+ return check_mode & query;
+}
+
+static int
+mono_check_transition_limit (void)
+{
+ static int transition_limit = -1;
+ if (transition_limit < 0) {
+ const gchar *env_string = g_getenv ("MONO_CHECK_THREAD_TRANSITION_HISTORY");
+ if (env_string)
+ transition_limit = atoi (env_string);
+ else
+ transition_limit = 3;
+ }
+ return transition_limit;
+}
+
typedef struct {
GPtrArray *transitions;
guint32 in_gc_critical_region;
void
checked_build_init (void)
{
- mono_native_tls_alloc (&thread_status, NULL);
+ // Init state for get_state, which can be called either by gc or thread mode
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC | MONO_CHECK_MODE_THREAD))
+ mono_native_tls_alloc (&thread_status, NULL);
}
static CheckState*
return state;
}
-#if !defined(DISABLE_CHECKED_BUILD_THREAD)
+#ifdef ENABLE_CHECKED_BUILD_THREAD
#define MAX_NATIVE_BT 6
#define MAX_NATIVE_BT_PROBE (MAX_NATIVE_BT + 5)
-#define MAX_TRANSITIONS 3
+#define MAX_TRANSITIONS (mono_check_transition_limit ())
#ifdef HAVE_BACKTRACE_SYMBOLS
void
checked_build_thread_transition (const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_THREAD))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current_unchecked ();
CheckState *state = get_state ();
/* We currently don't record external changes as those are hard to reason about. */
g_ptr_array_add (state->transitions, t);
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_THREAD) */
-
-#if !defined(DISABLE_CHECKED_BUILD_GC)
-
-static void
-assertion_fail (const char *msg, ...)
+void
+mono_fatal_with_history (const char *msg, ...)
{
int i;
GString* err = g_string_sized_new (100);
- CheckState *state = get_state ();
g_string_append_printf (err, "Assertion failure in thread %p due to: ", mono_native_thread_id_get ());
g_string_append_vprintf (err, msg, args);
va_end (args);
- g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len);
-
- for (i = state->transitions->len - 1; i >= 0; --i) {
- ThreadTransition *t = state->transitions->pdata [i];
- char *bt = translate_backtrace (t->backtrace, t->size);
- g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s",
- t->name,
- mono_thread_state_name (t->from_state),
- mono_thread_state_name (t->next_state),
- t->suspend_count,
- t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1
- t->suspend_count_delta,
- bt);
- g_free (bt);
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_THREAD))
+ {
+ CheckState *state = get_state ();
+
+ g_string_append_printf (err, "\nLast %d state transitions: (most recent first)\n", state->transitions->len);
+
+ for (i = state->transitions->len - 1; i >= 0; --i) {
+ ThreadTransition *t = state->transitions->pdata [i];
+ char *bt = translate_backtrace (t->backtrace, t->size);
+ g_string_append_printf (err, "[%s] %s -> %s (%d) %s%d at:\n%s",
+ t->name,
+ mono_thread_state_name (t->from_state),
+ mono_thread_state_name (t->next_state),
+ t->suspend_count,
+ t->suspend_count_delta > 0 ? "+" : "", //I'd like to see this sort of values: -1, 0, +1
+ t->suspend_count_delta,
+ bt);
+ g_free (bt);
+ }
}
g_error (err->str);
g_string_free (err, TRUE);
}
+#endif /* defined(ENABLE_CHECKED_BUILD_THREAD) */
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+
void
assert_gc_safe_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Safe mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Safe mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_BLOCKING:
case STATE_BLOCKING_AND_SUSPENDED:
break;
default:
- assertion_fail ("Expected GC Safe mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Safe mode but was in %s state", mono_thread_state_name (state));
}
}
void
assert_gc_unsafe_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Unsafe mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Unsafe mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_RUNNING:
case STATE_SELF_SUSPEND_REQUESTED:
break;
default:
- assertion_fail ("Expected GC Unsafe mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Unsafe mode but was in %s state", mono_thread_state_name (state));
}
}
void
assert_gc_neutral_mode (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
MonoThreadInfo *cur = mono_thread_info_current ();
int state;
if (!cur)
- assertion_fail ("Expected GC Neutral mode but thread is not attached");
+ mono_fatal_with_history ("Expected GC Neutral mode but thread is not attached");
switch (state = mono_thread_info_current_state (cur)) {
case STATE_RUNNING:
case STATE_BLOCKING_AND_SUSPENDED:
break;
default:
- assertion_fail ("Expected GC Neutral mode but was in %s state", mono_thread_state_name (state));
+ mono_fatal_with_history ("Expected GC Neutral mode but was in %s state", mono_thread_state_name (state));
}
}
void *
critical_gc_region_begin(void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return NULL;
+
CheckState *state = get_state ();
state->in_gc_critical_region++;
return state;
void
critical_gc_region_end(void* token)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
g_assert (state == token);
state->in_gc_critical_region--;
void
assert_not_in_gc_critical_region(void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
if (state->in_gc_critical_region > 0) {
- assertion_fail("Expected GC Unsafe mode, but was in %s state", mono_thread_state_name (mono_thread_info_current_state (mono_thread_info_current ())));
+ mono_fatal_with_history("Expected GC Unsafe mode, but was in %s state", mono_thread_state_name (mono_thread_info_current_state (mono_thread_info_current ())));
}
}
void
assert_in_gc_critical_region (void)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_GC))
+ return;
+
CheckState *state = get_state();
if (state->in_gc_critical_region == 0)
- assertion_fail("Expected GC critical region");
+ mono_fatal_with_history("Expected GC critical region");
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_GC) */
+#endif /* defined(ENABLE_CHECKED_BUILD_GC) */
-#if !defined(DISABLE_CHECKED_BUILD_METADATA)
+#ifdef ENABLE_CHECKED_BUILD_METADATA
// check_metadata_store et al: The goal of these functions is to verify that if there is a pointer from one mempool into
// another, that the pointed-to memory is protected by the reference count mechanism for MonoImages.
static void
check_mempool_may_reference_mempool (void *from_ptr, void *to_ptr, gboolean require_local)
{
+ if (!mono_check_mode_enabled (MONO_CHECK_MODE_METADATA))
+ return;
+
// Null pointers are OK
if (!to_ptr)
return;
check_mempool_may_reference_mempool (from, to, TRUE);
}
-#endif /* !defined(DISABLE_CHECKED_BUILD_METADATA) */
+#endif /* defined(ENABLE_CHECKED_BUILD_METADATA) */
-#endif /* CHECKED_BUILD */
+#endif /* ENABLE_CHECKED_BUILD */
#include <config.h>
#include <mono/utils/atomic.h>
+#include <mono/utils/mono-publib.h>
+
+typedef enum {
+ MONO_CHECK_MODE_NONE = 0,
+ MONO_CHECK_MODE_GC = 0x1,
+ MONO_CHECK_MODE_METADATA = 0x2,
+ MONO_CHECK_MODE_THREAD = 0x4,
+ MONO_CHECK_MODE_ALL = MONO_CHECK_MODE_GC | MONO_CHECK_MODE_METADATA | MONO_CHECK_MODE_THREAD,
+ MONO_CHECK_MODE_UNKNOWN = 0x8
+} MonoCheckMode;
+
+mono_bool mono_check_mode_enabled (MonoCheckMode query);
// This is for metadata writes which we have chosen not to check at the current time.
// Because in principle this should never happen, we still use a macro so that the exemptions will be easier to find, and remove, later.
// The current reason why this is needed is for pointers to constant strings, which the checker cannot verify yet.
#define CHECKED_METADATA_WRITE_PTR_EXEMPT(ptr, val) do { (ptr) = (val); } while (0)
-#if defined(CHECKED_BUILD)
+#ifdef ENABLE_CHECKED_BUILD
#define g_assert_checked g_assert
#define CHECKED_MONO_INIT()
-#endif /* CHECKED_BUILD */
-
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_GC)
+#endif /* ENABLE_CHECKED_BUILD */
+#ifdef ENABLE_CHECKED_BUILD_GC
/*
GC runtime modes rules:
#define MONO_REQ_GC_NOT_CRITICAL
#define MONO_REQ_GC_CRITICAL
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_GC) */
+#endif /* defined(ENABLE_CHECKED_BUILD_GC) */
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_METADATA)
+#ifdef ENABLE_CHECKED_BUILD_METADATA
// Use when writing a pointer from one image or imageset to another.
#define CHECKED_METADATA_WRITE_PTR(ptr, val) do { \
#define CHECKED_METADATA_WRITE_PTR_LOCAL(ptr, val) do { (ptr) = (val); } while (0)
#define CHECKED_METADATA_WRITE_PTR_ATOMIC(ptr, val) do { mono_atomic_store_release (&(ptr), (val)); } while (0)
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_METADATA) */
+#endif /* defined(ENABLE_CHECKED_BUILD_METADATA) */
-#if defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_THREAD)
+#ifdef ENABLE_CHECKED_BUILD_THREAD
#define CHECKED_BUILD_THREAD_TRANSITION(transition, info, from_state, suspend_count, next_state, suspend_count_delta) do { \
checked_build_thread_transition (transition, info, from_state, suspend_count, next_state, suspend_count_delta); \
void checked_build_thread_transition(const char *transition, void *info, int from_state, int suspend_count, int next_state, int suspend_count_delta);
+void mono_fatal_with_history(const char *msg, ...);
+
#else
#define CHECKED_BUILD_THREAD_TRANSITION(transition, info, from_state, suspend_count, next_state, suspend_count_delta)
-#endif /* defined(CHECKED_BUILD) && !defined(DISABLE_CHECKED_BUILD_THREAD) */
+#define mono_fatal_with_history g_error
+
+#endif /* defined(ENABLE_CHECKED_BUILD_THREAD) */
#endif /* __CHECKED_BUILD_H__ */
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-threads-coop.h>
#include <mono/utils/mono-threads-api.h>
+#include <mono/utils/checked-build.h>
#ifdef TARGET_OSX
#include <mono/utils/mach-support.h>
volatile size_t mono_polling_required;
+// FIXME: This would be more efficient if instead of instantiating the stack it just pushed a simple depth counter up and down,
+// perhaps with a per-thread cookie in the high bits.
+#ifdef ENABLE_CHECKED_BUILD_GC
+// Maintains a single per-thread stack of ints, used to ensure nesting is not violated
+MonoNativeTlsKey coop_reset_count_stack_key;
+static int coop_tls_push (int v) {
+ GArray *stack = mono_native_tls_get_value (coop_reset_count_stack_key);
+ if (!stack) {
+ stack = g_array_new (FALSE,FALSE,sizeof(int));
+ mono_native_tls_set_value (coop_reset_count_stack_key, stack);
+ }
+ g_array_append_val (stack, v);
+ return stack->len;
+}
+static int coop_tls_pop (int *v) {
+ GArray *stack = mono_native_tls_get_value (coop_reset_count_stack_key);
+ if (!stack || 0 == stack->len)
+ return -1;
+ stack->len--;
+ *v = g_array_index (stack, int, stack->len);
+ int len = stack->len;
+ if (0 == len) {
+ g_array_free (stack,TRUE);
+ mono_native_tls_set_value (coop_reset_count_stack_key, NULL);
+ }
+ return len;
+}
+#endif
+
static int coop_reset_blocking_count;
static int coop_try_blocking_count;
static int coop_do_blocking_count;
if (!mono_threads_is_coop_enabled ())
return NULL;
+ info = mono_thread_info_current_unchecked ();
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ int reset_blocking_count = InterlockedIncrement (&coop_reset_blocking_count);
+ // In this mode, the blocking count is used as the reset cookie. We would prefer
+ // (but do not require) this to be unique across invocations and threads.
+ if (reset_blocking_count == 0) // We *do* require it be nonzero
+ reset_blocking_count = coop_reset_blocking_count = 1;
+#else
++coop_reset_blocking_count;
+#endif
- info = mono_thread_info_current_unchecked ();
/* If the thread is not attached, it doesn't make sense prepare for suspend. */
if (!info || !mono_thread_info_is_live (info))
return NULL;
return NULL;
case AbortBlockingOk:
info->thread_saved_state [SELF_SUSPEND_STATE_INDEX].valid = FALSE;
- return info;
+ break;
case AbortBlockingOkAndPool:
mono_threads_state_poll ();
- return info;
+ break;
default:
g_error ("Unknown thread state");
}
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC)) {
+ int level = coop_tls_push (reset_blocking_count);
+ //g_warning("Entering reset nest; level %d; cookie %d\n", level, reset_blocking_count);
+ return (void *)(intptr_t)reset_blocking_count;
+ }
+#endif
+
+ return info;
}
void
mono_threads_reset_blocking_end (void *cookie, void* stackdata)
{
- MonoThreadInfo *info;
-
if (!mono_threads_is_coop_enabled ())
return;
- info = (MonoThreadInfo *)cookie;
- if (!info)
+ if (!cookie)
return;
- g_assert (info == mono_thread_info_current_unchecked ());
+#ifdef ENABLE_CHECKED_BUILD_GC
+ if (mono_check_mode_enabled (MONO_CHECK_MODE_GC)) {
+ int received_cookie = (int)(intptr_t)cookie;
+ int desired_cookie;
+ int level = coop_tls_pop (&desired_cookie);
+ //g_warning("Leaving reset nest; back to level %d; desired cookie %d; received cookie %d\n", level, desired_cookie, received_cookie);
+ if (level < 0)
+ mono_fatal_with_history ("Expected cookie %d but found no stack at all\n", desired_cookie);
+ if (desired_cookie != received_cookie)
+ mono_fatal_with_history ("Expected cookie %d but received %d\n", desired_cookie, received_cookie);
+ } else // Notice this matches the line after the endif
+#endif
+ {
+ g_assert (((MonoThreadInfo *)cookie) == mono_thread_info_current_unchecked ());
+ }
+
mono_threads_prepare_blocking (stackdata);
}
mono_counters_register ("Coop Do Polling", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_do_polling_count);
mono_counters_register ("Coop Save Count", MONO_COUNTER_GC | MONO_COUNTER_INT, &coop_save_count);
//See the above for what's wrong here.
+
+#ifdef ENABLE_CHECKED_BUILD_GC
+ mono_native_tls_alloc (&coop_reset_count_stack_key, NULL);
+#endif
}
void
trace_state_change ("ATTACH", info, raw_state, STATE_RUNNING, 0);
break;
default:
- g_error ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition current thread from %s with ATTACH", state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This is a bug in coop x suspend that resulted the thread in an undetachable state.
*/
default:
- g_error ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition current thread %p from %s with DETACH", info, state_name (cur_state));
}
}
If this turns to be an issue we can introduce a new suspend request state for when both have been requested.
*/
default:
- g_error ("Cannot transition thread %p from %s with SUSPEND_REQUEST", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with SUSPEND_REQUEST", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_ASYNC_SUSPEND_REQUESTED: Since there can only be one async suspend in progress and it must finish, it should not be possible to witness this.
*/
default:
- g_error ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with ASYNC_SUSPEND_REQUESTED", mono_thread_info_get_tid (info), state_name (cur_state));
}
return (MonoRequestAsyncSuspendResult) FALSE;
}
STATE_BLOCKING_AND_SUSPENDED: Pool is a local state transition. No VM activities are allowed while in blocking mode.
*/
default:
- g_error ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with STATE_POLL", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
*/
default:
- g_error ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with REQUEST_RESUME", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING: Async suspend only begins if a transition to async suspend requested happened. Blocking would have put us into blocking with positive suspend count if it raced with async finish.
*/
default:
- g_error ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_SELF_SUSPEND_REQUESTED: All those are invalid end states of a sucessfull finish async suspend
*/
default:
- g_error ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with COMPENSATE_FINISH_ASYNC_SUSPEND", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: Blocking is not nestabled
*/
default:
- g_error ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DO_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This an exit state of done blocking
*/
default:
- g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
STATE_BLOCKING_AND_SUSPENDED: This is an exit state of done blocking, can't happen here.
*/
default:
- g_error ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
+ mono_fatal_with_history ("Cannot transition thread %p from %s with DONE_BLOCKING", mono_thread_info_get_tid (info), state_name (cur_state));
}
}
endif BUILD_MCS
-TEST_SUPPORT_FILES = $(tmpinst)/bin/mono $(tmpinst)/bin/ilasm $(tmpinst)/bin/mcs $(tmpinst)/bin/dmcs $(tmpinst)/bin/al2 $(tmpinst)/bin/al
+TEST_SUPPORT_FILES = $(tmpinst)/bin/mono $(tmpinst)/bin/ilasm $(tmpinst)/bin/mcs $(tmpinst)/bin/al
mcs-do-test-profiles:
cd $(mcs_topdir) && $(MAKE) NO_DIR_CHECK=1 PROFILES='$(test_profiles)' test-profiles
echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/build/mcs.exe"'" "$$@"' >> $@ ; \
chmod +x $@
-$(tmpinst)/bin/dmcs: $(tmpinst)/bin/mono Makefile
- echo '#! /bin/sh' > $@ ; \
- r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
- echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/build/mcs.exe -sdk:4"'" "$$@"' >> $@ ; \
- chmod +x $@
-
$(tmpinst)/bin/ilasm: $(tmpinst)/bin/mono Makefile
echo '#! /bin/sh' > $@ ; \
r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/ilasm/ilasm.exe"'" "$$@"' >> $@ ; \
chmod +x $@
-$(tmpinst)/bin/al2: $(tmpinst)/bin/mono Makefile
- echo '#! /bin/sh' > $@ ; \
- r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
- echo 'exec "'"$$r/$(tmpinst)/bin/mono"'" "'"$$m/class/lib/net_2_0/al.exe"'" "$$@"' >> $@ ; \
- chmod +x $@
-
$(tmpinst)/bin/al: $(tmpinst)/bin/mono Makefile
echo '#! /bin/sh' > $@ ; \
r=`pwd`; m=`cd $(mcs_topdir) && pwd`; \
/mono-abi-info
/mono-api-diff
/mono-api-info
+/mono-api-html
/mono-api-info1
/mono-api-info2
/mono-cil-strip
mod$(SCRIPT_SUFFIX) \
monolinker$(SCRIPT_SUFFIX) \
mono-api-info$(SCRIPT_SUFFIX) \
+ mono-api-html$(SCRIPT_SUFFIX) \
mono-shlib-cop$(SCRIPT_SUFFIX) \
mozroots$(SCRIPT_SUFFIX) \
permview$(SCRIPT_SUFFIX) \