[RFC 5/6] aarch64 gas: Record dynamic allocations during startup

Matthieu Longo matthieu.longo@arm.com
Tue Mar 3 17:21:01 GMT 2026


On 03/03/2026 12:41, Alice Carlotti wrote:
> This allows them to be freed at exit, removing them from LeakSanitizer
> reports.
> 
> 
> diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
> index b580815bdfa20f358c818925b44f8bb2e2adba94..3dde65e3d91e346bd271189f11d119f78355a92d 100644
> --- a/gas/config/tc-aarch64.c
> +++ b/gas/config/tc-aarch64.c
> @@ -10454,6 +10454,41 @@ aarch64_adjust_symtab (void)
>   #endif
>   }
>   
> +struct aarch64_pointer_list
> +{
> +  void *ptr;
> +  struct aarch64_pointer_list *next;
> +};
> +
> +/* A linked list of dynamic memory allocations that are created once during
> +   startup.  These allocations can be freed when the assembler finishes, to
> +   prevent them appearing in memory leak reports.  */
> +
> +static struct
> +aarch64_pointer_list *aarch64_startup_allocations = NULL;
> +
> +static inline void
> +push_startup_allocation (void *ptr)
> +{
> +  struct aarch64_pointer_list *head = XNEW (struct aarch64_pointer_list);
> +  head->ptr = ptr;
> +  head->next = aarch64_startup_allocations;
> +  aarch64_startup_allocations = head;
> +}
> +
> +static void
> +free_startup_allocations (void)
> +{
> +  struct aarch64_pointer_list *strings = aarch64_startup_allocations;
> +  while (strings)
> +    {
> +      struct aarch64_pointer_list *next = strings->next;
> +      free (strings->ptr);
> +      free (strings);
> +      strings = next;
> +    }
> +}
> +

It might be preferable to use objalloc as discussed with Richard Earnshaw.

If you change the parameters of the htab as follows:

static struct objalloc *OBJ_ALLOC_HTABS = NULL;

/* at the top of md_begin() */
OBJ_ALLOC_HTABS = objalloc_create ();

/* helper for htab_malloc_parameter */
void *dyn_str_htab_alloc (unsigned long size)
{
   return _objalloc_alloc (OBJ_ALLOC_HTABS, size);
}

/* Helper to create a htab */
static htab_t
dyn_str_htab_create (void)
{
   return htab_create_alloc (16, hash_string_tuple, eq_string_tuple,
			    NULL, dyn_str_hashtab_calloc, NULL);
}


Then, the freeing of the memory at md_end() can be simply summarized with:
objalloc_free (OBJ_ALLOC_HTABS);

This solution has the advantage of reusing available utilities.
The only drawback seems to be the replacement of all xstrdup() with your own implementation using _objalloc_alloc (). This cost seems acceptable.

