[Mono-dev] [Patch] AssemblyName ctor (yes, again)

Paolo Molaro lupus at ximian.com
Thu Aug 25 09:42:52 EDT 2005


On 08/24/05 Carlos Alberto Cortez wrote:
> The attached patches contain some changes to runtime functions to
> support the new AssemblyName ctor. They also add an internal call for
> this ctor.
> 
> I added a pair of new fields to MonoAssemblyName (is_persistent and
> is_version_defined) to define if the public_key was parsed (should be
> freed) or is persistent (image metadata). The second is used for
> avoiding creating the version if it was not defined (I need it to
> mimic .Net behavior).
> 
> Comments?
> 
> PD - The run rests fine with the patches.

> Index: assembly.c
> ===================================================================
> --- assembly.c	(revisión: 48811)
> +++ assembly.c	(copia de trabajo)
> @@ -449,6 +449,7 @@
>  
>  	mono_metadata_decode_row (t, 0, cols, MONO_ASSEMBLY_SIZE);
>  
> +	aname->is_persistent = TRUE;
>  	aname->hash_len = 0;
>  	aname->hash_value = NULL;
>  	aname->name = mono_metadata_string_heap (image, cols [MONO_ASSEMBLY_NAME]);
> @@ -458,6 +459,7 @@
>  	aname->minor = cols [MONO_ASSEMBLY_MINOR_VERSION];
>  	aname->build = cols [MONO_ASSEMBLY_BUILD_NUMBER];
>  	aname->revision = cols [MONO_ASSEMBLY_REV_NUMBER];
> +	aname->is_version_defined = TRUE;
>  	aname->hash_alg = cols [MONO_ASSEMBLY_HASH_ALG];
>  	if (cols [MONO_ASSEMBLY_PUBLIC_KEY]) {
>  		gchar* token = g_malloc (8);
> @@ -1169,23 +1171,35 @@
>  	g_free ((void *) aname->name);
>  	g_free ((void *) aname->culture);
>  	g_free ((void *) aname->hash_value);
> +
> +	if (!aname->is_persistent)
> +		g_free ((void *) aname->public_key);
>  }
>  
>  static gboolean
> -build_assembly_name (const char *name, const char *version, const char *culture, const char *token, MonoAssemblyName *aname)
> +build_assembly_name (const char *name, const char *version, const char *culture, const char *token, const char *key, MonoAssemblyName *aname)
>  {
>  	gint major, minor, build, revision;
>  
>  	memset (aname, 0, sizeof (MonoAssemblyName));
>  
>  	if (version) {
> -		if (sscanf (version, "%u.%u.%u.%u", &major, &minor, &build, &revision) != 4)
> +		gchar **tmp, **parts = g_strsplit (version, ".", 4);
> +
> +		tmp = parts;
> +		major = *tmp ? atoi (*tmp++) : -1;

Use strtol() for proper error checking.

> +		aname->major = (guint16) major;

Why the cast?

> @@ -1197,8 +1211,35 @@
>  			aname->culture = g_strdup (culture);
>  	}
>  	
> -	if (token && strncmp (token, "null", 4) != 0)
> +	if (token && strncmp (token, "null", 4) != 0) {
> +		if (strlen (token) != MONO_PUBLIC_KEY_TOKEN_LENGTH - 1)
> +			return FALSE;
> +		
>  		g_strlcpy ((char*)aname->public_key_token, token, MONO_PUBLIC_KEY_TOKEN_LENGTH);
> +	}
> +
> +	if (key && strncmp (key, "null", 4) != 0) {
> +		gchar *arr, *tok, *encoded;
> +		int i, j;
> +		
> +		if (strlen (key) != MONO_PUBLIC_KEY_LENGTH)
> +			return FALSE;

Can't the length change based on the flags? Sebastien?

> +		arr = g_malloc (160);
> +		for (i = 0, j = 0; i < 160; i++) {
> +			arr [i] = g_ascii_xdigit_value (key [j++]) << 4;
> +			arr [i] |= g_ascii_xdigit_value (key [j++]);
> +		}
> +		aname->public_key = (guint8*) arr;
> +		
> +		// We also need to generate the key token
> +		tok = g_malloc (8);

Ugh, just alloc it on the stack.

> +		mono_digest_get_public_token ((guchar*) tok, aname->public_key, 160);
> +		encoded = encode_public_tok ((guchar*) tok, 8);
> +		g_strlcpy ((char*)aname->public_key_token, encoded, MONO_PUBLIC_KEY_TOKEN_LENGTH);
> +		g_free (tok);
> +		g_free (encoded);
> +	}
>  	
>  	return TRUE;
>  }
> @@ -1215,7 +1256,7 @@
>  		return FALSE;
>  	}
>  	
> -	res = build_assembly_name (name, parts[0], parts[1], parts[2], aname);
> +	res = build_assembly_name (name, parts[0], parts[1], parts[2], NULL, aname);
>  	g_strfreev (parts);
>  	return res;
>  }
> @@ -1236,6 +1277,7 @@
>  	gchar *version = NULL;
>  	gchar *culture = NULL;
>  	gchar *token = NULL;
> +	gchar *key = NULL;
>  	gboolean res;
>  	gchar *value;
>  	gchar **parts;
> @@ -1270,12 +1312,18 @@
>  			tmp++;
>  			continue;
>  		}
> +
> +		if (!g_ascii_strncasecmp (value, "PublicKey=", 10)) {
> +			key = g_strstrip (value + 10);
> +			tmp++;
> +			continue;
> +		}
>  		
>  		g_strfreev (parts);
>  		return FALSE;
>  	}
>  
> -	res = build_assembly_name (dllname, version, culture, token, aname);
> +	res = build_assembly_name (dllname, version, culture, token, key, aname);
>  	g_strfreev (parts);
>  	return res;
>  }
> Index: image.h
> ===================================================================
> --- image.h	(revisión: 48811)
> +++ image.h	(copia de trabajo)
> @@ -12,6 +12,7 @@
>  typedef struct _MonoTableInfo MonoTableInfo;
>  
>  #define MONO_PUBLIC_KEY_TOKEN_LENGTH	17
> +#define MONO_PUBLIC_KEY_LENGTH	320
>  
>  typedef struct {
>  	const char *name;
> @@ -24,6 +25,8 @@
>  	guint32 hash_len;
>  	guint32 flags;
>  	guint16 major, minor, build, revision;
> +	guint is_persistent : 1;
> +	guint is_version_defined : 1;
>  } MonoAssemblyName;

