1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
| | mono: metadata: add <runpath> element to .config files.
This new element is of the form:
<runpath path="/path1/to/libs:/path2/to/libs:..."/>
(the : will actually be whatever G_SEARCHPATH_SEPARATOR_S is, so likely ; on
windows and : elsewhere).
* mono/metadata/metadata-internals.h (struct _MonoImage): new 'runpath' field.
* mono/metadata/mono-config.c (runpath_init, runpath_start, runpath_handler):
new functions and parser using them to populate runpath field from <runpath>
element.
(mono_config_init): register runpath_handler.
* mono/metadata/assembly.c (mono_assembly_load_full_gac_base_default): new
'requesting' parameter, use it to search the requesting assembly's runpath
first.
(mono_assembly_request_byname_nosearch): use it.
diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c
index f9feaacf2c1..8c71ad0eb95 100644
--- a/mono/metadata/assembly.c
+++ b/mono/metadata/assembly.c
@@ -376,7 +376,7 @@ mono_assembly_invoke_search_hook_internal (MonoAssemblyLoadContext *alc, MonoAss
static MonoAssembly*
mono_assembly_request_byname_nosearch (MonoAssemblyName *aname, const MonoAssemblyByNameRequest *req, MonoImageOpenStatus *status);
static MonoAssembly*
-mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname, const char *basedir, MonoAssemblyLoadContext *alc, MonoAssemblyContextKind asmctx, MonoImageOpenStatus *status);
+mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname, MonoAssembly *requesting, const char *basedir, MonoAssemblyLoadContext *alc, MonoAssemblyContextKind asmctx, MonoImageOpenStatus *status);
static MonoAssembly*
chain_redirections_loadfrom (MonoAssemblyLoadContext *alc, MonoImage *image, MonoImageOpenStatus *out_status);
static MonoAssembly*
@@ -4655,7 +4655,7 @@ mono_assembly_request_byname_nosearch (MonoAssemblyName *aname,
}
#ifndef ENABLE_NETCORE
- result = mono_assembly_load_full_gac_base_default (aname, req->basedir, req->request.alc, req->request.asmctx, status);
+ result = mono_assembly_load_full_gac_base_default (aname, req->requesting_assembly, req->basedir, req->request.alc, req->request.asmctx, status);
#endif
return result;
}
@@ -4667,6 +4667,7 @@ mono_assembly_request_byname_nosearch (MonoAssemblyName *aname,
*/
MonoAssembly*
mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname,
+ MonoAssembly *requesting,
const char *basedir,
MonoAssemblyLoadContext *alc,
MonoAssemblyContextKind asmctx,
@@ -4718,6 +4719,23 @@ mono_assembly_load_full_gac_base_default (MonoAssemblyName *aname,
filename = g_strconcat (aname->name, ext, (const char*)NULL);
}
+ if (requesting
+ && requesting->image
+ && requesting->image->runpath) {
+ char **runpath = requesting->image->runpath;
+ int j;
+ for (j = 0; runpath[j]; j++) {
+ fullpath = g_build_filename (runpath[j], filename, NULL);
+ result = mono_assembly_request_open (fullpath, &req, status);
+ g_free (fullpath);
+ if (result) {
+ result->in_gac = FALSE;
+ g_free (filename);
+ return result;
+ }
+ }
+ }
+
#ifndef DISABLE_GAC
const gboolean refonly = asmctx == MONO_ASMCTX_REFONLY;
diff --git a/mono/metadata/image.c b/mono/metadata/image.c
index e0b86dd3d09..12a8094e4e0 100644
--- a/mono/metadata/image.c
+++ b/mono/metadata/image.c
@@ -2363,6 +2363,9 @@ mono_image_close_except_pools (MonoImage *image)
mono_metadata_clean_for_image (image);
+ if (image->runpath)
+ g_strfreev (image->runpath);
+
/*
* The caches inside a MonoImage might refer to metadata which is stored in referenced
* assemblies, so we can't release these references in mono_assembly_close () since the
diff --git a/mono/metadata/metadata-internals.h b/mono/metadata/metadata-internals.h
index 9388d69b0fd..93f4b880c61 100644
--- a/mono/metadata/metadata-internals.h
+++ b/mono/metadata/metadata-internals.h
@@ -423,6 +423,12 @@ struct _MonoImage {
/**/
MonoTableInfo tables [MONO_TABLE_NUM];
+ /*
+ Search path to be tried first when looking for assemblies referenced by
+ this image, or NULL. Is a NULL-terminated vector.
+ */
+ char **runpath;
+
/*
* references is initialized only by using the mono_assembly_open
* function, and not by using the lowlevel mono_image_open.
diff --git a/mono/metadata/mono-config.c b/mono/metadata/mono-config.c
index d973de53c8c..8888c7b4fac 100644
--- a/mono/metadata/mono-config.c
+++ b/mono/metadata/mono-config.c
@@ -21,6 +21,7 @@
#include "mono/metadata/metadata-internals.h"
#include "mono/metadata/object-internals.h"
#include "mono/utils/mono-logger-internals.h"
+#include "mono/utils/mono-path.h"
#if defined(TARGET_PS3)
#define CONFIG_OS "CellOS"
@@ -464,6 +465,59 @@ aot_cache_handler = {
NULL, /* finish */
};
+static void*
+runpath_init (MonoImage *assembly)
+{
+ return assembly;
+}
+
+static void
+runpath_start (gpointer user_data,
+ const gchar *element_name,
+ const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ MonoImage *assembly = (MonoImage *) user_data;
+ int i;
+
+ if (strcmp (element_name, "runpath") != 0)
+ return;
+
+ for (i = 0; attribute_names[i]; i++)
+ {
+ if(!strcmp (attribute_names [i], "path"))
+ {
+ char **splitted, **dest;
+
+ splitted = g_strsplit (attribute_values[i],
+ G_SEARCHPATH_SEPARATOR_S,
+ 1000);
+ if (assembly->runpath)
+ g_strfreev (assembly->runpath);
+ assembly->runpath = dest = splitted;
+ while (*splitted) {
+ char *tmp = *splitted;
+ if (*tmp)
+ *dest++ = mono_path_canonicalize (tmp);
+ g_free (tmp);
+ splitted++;
+ }
+ *dest = *splitted;
+ break;
+ }
+ }
+}
+
+static const MonoParseHandler
+runpath_handler = {
+ "runpath",
+ runpath_init,
+ runpath_start,
+ NULL, /* text */
+ NULL, /* end */
+ NULL, /* finish */
+};
+
static int inited = 0;
static void
@@ -476,6 +530,7 @@ mono_config_init (void)
#endif
g_hash_table_insert (config_handlers, (gpointer) legacyUEP_handler.element_name, (gpointer) &legacyUEP_handler);
g_hash_table_insert (config_handlers, (gpointer) aot_cache_handler.element_name, (gpointer) &aot_cache_handler);
+ g_hash_table_insert (config_handlers, (gpointer) runpath_handler.element_name, (gpointer) &runpath_handler);
}
/**
|