>   static void
>   checked_hash_insert (htab_t table, const char *key, const void *value)
>   {
> @@ -10478,6 +10513,7 @@ fill_instruction_hash_table (void)
>         templ = str_hash_find (aarch64_ops_hsh, opcode->name);
>   
>         new_templ = XNEW (templates);
> +      push_startup_allocation (new_templ);
>         new_templ->opcode = opcode;
>         new_templ->next = NULL;
>   
> @@ -10503,7 +10539,7 @@ convert_to_upper (char *dst, const char *src, size_t num)
>   
>   /* Assume STR point to a lower-case string, allocate, convert and return
>      the corresponding upper-case string.  */
> -static inline const char*
> +static inline char*
>   get_upper_str (const char *str)
>   {
>     char *ret;
> @@ -10513,6 +10549,20 @@ get_upper_str (const char *str)
>     return ret;
>   }
>   
> +/* Some operands are recognised in either lower case or upper case forms.
> +   Create entries for both versions.  Record a pointer to the dynamically
> +   allocated upper case string so that we can free it later.  */
> +
> +static void
> +checked_hash_insert_with_upper (htab_t table, const char *key,
> +				const void *value)
> +{
> +  checked_hash_insert (table, key, value);
> +  char *upper = get_upper_str (key);
> +  checked_hash_insert (table, upper, value);
> +  push_startup_allocation (upper);
> +}
> +

Ok for this refactoring.

>   /* MD interface: Initialization.  */
>   
>   void
> @@ -10608,11 +10658,8 @@ md_begin (void)
>     for (i = 0; aarch64_operand_modifiers[i].name != NULL; i++)
>       {
>         const char *name = aarch64_operand_modifiers[i].name;
> -      checked_hash_insert (aarch64_shift_hsh, name,
> -			   aarch64_operand_modifiers + i);
> -      /* Also hash the name in the upper case.  */
> -      checked_hash_insert (aarch64_shift_hsh, get_upper_str (name),
> -			   aarch64_operand_modifiers + i);
> +      checked_hash_insert_with_upper (aarch64_shift_hsh, name,
> +				      aarch64_operand_modifiers + i);
>       }
>   
>     for (i = 0; i < ARRAY_SIZE (aarch64_conds); i++)
> @@ -10625,11 +10672,8 @@ md_begin (void)
>   	  const char *name = aarch64_conds[i].names[j];
>   	  if (name == NULL)
>   	    break;
> -	  checked_hash_insert (aarch64_cond_hsh, name,
> -			       aarch64_conds + i);
> -	  /* Also hash the name in the upper case.  */
> -	  checked_hash_insert (aarch64_cond_hsh, get_upper_str (name),
> -			       aarch64_conds + i);
> +	  checked_hash_insert_with_upper (aarch64_cond_hsh, name,
> +					  aarch64_conds + i);
>   	}
>       }
>   
> @@ -10639,21 +10683,15 @@ md_begin (void)
>         /* Skip xx00 - the unallocated values of option.  */
>         if ((i & 0x3) == 0)
>   	continue;
> -      checked_hash_insert (aarch64_barrier_opt_hsh, name,
> -			   aarch64_barrier_options + i);
> -      /* Also hash the name in the upper case.  */
> -      checked_hash_insert (aarch64_barrier_opt_hsh, get_upper_str (name),
> -			   aarch64_barrier_options + i);
> +      checked_hash_insert_with_upper (aarch64_barrier_opt_hsh, name,
> +				      aarch64_barrier_options + i);
>       }
>   
>     for (i = 0; i < ARRAY_SIZE (aarch64_barrier_dsb_nxs_options); i++)
>       {
>         const char *name = aarch64_barrier_dsb_nxs_options[i].name;
> -      checked_hash_insert (aarch64_barrier_opt_hsh, name,
> -			   aarch64_barrier_dsb_nxs_options + i);
> -      /* Also hash the name in the upper case.  */
> -      checked_hash_insert (aarch64_barrier_opt_hsh, get_upper_str (name),
> -			   aarch64_barrier_dsb_nxs_options + i);
> +      checked_hash_insert_with_upper (aarch64_barrier_opt_hsh, name,
> +				      aarch64_barrier_dsb_nxs_options + i);
>       }
>   
>     for (i = 0; i < ARRAY_SIZE (aarch64_prfops); i++)
> @@ -10662,11 +10700,8 @@ md_begin (void)
>         /* Skip the unallocated hint encodings.  */
>         if (name == NULL)
>   	continue;
> -      checked_hash_insert (aarch64_pldop_hsh, name,
> -			   aarch64_prfops + i);
> -      /* Also hash the name in the upper case.  */
> -      checked_hash_insert (aarch64_pldop_hsh, get_upper_str (name),
> -			   aarch64_prfops + i);
> +      checked_hash_insert_with_upper (aarch64_pldop_hsh, name,
> +				      aarch64_prfops + i);
>       }
>   
>     for (i = 0; aarch64_hint_options[i].name != NULL; i++)
> @@ -10676,11 +10711,8 @@ md_begin (void)
>   	 up in the hash table.  */
>         if (*name == '\0')
>   	continue;
> -      checked_hash_insert (aarch64_hint_opt_hsh, name,
> -			   aarch64_hint_options + i);
> -      /* Also hash the name in the upper case.  */
> -      checked_hash_insert (aarch64_hint_opt_hsh, get_upper_str (name),
> -			   aarch64_hint_options + i);
> +      checked_hash_insert_with_upper (aarch64_hint_opt_hsh, name,
> +				      aarch64_hint_options + i);
>       }
>   
>     for (i = 0; aarch64_sys_ins_gic[i].name != NULL; i++)
> @@ -10745,6 +10777,8 @@ aarch64_md_end (void)
>     htab_delete (aarch64_barrier_opt_hsh);
>     htab_delete (aarch64_pldop_hsh);
>     htab_delete (aarch64_hint_opt_hsh);
> +
> +  free_startup_allocations();
>   }
>   
>   /* Command line processing.  */

Matthieu


More information about the Binutils mailing list