This break the ABI: is_version_defined is not needed since you can check
the fields anyway.
is_persistent can go away some other way (for example by always having
public_key allocated, but it would be better to find another which
doesn't make us waste memory).

> Index: icall.c
> ===================================================================
> --- icall.c	(revisión: 48811)
> +++ icall.c	(copia de trabajo)
> @@ -4132,12 +4132,14 @@
>  	MONO_ARCH_SAVE_REGS;
>  
>  	aname->name = mono_string_new (domain, name->name);
> -	aname->major = name->major;
> -	aname->minor = name->minor;
> -	aname->build = name->build;
> -	aname->revision = name->revision;
>  	aname->hashalg = name->hash_alg;
> -	aname->version = create_version (domain, name->major, name->minor, name->build, name->revision);
> +	if (name->is_version_defined) {

You can replace this flag check by checking the fields themselves.

>  	if (name->public_key) {
> -		pkey_ptr = (char*)name->public_key;
> -		pkey_len = mono_metadata_decode_blob_size (pkey_ptr, &pkey_ptr);
> +		// We could be getting a user generated key
> +		if (!name->is_persistent) {
> +			pkey_ptr = (char*)name->public_key;
> +			pkey_len = 160; // Default length

This doesn't look safe at all. You could encode the length when you set
the public_key field in the first place.

> +static void
> +ves_icall_System_Reflection_AssemblyName_ParseName (MonoReflectionAssemblyName *name, MonoString *assname)
> +{
> +	MonoAssemblyName aname;
> +	MonoDomain *domain = mono_object_domain (name);
> +	char *val;
> +
> +	val = mono_string_to_utf8 (assname);
> +	if (!mono_assembly_name_parse (val, &aname)) {

Make the icall return a error flag and raise the exception in managed
code.

Thanks.

lupus

-- 
-----------------------------------------------------------------
lupus at debian.org                                     debian/rules
lupus at ximian.com                             Monkeys do it better



More information about the Mono-devel-list mailing list