This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Ada] Fix another alloc/free discrepancy for unconstrained arrays


This is an annoying old bug, filed as PR ada/34173, which showed up on
a testcase introduced when a fix for another problem was introduced

  http://gcc.gnu.org/ml/gcc-patches/2007-11/msg01095.html

The testcase below misbehaves on a number of targets because the
address we pass to Free does not match what the corresponding malloc
call returned.

   with Ada.Unchecked_Deallocation;
   procedure Unc_Memfree is

      type List is array (Natural range <>) of Integer;
      for List'Alignment use Standard'Maximum_Alignment;

      type Fat_List_Access is access all List;

      procedure Release_Fat is new Ada.Unchecked_Deallocation
        (Object => List, Name => Fat_List_Access);

      My_Fat_List : Fat_List_Access;

   begin
      My_Fat_List := new List (1 .. 3);
      Release_Fat (My_Fat_List);
   end;
              
 The alloc/free discrepency for this case stems from a difference
 in the DECL_ALIGN attached to the ARRAY field of an object with
 template, as computed in two different places.

 The easiest way to observe this is from breakpoints on
 build_unc_object_type. This is called twice on the testcase at hand:

 1/ from gnat_to_gnu_entity to process the E_Array_Type node
 2/ from build_allocator to process the allocation request

 On x86 for 1/, the alignment of List is *not* propagated in the ARRAY
 field of the unconstrained object type, eventhough it is set on the
 corresponding array type.  This is


 Breakpoint 1, build_unc_object_type

    (gdb) pt type
    <record_type 0xb71b0564 p__list___XUT type_3 BLK
       fields <field_decl 0xb71b05c0 BOUNDS
           chain <field_decl 0xb71b061c ARRAY
                                        ^^^^^
                  type <array_type 0xb71b02e0 p__list___XUA>
                  align 32 offset_align 128 bit offset <integer_cst 64>
                  ^^^^^^^^
 despite

    (gdb) pt object_type
    <array_type 0xb71b02e0 p__list___XUA
       type <integer_type 0xb71b0284 integer
       ...
       align 128 symtab 0 alias set -1
       ^^^^^^^^^

 There are multiple factors at play to get there:

  a/ gigi first creates a field decl with the expected alignment,
     DECL_USER_ALIGN is not set on it,

  b/ We get into

     layout_decl
      if (! DECL_USER_ALIGN (decl) && ...
        { ...
        #ifdef ADJUST_FIELD_ALIGN
          DECL_ALIGN (decl) = ADJUST_FIELD_ALIGN (decl, DECL_ALIGN (decl));
        ...

 c/ this routes to x86_field_alignment which downgrades the field alignment
    because this is an array of integers.


 From build_allocator, the object_type is a padding record type,
 x86_field_alignment leaves the alignment set by gigi alone and we get

    chain <field_decl 0xb71b0ebc ARRAY type <record_type p__S3b___PAD>
            BLK file p.adb line 22
            align 128

 From there, the array is placed 16bytes off the bounds, while
 N_Free_Statements thinks its only 8bytes off from the unconstrained
 type description.

 N_Free_Statement uses this offset to compute the storage address
 to 'free' from the array address, as per

          if (TREE_CODE (gnu_obj_type) == RECORD_TYPE
              && TYPE_CONTAINS_TEMPLATE_P (gnu_obj_type))
            {
              tree gnu_char_ptr_type = build_pointer_type (char_type_node);
              tree gnu_pos = byte_position (TYPE_FIELDS (gnu_obj_type));
              tree gnu_byte_offset
                = convert (gnu_char_ptr_type,
                           size_diffop (size_zero_node, gnu_pos));

              gnu_ptr = convert (gnu_char_ptr_type, gnu_ptr);
              gnu_ptr = build_binary_op (MINUS_EXPR, gnu_char_ptr_type,
                                         gnu_ptr, gnu_byte_offset);
            }

 and it gets it wrong.

 The fix applied here is to ensure that the ARRAY field has
 DECL_USER_ALIGN set when the alignment comes from an alignment clause,
 which is legitimate in any case and prevents the downgrade from
 layout_decl.

 Tested locally on x86-pc-linux-gnu.
 Bootstrapped and reg tested on x86_64-pc-linux-gnu.
 Committing to mainline.

 2007-12-07  Olivier Hainque  <hainque@adacore.com>
 
	PR ada/34173
	* decl.c (gnat_to_gnu_entity) <case E_Array_Type>: When setting
	the alignment on the GCC XUA array type, set TYPE_USER_ALIGN if
	this is from an alignment clause on the GNAT entity.
	* utils.c (create_field_decl): Rewrite the computation of DECL_ALIGN
	to distinguish the case where we set it from the type's alignment.
	When so, propagate TYPE_USER_ALIGN into DECL_USER_ALIGN to indicate
	whether this alignment was set from an explicit alignment clause.

Attachment: unc_memfree.dif
Description: Text document


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]