public void ManagedSignature() { int n = 0; Errors = 0; ErrorData.Clear(); foreach (Type t in Assembly.GetTypes()) { if (!NSObjectType.IsAssignableFrom(t)) { continue; } CurrentType = t; foreach (MethodInfo m in t.GetMethods(Flags)) { CheckManagedMemberSignatures(m, t, ref n); } foreach (MethodBase m in t.GetConstructors(Flags)) { CheckManagedMemberSignatures(m, t, ref n); } } AssertIfErrors("{0} errors found in {1} signatures validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
public void StaticMethods() { Errors = 0; ErrorData.Clear(); int n = 0; IntPtr responds_handle = Selector.GetHandle("respondsToSelector:"); foreach (Type t in Assembly.GetTypes()) { if (t.IsNested || !NSObjectType.IsAssignableFrom(t)) { continue; } if (Skip(t) || SkipDueToAttribute(t)) { continue; } FieldInfo fi = t.GetField("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); if (fi == null) { continue; // e.g. *Delegate } IntPtr class_ptr = (IntPtr)fi.GetValue(null); foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if (SkipDueToAttribute(m)) { continue; } foreach (object ca in m.GetCustomAttributes(true)) { if (ca is ExportAttribute) { string name = (ca as ExportAttribute).Selector; if (Skip(t, name)) { continue; } bool result = bool_objc_msgSend_IntPtr(class_ptr, responds_handle, Selector.GetHandle(name)); bool response = CheckStaticResponse(result, t, m.DeclaringType, ref name); if (!response) { ReportError(name); } n++; } } } } Assert.AreEqual(0, Errors, "{0} errors found in {1} static selector validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
// we just want to confirm the symbol exists so `dlsym` can be disabled protected void Check(Assembly a) { Errors = 0; ErrorData.Clear(); int n = 0; foreach (var t in a.GetTypes()) { foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) { continue; } var dllimport = m.GetCustomAttribute <DllImportAttribute> (); string name = dllimport.EntryPoint ?? m.Name; switch (name) { // known not to be present in ARM64 case "objc_msgSend_stret": case "objc_msgSendSuper_stret": // the linker normally removes them (IntPtr.Size optimization) continue; } string path = dllimport.Value; switch (path) { case "__Internal": // load from executable path = null; break; case "libc": // we still have some rogue/not-fully-qualified DllImport path = "/usr/lib/libSystem.dylib"; break; } var lib = Dlfcn.dlopen(path, 0); var h = Dlfcn.dlsym(lib, name); if (h == IntPtr.Zero) { ReportError("Could not find the symbol '{0}' in {1}", name, path); } Dlfcn.dlclose(lib); n++; } } Assert.AreEqual(0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
public void NativeSignatures() { int n = 0; Errors = 0; ErrorData.Clear(); foreach (Type t in Assembly.GetTypes()) { var static_type = t.IsSealed && t.IsAbstract; // e.g. [Category] if (t.IsNested || (!static_type && !NSObjectType.IsAssignableFrom(t))) { continue; } if (Skip(t)) { continue; } CurrentType = t; FieldInfo fi = null; if (!static_type) { fi = t.GetField("class_ptr", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); } IntPtr class_ptr = fi == null ? IntPtr.Zero : (IntPtr)fi.GetValue(null); foreach (MethodBase m in t.GetMethods(Flags)) { CheckMemberSignature(m, t, class_ptr, ref n); } foreach (MethodBase m in t.GetConstructors(Flags)) { CheckMemberSignature(m, t, class_ptr, ref n); } } AssertIfErrors("{0} errors found in {1} signatures validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
public void InstanceMethods() { Errors = 0; ErrorData.Clear(); int n = 0; foreach (Type t in Assembly.GetTypes()) { if (t.IsNested || !NSObjectType.IsAssignableFrom(t)) { continue; } if (Skip(t) || SkipDueToAttribute(t)) { continue; } IntPtr class_ptr = GetClassForType(t); if (class_ptr == IntPtr.Zero) { continue; } foreach (var c in t.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { Process(class_ptr, t, c, ref n); } foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { Process(class_ptr, t, m, ref n); } } Assert.AreEqual(0, Errors, "{0} errors found in {1} instance selector validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
public void DefaultCtorAllowed() { Errors = 0; ErrorData.Clear(); int n = 0; foreach (Type t in Assembly.GetTypes()) { if (t.IsAbstract || !NSObjectType.IsAssignableFrom(t)) { continue; } if (Skip(t)) { continue; } var ctor = t.GetConstructor(Type.EmptyTypes); if (SkipDueToAttribute(ctor)) { continue; } if ((ctor == null) || ctor.IsAbstract) { if (LogUntestedTypes) { Console.WriteLine("[WARNING] {0} was skipped because it had no default constructor", t); } continue; } instance_type_name = t.FullName; if (LogProgress) { Console.WriteLine("{0}. {1}", n, instance_type_name); } NSObject obj = null; try { obj = ctor.Invoke(null) as NSObject; CheckHandle(obj); CheckToString(obj); CheckIsDirectBinding(obj); CheckNSObjectProtocol(obj); Dispose(obj, t); } catch (Exception e) { // Objective-C exception thrown if (!ContinueOnFailure) { throw; } TargetInvocationException tie = (e as TargetInvocationException); if (tie != null) { e = tie.InnerException; } ReportError("Default constructor not allowed for {0} : {1}", instance_type_name, e.Message); } n++; } Assert.AreEqual(0, Errors, "{0} potential errors found in {1} default ctor validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
// we just want to confirm the symbol exists so `dlsym` can be disabled protected void Check(Assembly a) { Errors = 0; ErrorData.Clear(); int n = 0; foreach (var t in a.GetTypes()) { foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) { continue; } var dllimport = m.GetCustomAttribute <DllImportAttribute> (); string name = dllimport.EntryPoint ?? m.Name; switch (name) { // known not to be present in ARM64 case "objc_msgSend_stret": case "objc_msgSendSuper_stret": // the linker normally removes them (IntPtr.Size optimization) continue; } string path = dllimport.Value; switch (path) { case "__Internal": // load from executable path = null; break; #if NET case "QCall": // Globalization hasn't been implemented yet: https://github.com/xamarin/xamarin-macios/issues/8906 if (name.StartsWith("GlobalizationNative_", StringComparison.Ordinal)) { continue; } break; case "libhostpolicy": // There's no libhostpolicy library. // https://github.com/dotnet/runtime/issues/38543 continue; case "libSystem.Native": path += ".dylib"; break; #endif case "libc": // we still have some rogue/not-fully-qualified DllImport path = "/usr/lib/libSystem.dylib"; break; case "System.Native": case "System.Security.Cryptography.Native.Apple": case "System.Net.Security.Native": if (MonoNativeConfig.LinkMode == MonoNativeLinkMode.None) { continue; } #if __IOS__ path = MonoNativeConfig.GetPInvokeLibraryName(MonoNativeFlavor.Compat, MonoNativeConfig.LinkMode); #else path = null; #endif break; } var lib = Dlfcn.dlopen(path, 0); var h = Dlfcn.dlsym(lib, name); if (h == IntPtr.Zero) { ReportError("Could not find the symbol '{0}' in {1}", name, path); } Dlfcn.dlclose(lib); n++; } } Assert.AreEqual(0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
public void AsyncCandidates() { int n = 0; Errors = 0; ErrorData.Clear(); foreach (Type t in Assembly.GetTypes()) { // e.g. delegates used for events if (t.IsNested) { continue; } if (!NSObjectType.IsAssignableFrom(t)) { continue; } if (t.GetCustomAttribute <ProtocolAttribute> () != null) { continue; } if (t.GetCustomAttribute <ModelAttribute> () != null) { continue; } // let's not encourage the use of some API if (IsDiscouraged(t)) { continue; } CurrentType = t; var methods = t.GetMethods(Flags); foreach (MethodInfo m in methods) { if (m.DeclaringType != t) { continue; } // skip properties / events if (m.IsSpecialName) { continue; } if (IgnoreAsync(m)) { continue; } // some calls are "natively" async if (m.Name.IndexOf("Async", StringComparison.Ordinal) != -1) { continue; } // let's not encourage the use of some API if (IsDiscouraged(m)) { continue; } // is it a candidate ? var p = m.GetParameters(); if (p.Length == 0) { continue; } var last = p [p.Length - 1]; // trying to limit false positives and the need for large ignore lists to maintain // unlike other introspection tests a failure does not mean a broken API switch (last.Name) { case "completionHandler": case "completion": break; default: continue; } if (!last.ParameterType.IsSubclassOf(typeof(Delegate))) { continue; } // did we provide a async wrapper ? string ma = m.Name + "Async"; if (methods.Where((mi) => mi.Name == ma).FirstOrDefault() != null) { continue; } var name = m.ToString(); var i = name.IndexOf(' '); ErrorData.AppendLine(name.Insert(i + 1, m.DeclaringType.Name + "::")); Errors++; } } AssertIfErrors("{0} errors found in {1} signatures validated{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }
// we just want to confirm the symbol exists so `dlsym` can be disabled protected void Check(Assembly a) { Errors = 0; ErrorData.Clear(); int n = 0; foreach (var t in a.GetTypes()) { foreach (var m in t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)) { if ((m.Attributes & MethodAttributes.PinvokeImpl) == 0) { continue; } var dllimport = m.GetCustomAttribute <DllImportAttribute> (); string name = dllimport.EntryPoint ?? m.Name; switch (name) { // known not to be present in ARM64 case "objc_msgSend_stret": case "objc_msgSendSuper_stret": // the linker normally removes them (IntPtr.Size optimization) continue; } string path = dllimport.Value; switch (path) { case "__Internal": // load from executable path = null; break; #if NET case "libSystem.Globalization.Native": // load from executable (like __Internal above since it's part of the static library) path = null; break; case "libSystem.Native": path += ".dylib"; break; #endif case "libc": // we still have some rogue/not-fully-qualified DllImport path = "/usr/lib/libSystem.dylib"; break; case "System.Native": case "System.Security.Cryptography.Native.Apple": case "System.Net.Security.Native": if (MonoNativeConfig.LinkMode == MonoNativeLinkMode.None) { continue; } #if __IOS__ path = MonoNativeConfig.GetPInvokeLibraryName(MonoNativeFlavor.Compat, MonoNativeConfig.LinkMode); #else path = null; #endif break; } var lib = Dlfcn.dlopen(path, 0); var h = Dlfcn.dlsym(lib, name); if (h == IntPtr.Zero) { ReportError("Could not find the symbol '{0}' in {1} for the P/Invoke {2}.{3} in {4}", name, path, t.FullName, m.Name, a.GetName().Name); } else if (path != null) { // Verify that the P/Invoke points to the right library. Dl_info info = default(Dl_info); var found = dladdr(h, out info); if (found != 0) { // Resolve symlinks in both cases var dllImportPath = ResolveLibrarySymlinks(path); var foundLibrary = ResolveLibrarySymlinks(Marshal.PtrToStringAuto(info.dli_fname)); if (Skip(name, ref dllImportPath, ref foundLibrary)) { // Skipped } else if (foundLibrary != dllImportPath) { ReportError($"Found the symbol '{name}' in the library '{foundLibrary}', but the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} claims it's in '{dllimport.Value}'."); } } else { Console.WriteLine($"Unable to find the library for the symbol '{name}' claimed to be in {path} for the P/Invoke {t.FullName}.{m.Name} in {a.GetName ().Name} (rv: {found})"); } } Dlfcn.dlclose(lib); n++; } } Assert.AreEqual(0, Errors, "{0} errors found in {1} symbol lookups{2}", Errors, n, Errors == 0 ? string.Empty : ":\n" + ErrorData.ToString() + "\n"); }