added array bound checking
[mono.git] / mono / metadata / object.c
1 /*
2  * object.c: Object creation for the Mono runtime
3  *
4  * Author:
5  *   Miguel de Icaza (miguel@ximian.com)
6  *
7  * (C) 2001 Ximian, Inc.
8  */
9 #include <config.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <signal.h>
13 #include <string.h>
14 #include <mono/metadata/tabledefs.h>
15 #include <mono/metadata/loader.h>
16 #include <mono/metadata/object.h>
17 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
18 #include <sys/mman.h>
19 #include <limits.h>    /* for PAGESIZE */
20 #ifndef PAGESIZE
21 #define PAGESIZE 4096
22 #endif
23 #endif
24
25 static void
26 default_runtime_object_init (MonoObject *o)
27 {
28         return;
29 }
30
31 MonoRuntimeObjectInit mono_runtime_object_init = default_runtime_object_init;
32 MonoRuntimeExecMain   mono_runtime_exec_main = NULL;
33
34 void
35 mono_install_runtime_object_init (MonoRuntimeObjectInit func)
36 {
37         mono_runtime_object_init = func? func: default_runtime_object_init;
38 }
39
40 void
41 mono_install_runtime_exec_main (MonoRuntimeExecMain func)
42 {
43         mono_runtime_exec_main = func;
44 }
45
46 /**
47  * mono_object_allocate:
48  * @size: number of bytes to allocate
49  *
50  * This is a very simplistic routine until we have our GC-aware
51  * memory allocator. 
52  *
53  * Returns: an allocated object of size @size, or NULL on failure.
54  */
55 void *
56 mono_object_allocate (size_t size)
57 {
58         void *o = calloc (1, size);
59
60         return o;
61 }
62
63 /**
64  * mono_object_free:
65  *
66  * Frees the memory used by the object.  Debugging purposes
67  * only, as we will have our GC system.
68  */
69 void
70 mono_object_free (MonoObject *o)
71 {
72         MonoClass *c = o->klass;
73         
74         memset (o, 0, c->instance_size);
75         free (o);
76 }
77
78 /**
79  * mono_object_new:
80  * @klass: the class of the object that we want to create
81  *
82  * Returns: A newly created object whose definition is
83  * looked up using @klass
84  */
85 MonoObject *
86 mono_object_new (MonoClass *klass)
87 {
88         MonoObject *o;
89
90         if (!klass->inited)
91                 mono_class_init (klass);
92
93         o = mono_object_allocate (klass->instance_size);
94         o->klass = klass;
95
96         return o;
97 }
98
99 /**
100  * mono_object_new_from_token:
101  * @image: Context where the type_token is hosted
102  * @token: a token of the type that we want to create
103  *
104  * Returns: A newly created object whose definition is
105  * looked up using @token in the @image image
106  */
107 MonoObject *
108 mono_object_new_from_token  (MonoImage *image, guint32 token)
109 {
110         MonoClass *class;
111
112         class = mono_class_get (image, token);
113
114         return mono_object_new (class);
115 }
116
117
118 /**
119  * mono_object_clone:
120  * @obj: the object to clone
121  *
122  * Returns: A newly created object who is a shallow copy of @obj
123  */
124 MonoObject *
125 mono_object_clone (MonoObject *obj)
126 {
127         MonoObject *o;
128         int size;
129         
130         size = obj->klass->instance_size;
131         o = mono_object_allocate (size);
132         /* FIXME: handle arrays... */
133         
134         memcpy (o, obj, size);
135
136         return o;
137 }
138
139 MonoArray*
140 mono_array_new_full (MonoClass *array_class, guint32 *lengths, guint32 *lower_bounds)
141 {
142         guint32 byte_len;
143         MonoObject *o;
144         MonoArray *array;
145         MonoArrayBounds *bounds;
146         int i;
147
148         if (!array_class->inited)
149                 mono_class_init (array_class);
150         byte_len = mono_array_element_size (array_class);
151
152         bounds = g_malloc0 (sizeof (MonoArrayBounds) * array_class->rank);
153         for (i = 0; i < array_class->rank; ++i) {
154                 bounds [i].length = lengths [i];
155                 byte_len *= lengths [i];
156         }
157
158         if (lower_bounds)
159                 for (i = 0; i < array_class->rank; ++i)
160                         bounds [i].lower_bound = lower_bounds [i];
161         /* 
162          * Following three lines almost taken from mono_object_new ():
163          * they need to be kept in sync.
164          */
165         o = mono_object_allocate (sizeof (MonoArray) + byte_len);
166         if (!o)
167                 G_BREAKPOINT ();
168         o->klass = array_class;
169
170         array = (MonoArray*)o;
171
172         array->bounds = bounds;
173         array->max_length = bounds [0].length;
174
175         return array;
176 }
177
178 /*
179  * mono_array_new:
180  * @image: image where the object is being referenced
181  * @eclass: element class
182  * @n: number of array elements
183  *
184  * This routine creates a new szarray with @n elements of type @token
185  */
186 MonoArray *
187 mono_array_new (MonoClass *eclass, guint32 n)
188 {
189         MonoClass *ac;
190
191         ac = mono_array_class_get (eclass, 1);
192         g_assert (ac != NULL);
193
194         return mono_array_new_full (ac, &n, NULL);
195 }
196
197 /**
198  * mono_string_new_utf16:
199  * @text: a pointer to an utf16 string
200  * @len: the length of the string
201  *
202  * Returns: A newly created string object which contains @text.
203  */
204 MonoString *
205 mono_string_new_utf16 (const guint16 *text, gint32 len)
206 {
207         MonoString *s;
208         MonoArray *ca;
209
210         s = (MonoString*)mono_object_new (mono_defaults.string_class);
211         g_assert (s != NULL);
212
213         ca = (MonoArray *)mono_array_new (mono_defaults.string_class, len);
214         g_assert (ca != NULL);
215         
216         s->c_str = ca;
217         s->length = len;
218
219         memcpy (ca->vector, text, len * 2);
220
221         return s;
222 }
223
224 /**
225  * mono_string_new:
226  * @text: a pointer to an utf8 string
227  *
228  * Returns: A newly created string object which contains @text.
229  */
230 MonoString*
231 mono_string_new (const char *text)
232 {
233         GError *error = NULL;
234         MonoString *o = NULL;
235         guint16 *ut;
236         glong items_written;
237         int l;
238
239         l = strlen (text);
240         
241         ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
242
243         if (!error)
244                 o = mono_string_new_utf16 (ut, items_written);
245         else 
246                 g_error_free (error);
247
248         g_free (ut);
249
250         return o;
251 }
252
253 /**
254  * mono_value_box:
255  * @class: the class of the value
256  * @value: a pointer to the unboxed data
257  *
258  * Returns: A newly created object which contains @value.
259  */
260 MonoObject *
261 mono_value_box (MonoClass *class, gpointer value)
262 {
263         MonoObject *res;
264         int size;
265
266         g_assert (class->valuetype);
267
268         size = mono_class_instance_size (class);
269         res = mono_object_allocate (size);
270         res->klass = class;
271
272         size = size - sizeof (MonoObject);
273
274         memcpy ((char *)res + sizeof (MonoObject), value, size);
275
276         return res;
277 }
278
279 /**
280  * mono_object_isinst:
281  * @obj: an object
282  * @klass: a pointer to a class 
283  *
284  * Returns: @obj if @obj is derived from @klass
285  */
286 MonoObject *
287 mono_object_isinst (MonoObject *obj, MonoClass *klass)
288 {
289         MonoClass *oklass;
290
291         if (!obj)
292                 return NULL;
293
294         oklass = obj->klass;
295
296         if (!klass->inited)
297                 mono_class_init (klass);
298
299         if (klass->flags & TYPE_ATTRIBUTE_INTERFACE) {
300                 if ((klass->interface_id <= oklass->max_interface_id) &&
301                     oklass->interface_offsets [klass->interface_id])
302                         return obj;
303         } else {
304                 if ((oklass->baseval - klass->baseval) <= klass->diffval)
305                         return obj;
306         }
307
308         return NULL;
309 }
310
311 static GHashTable *ldstr_table = NULL;
312
313 static int
314 ldstr_hash (const char* str)
315 {
316         guint len, h;
317         const char *end;
318         len = mono_metadata_decode_blob_size (str, &str);
319         end = str + len;
320         h = *str;
321         /*
322          * FIXME: The distribution may not be so nice with lots of
323          * null chars in the string.
324          */
325         for (str += 1; str < end; str++)
326                 h = (h << 5) - h + *str;
327         return h;
328 }
329
330 static gboolean
331 ldstr_equal (const char *str1, const char *str2) {
332         int len;
333         if ((len=mono_metadata_decode_blob_size (str1, &str1)) !=
334                                 mono_metadata_decode_blob_size (str2, &str2))
335                 return 0;
336         return memcmp (str1, str2, len) == 0;
337 }
338
339 typedef struct {
340         MonoString *obj;
341         MonoString *found;
342 } InternCheck;
343
344 static void
345 check_interned (gpointer key, MonoString *value, InternCheck *check)
346 {
347         if (value == check->obj)
348                 check->found = value;
349 }
350
351 MonoString*
352 mono_string_is_interned (MonoString *o)
353 {
354         InternCheck check;
355         check.obj = o;
356         check.found = NULL;
357         /*
358          * Yes, this is slow. Our System.String implementation needs to be redone.
359          * And GLib needs foreach() methods that can be stopped halfway.
360          */
361         g_hash_table_foreach (ldstr_table, (GHFunc)check_interned, &check);
362         return check.found;
363 }
364
365 MonoString*
366 mono_string_intern (MonoString *str)
367 {
368         MonoString *res;
369         char *ins = g_malloc (4 + str->length * 2);
370         char *p;
371         
372         /* Encode the length */
373         p = ins;
374         mono_metadata_encode_value (str->length, p, &p);
375         memcpy (p, str->c_str->vector, str->length * 2);
376         
377         if ((res = g_hash_table_lookup (ldstr_table, str))) {
378                 g_free (ins);
379                 return res;
380         }
381         g_hash_table_insert (ldstr_table, ins, str);
382         return str;
383 }
384
385 MonoString*
386 mono_ldstr (MonoImage *image, guint32 index)
387 {
388         const char *str, *sig;
389         MonoString *o;
390         size_t len2;
391         
392         if (!ldstr_table)
393                 ldstr_table = g_hash_table_new ((GHashFunc)ldstr_hash, (GCompareFunc)ldstr_equal);
394         
395         sig = str = mono_metadata_user_string (image, index);
396         
397         if ((o = g_hash_table_lookup (ldstr_table, str)))
398                 return o;
399         
400         len2 = mono_metadata_decode_blob_size (str, &str);
401 #if G_BYTE_ORDER != G_LITTLE_ENDIAN
402 #define SWAP16(x) (x) = GUINT16_FROM_LE ((x))
403         {
404                 gint i;
405                 guint16 *s;
406
407                 /* FIXME: it will be better to just add WRITE and after get it to previous state */
408                 mprotect ((void *) ((int) str & ~(PAGESIZE - 1)), len2 + ((int) str & (PAGESIZE - 1)),
409                                     PROT_READ | PROT_WRITE | PROT_EXEC);
410                 len2 >>= 1;
411                 /* printf ("swap %p\n", str); */
412                 for (i = 0, s = (guint16 *) str; i < len2; i++, s++) {
413                         *s = ((*s & 0xff) << 8) | (*s >> 8);
414                 }
415         }
416 #undef SWAP16
417 #else
418                 len2 >>= 1;
419 #endif
420
421         o = mono_string_new_utf16 ((guint16*)str, len2);
422         g_hash_table_insert (ldstr_table, (gpointer)sig, o);
423
424         return o;
425 }
426
427 char *
428 mono_string_to_utf8 (MonoString *s)
429 {
430         char *as, *vector;
431         GError *error = NULL;
432
433         g_assert (s != NULL);
434
435         if (!s->length || !s->c_str)
436                 return g_strdup ("");
437
438         vector = (char*)s->c_str->vector;
439
440         g_assert (vector != NULL);
441
442         as = g_utf16_to_utf8 (vector, s->length, NULL, NULL, &error);
443
444         g_assert (!error);
445
446         return as;
447 }
448
449 char *
450 mono_string_to_utf16 (MonoString *s)
451 {
452         char *as;
453
454         g_assert (s != NULL);
455
456         as = g_malloc ((s->length * 2) + 2);
457         as [(s->length * 2)] = '\0';
458         as [(s->length * 2) + 1] = '\0';
459
460         if (!s->length || !s->c_str) {
461                 return (as);
462         }
463         
464         memcpy (as, mono_string_chars(s), s->length * 2);
465         
466         return (as);
467 }
468
469 static void
470 default_ex_handler (MonoException *ex)
471 {
472         MonoObject *o = (MonoObject*)ex;
473         g_error ("Exception %s.%s raised in C code", o->klass->name_space, o->klass->name);
474 }
475
476 static MonoExceptionFunc ex_handler = default_ex_handler;
477
478 void
479 mono_install_handler        (MonoExceptionFunc func)
480 {
481         ex_handler = func? func: default_ex_handler;
482 }
483
484 void
485 mono_raise_exception (MonoException *ex) 
486 {
487         ex_handler (ex);
488 }
489