[loader] Set domain->entry_assembly earlier in startup (#31814)
authorRyan Lucia <rylucia@microsoft.com>
Fri, 7 Feb 2020 16:18:40 +0000 (11:18 -0500)
committerGitHub <noreply@github.com>
Fri, 7 Feb 2020 16:18:40 +0000 (11:18 -0500)
When locating AppContext.BaseDirectory on netcore, if APP_CONTEXT_BASE_DIRECTORY is not set we call into the runtime for a fallback location, which checks domain->entry_assembly. On legacy this is fine because we set that property in `prepare_thread_to_exec_main`, but on netcore the new managed assembly loading algorithm will call into managed and check the property before that function is run, which will result in AppContext.BaseDirectory returning an empty string. The solution is to set entry_assembly a bit earlier in initialization. This is the appropriate location because it's what embedding API users will call to run an assembly.

In the process, remove some code that would bypass the usual lookup algorithm unnecessarily.

src/mono/mono/metadata/domain-internals.h
src/mono/mono/metadata/domain.c
src/mono/mono/metadata/object.c

index e783a27..987487f 100644 (file)
@@ -680,6 +680,9 @@ mono_runtime_install_appctx_properties (void);
 gboolean 
 mono_domain_set_fast (MonoDomain *domain, gboolean force);
 
+void
+mono_domain_ensure_entry_assembly (MonoDomain *domain, MonoAssembly *assembly);
+
 MonoAssemblyLoadContext *
 mono_domain_default_alc (MonoDomain *domain);
 
index 98214f1..45245c8 100644 (file)
@@ -1023,7 +1023,32 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data)
        MONO_EXIT_GC_UNSAFE;
 }
 
-/* FIXME: maybe we should integrate this with mono_assembly_open? */
+void
+mono_domain_ensure_entry_assembly (MonoDomain *domain, MonoAssembly *assembly)
+{
+       if (!domain->entry_assembly && assembly) {
+               gchar *str;
+               ERROR_DECL (error);
+
+               domain->entry_assembly = assembly;
+               /* Domains created from another domain already have application_base and configuration_file set */
+               if (domain->setup->application_base == NULL) {
+                       MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, error);
+                       mono_error_assert_ok (error);
+                       MONO_OBJECT_SETREF_INTERNAL (domain->setup, application_base, basedir);
+               }
+
+               if (domain->setup->configuration_file == NULL) {
+                       str = g_strconcat (assembly->image->name, ".config", (const char*)NULL);
+                       MonoString *config_file = mono_string_new_checked (domain, str, error);
+                       mono_error_assert_ok (error);
+                       MONO_OBJECT_SETREF_INTERNAL (domain->setup, configuration_file, config_file);
+                       g_free (str);
+                       mono_domain_set_options_from_config (domain);
+               }
+       }
+}
+
 /**
  * mono_domain_assembly_open:
  * \param domain the application domain
@@ -1040,37 +1065,15 @@ mono_domain_assembly_open (MonoDomain *domain, const char *name)
 }
 
 // Uses the domain on legacy mono and the ALC on current
+// Intended only for loading the main assembly
 MonoAssembly *
 mono_domain_assembly_open_internal (MonoDomain *domain, MonoAssemblyLoadContext *alc, const char *name)
 {
        MonoDomain *current;
        MonoAssembly *ass;
-       GSList *tmp;
 
        MONO_REQ_GC_UNSAFE_MODE;
 
-#ifdef ENABLE_NETCORE
-       mono_alc_assemblies_lock (alc);
-       for (tmp = alc->loaded_assemblies; tmp; tmp = tmp->next) {
-               ass = (MonoAssembly *)tmp->data;
-               if (strcmp (name, ass->aname.name) == 0) {
-                       mono_alc_assemblies_unlock (alc);
-                       return ass;
-               }
-       }
-       mono_alc_assemblies_unlock (alc);
-#else
-       mono_domain_assemblies_lock (domain);
-       for (tmp = domain->domain_assemblies; tmp; tmp = tmp->next) {
-               ass = (MonoAssembly *)tmp->data;
-               if (strcmp (name, ass->aname.name) == 0) {
-                       mono_domain_assemblies_unlock (domain);
-                       return ass;
-               }
-       }
-       mono_domain_assemblies_unlock (domain);
-#endif
-
        MonoAssemblyOpenRequest req;
        mono_assembly_request_prepare_open (&req, MONO_ASMCTX_DEFAULT, alc);
        if (domain != mono_domain_get ()) {
@@ -1083,6 +1086,12 @@ mono_domain_assembly_open_internal (MonoDomain *domain, MonoAssemblyLoadContext
                ass = mono_assembly_request_open (name, &req, NULL);
        }
 
+       // On netcore, this is necessary because we check the AppContext.BaseDirectory property as part of the assembly lookup algorithm
+       // AppContext.BaseDirectory can sometimes fall back to checking the location of the entry_assembly, which should be non-null
+#ifdef ENABLE_NETCORE
+       mono_domain_ensure_entry_assembly (domain, ass);
+#endif
+
        return ass;
 }
 
index f6946d1..94b68b1 100644 (file)
@@ -5118,29 +5118,8 @@ prepare_thread_to_exec_main (MonoDomain *domain, MonoMethod *method)
        MonoCustomAttrInfo* cinfo;
        gboolean has_stathread_attribute;
 
-       if (!domain->entry_assembly) {
-               gchar *str;
-               ERROR_DECL (error);
-               MonoAssembly *assembly;
-
-               assembly = m_class_get_image (method->klass)->assembly;
-               domain->entry_assembly = assembly;
-               /* Domains created from another domain already have application_base and configuration_file set */
-               if (domain->setup->application_base == NULL) {
-                       MonoString *basedir = mono_string_new_checked (domain, assembly->basedir, error);
-                       mono_error_assert_ok (error);
-                       MONO_OBJECT_SETREF_INTERNAL (domain->setup, application_base, basedir);
-               }
-
-               if (domain->setup->configuration_file == NULL) {
-                       str = g_strconcat (assembly->image->name, ".config", (const char*)NULL);
-                       MonoString *config_file = mono_string_new_checked (domain, str, error);
-                       mono_error_assert_ok (error);
-                       MONO_OBJECT_SETREF_INTERNAL (domain->setup, configuration_file, config_file);
-                       g_free (str);
-                       mono_domain_set_options_from_config (domain);
-               }
-       }
+       if (!domain->entry_assembly)
+               mono_domain_ensure_entry_assembly (domain, m_class_get_image (method->klass)->assembly);
 
        ERROR_DECL (cattr_error);
        cinfo = mono_custom_attrs_from_method_checked (method, cattr_error);