Commit 40c32948 by Paul Thomas

re PR fortran/41478 (Corrupted memory using PACK for derived-types with allocated components)

2010-01-14  Paul Thomas  <pault@gcc.gnu.org>

        PR fortran/41478
        * trans-array.c (duplicate_allocatable):  Static version of
	gfc_duplicate_allocatable with provision to handle scalar
	components. New boolean argument to switch off call to malloc
	if true.
	(gfc_duplicate_allocatable): New function to call above with
	new argument false.
	(gfc_copy_allocatable_data): New function to call above with
	new argument true.
	(structure_alloc_comps): Do not apply indirect reference to
	scalar pointers. Add new section to copy allocatable components
	of arrays. Extend copying of allocatable components to include
	scalars.
	(gfc_copy_only_alloc_comp): New function to copy allocatable
	component derived types, without allocating the base structure.
	* trans-array.h : Add primitive for gfc_copy_allocatable_data.
	Add primitive for gfc_copy_only_alloc_comp.
	* trans-expr.c (gfc_conv_procedure_call): After calls to
	transformational functions with results that are derived types
	with allocatable components, copy the components in the result.
	(gfc_trans_arrayfunc_assign): Deallocate allocatable components
	of lhs derived types before allocation.
	

2010-01-14  Paul Thomas  <pault@gcc.gnu.org>

        PR fortran/41478
        * gfortran.dg/alloc_comp_scalar_1.f90: New test.
        * gfortran.dg/alloc_comp_transformational_1.f90: New test.

From-SVN: r155877
parent 08b02036
2010-01-14 Paul Thomas <pault@gcc.gnu.org> 2010-01-14 Paul Thomas <pault@gcc.gnu.org>
PR fortran/41478
* trans-array.c (duplicate_allocatable): Static version of
gfc_duplicate_allocatable with provision to handle scalar
components. New boolean argument to switch off call to malloc
if true.
(gfc_duplicate_allocatable): New function to call above with
new argument false.
(gfc_copy_allocatable_data): New function to call above with
new argument true.
(structure_alloc_comps): Do not apply indirect reference to
scalar pointers. Add new section to copy allocatable components
of arrays. Extend copying of allocatable components to include
scalars.
(gfc_copy_only_alloc_comp): New function to copy allocatable
component derived types, without allocating the base structure.
* trans-array.h : Add primitive for gfc_copy_allocatable_data.
Add primitive for gfc_copy_only_alloc_comp.
* trans-expr.c (gfc_conv_procedure_call): After calls to
transformational functions with results that are derived types
with allocatable components, copy the components in the result.
(gfc_trans_arrayfunc_assign): Deallocate allocatable components
of lhs derived types before allocation.
2010-01-14 Paul Thomas <pault@gcc.gnu.org>
PR fortran/42481 PR fortran/42481
* module.c (load_generic_interfaces): If a procedure that is * module.c (load_generic_interfaces): If a procedure that is
use associated but not generic is given an interface that use associated but not generic is given an interface that
......
...@@ -5711,10 +5711,12 @@ get_full_array_size (stmtblock_t *block, tree decl, int rank) ...@@ -5711,10 +5711,12 @@ get_full_array_size (stmtblock_t *block, tree decl, int rank)
} }
/* Allocate dest to the same size as src, and copy src -> dest. */ /* Allocate dest to the same size as src, and copy src -> dest.
If no_malloc is set, only the copy is done. */
tree static tree
gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank) duplicate_allocatable(tree dest, tree src, tree type, int rank,
bool no_malloc)
{ {
tree tmp; tree tmp;
tree size; tree size;
...@@ -5723,35 +5725,66 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank) ...@@ -5723,35 +5725,66 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank)
tree null_data; tree null_data;
stmtblock_t block; stmtblock_t block;
/* If the source is null, set the destination to null. */ /* If the source is null, set the destination to null. Then,
allocate memory to the destination. */
gfc_init_block (&block); gfc_init_block (&block);
gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
null_data = gfc_finish_block (&block);
gfc_init_block (&block); if (rank == 0)
{
tmp = null_pointer_node;
tmp = fold_build2 (MODIFY_EXPR, type, dest, tmp);
gfc_add_expr_to_block (&block, tmp);
null_data = gfc_finish_block (&block);
gfc_init_block (&block);
size = TYPE_SIZE_UNIT (type);
if (!no_malloc)
{
tmp = gfc_call_malloc (&block, type, size);
tmp = fold_build2 (MODIFY_EXPR, void_type_node, dest,
fold_convert (type, tmp));
gfc_add_expr_to_block (&block, tmp);
}
tmp = built_in_decls[BUILT_IN_MEMCPY];
tmp = build_call_expr_loc (input_location, tmp, 3,
dest, src, size);
}
else
{
gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
null_data = gfc_finish_block (&block);
gfc_init_block (&block);
nelems = get_full_array_size (&block, src, rank);
tmp = fold_convert (gfc_array_index_type,
TYPE_SIZE_UNIT (gfc_get_element_type (type)));
size = fold_build2 (MULT_EXPR, gfc_array_index_type, nelems, tmp);
if (!no_malloc)
{
tmp = TREE_TYPE (gfc_conv_descriptor_data_get (src));
tmp = gfc_call_malloc (&block, tmp, size);
gfc_conv_descriptor_data_set (&block, dest, tmp);
}
/* We know the temporary and the value will be the same length,
so can use memcpy. */
tmp = built_in_decls[BUILT_IN_MEMCPY];
tmp = build_call_expr_loc (input_location,
tmp, 3, gfc_conv_descriptor_data_get (dest),
gfc_conv_descriptor_data_get (src), size);
}
nelems = get_full_array_size (&block, src, rank);
size = fold_build2 (MULT_EXPR, gfc_array_index_type, nelems,
fold_convert (gfc_array_index_type,
TYPE_SIZE_UNIT (gfc_get_element_type (type))));
/* Allocate memory to the destination. */
tmp = gfc_call_malloc (&block, TREE_TYPE (gfc_conv_descriptor_data_get (src)),
size);
gfc_conv_descriptor_data_set (&block, dest, tmp);
/* We know the temporary and the value will be the same length,
so can use memcpy. */
tmp = built_in_decls[BUILT_IN_MEMCPY];
tmp = build_call_expr_loc (input_location,
tmp, 3, gfc_conv_descriptor_data_get (dest),
gfc_conv_descriptor_data_get (src), size);
gfc_add_expr_to_block (&block, tmp); gfc_add_expr_to_block (&block, tmp);
tmp = gfc_finish_block (&block); tmp = gfc_finish_block (&block);
/* Null the destination if the source is null; otherwise do /* Null the destination if the source is null; otherwise do
the allocate and copy. */ the allocate and copy. */
null_cond = gfc_conv_descriptor_data_get (src); if (rank == 0)
null_cond = src;
else
null_cond = gfc_conv_descriptor_data_get (src);
null_cond = convert (pvoid_type_node, null_cond); null_cond = convert (pvoid_type_node, null_cond);
null_cond = fold_build2 (NE_EXPR, boolean_type_node, null_cond = fold_build2 (NE_EXPR, boolean_type_node,
null_cond, null_pointer_node); null_cond, null_pointer_node);
...@@ -5759,11 +5792,30 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank) ...@@ -5759,11 +5792,30 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank)
} }
/* Allocate dest to the same size as src, and copy data src -> dest. */
tree
gfc_duplicate_allocatable (tree dest, tree src, tree type, int rank)
{
return duplicate_allocatable(dest, src, type, rank, false);
}
/* Copy data src -> dest. */
tree
gfc_copy_allocatable_data (tree dest, tree src, tree type, int rank)
{
return duplicate_allocatable(dest, src, type, rank, true);
}
/* Recursively traverse an object of derived type, generating code to /* Recursively traverse an object of derived type, generating code to
deallocate, nullify or copy allocatable components. This is the work horse deallocate, nullify or copy allocatable components. This is the work horse
function for the functions named in this enum. */ function for the functions named in this enum. */
enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP}; enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP,
COPY_ONLY_ALLOC_COMP};
static tree static tree
structure_alloc_comps (gfc_symbol * der_type, tree decl, structure_alloc_comps (gfc_symbol * der_type, tree decl,
...@@ -5786,7 +5838,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, ...@@ -5786,7 +5838,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
gfc_init_block (&fnblock); gfc_init_block (&fnblock);
if (POINTER_TYPE_P (TREE_TYPE (decl))) if (POINTER_TYPE_P (TREE_TYPE (decl)) && rank != 0)
decl = build_fold_indirect_ref_loc (input_location, decl = build_fold_indirect_ref_loc (input_location,
decl); decl);
...@@ -5841,6 +5893,14 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, ...@@ -5841,6 +5893,14 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
dref = gfc_build_array_ref (tmp, index, NULL); dref = gfc_build_array_ref (tmp, index, NULL);
tmp = structure_alloc_comps (der_type, vref, dref, rank, purpose); tmp = structure_alloc_comps (der_type, vref, dref, rank, purpose);
} }
else if (purpose == COPY_ONLY_ALLOC_COMP)
{
tmp = build_fold_indirect_ref_loc (input_location,
gfc_conv_array_data (dest));
dref = gfc_build_array_ref (tmp, index, NULL);
tmp = structure_alloc_comps (der_type, vref, dref, rank,
COPY_ALLOC_COMP);
}
else else
tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose); tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose);
...@@ -5978,7 +6038,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, ...@@ -5978,7 +6038,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
if (c->attr.allocatable && !cmp_has_alloc_comps) if (c->attr.allocatable && !cmp_has_alloc_comps)
{ {
tmp = gfc_duplicate_allocatable(dcmp, comp, ctype, c->as->rank); rank = c->as ? c->as->rank : 0;
tmp = gfc_duplicate_allocatable(dcmp, comp, ctype, rank);
gfc_add_expr_to_block (&fnblock, tmp); gfc_add_expr_to_block (&fnblock, tmp);
} }
...@@ -6025,7 +6086,7 @@ gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank) ...@@ -6025,7 +6086,7 @@ gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank)
/* Recursively traverse an object of derived type, generating code to /* Recursively traverse an object of derived type, generating code to
copy its allocatable components. */ copy it and its allocatable components. */
tree tree
gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
...@@ -6034,6 +6095,16 @@ gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) ...@@ -6034,6 +6095,16 @@ gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
} }
/* Recursively traverse an object of derived type, generating code to
copy only its allocatable components. */
tree
gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
{
return structure_alloc_comps (der_type, decl, dest, rank, COPY_ONLY_ALLOC_COMP);
}
/* NULLIFY an allocatable/pointer array on function entry, free it on exit. /* NULLIFY an allocatable/pointer array on function entry, free it on exit.
Do likewise, recursively if necessary, with the allocatable components of Do likewise, recursively if necessary, with the allocatable components of
derived types. */ derived types. */
......
...@@ -45,7 +45,9 @@ tree gfc_trans_g77_array (gfc_symbol *, tree); ...@@ -45,7 +45,9 @@ tree gfc_trans_g77_array (gfc_symbol *, tree);
/* Generate code to deallocate an array, if it is allocated. */ /* Generate code to deallocate an array, if it is allocated. */
tree gfc_trans_dealloc_allocated (tree); tree gfc_trans_dealloc_allocated (tree);
tree gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank); tree gfc_duplicate_allocatable (tree dest, tree src, tree type, int rank);
tree gfc_copy_allocatable_data (tree dest, tree src, tree type, int rank);
tree gfc_nullify_alloc_comp (gfc_symbol *, tree, int); tree gfc_nullify_alloc_comp (gfc_symbol *, tree, int);
...@@ -53,6 +55,8 @@ tree gfc_deallocate_alloc_comp (gfc_symbol *, tree, int); ...@@ -53,6 +55,8 @@ tree gfc_deallocate_alloc_comp (gfc_symbol *, tree, int);
tree gfc_copy_alloc_comp (gfc_symbol *, tree, tree, int); tree gfc_copy_alloc_comp (gfc_symbol *, tree, tree, int);
tree gfc_copy_only_alloc_comp (gfc_symbol *, tree, tree, int);
/* Add initialization for deferred arrays. */ /* Add initialization for deferred arrays. */
tree gfc_trans_deferred_array (gfc_symbol *, tree); tree gfc_trans_deferred_array (gfc_symbol *, tree);
/* Generate an initializer for a static pointer or allocatable array. */ /* Generate an initializer for a static pointer or allocatable array. */
......
...@@ -2757,6 +2757,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, ...@@ -2757,6 +2757,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
tree var; tree var;
tree len; tree len;
tree stringargs; tree stringargs;
tree result = NULL;
gfc_formal_arglist *formal; gfc_formal_arglist *formal;
int has_alternate_specifier = 0; int has_alternate_specifier = 0;
bool need_interface_mapping; bool need_interface_mapping;
...@@ -3288,6 +3289,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, ...@@ -3288,6 +3289,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
se->expr = build_fold_indirect_ref_loc (input_location, se->expr = build_fold_indirect_ref_loc (input_location,
se->expr); se->expr);
result = build_fold_indirect_ref_loc (input_location,
se->expr);
retargs = gfc_chainon_list (retargs, se->expr); retargs = gfc_chainon_list (retargs, se->expr);
} }
else if (comp && comp->attr.dimension) else if (comp && comp->attr.dimension)
...@@ -3310,8 +3313,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, ...@@ -3310,8 +3313,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
callee_alloc, &se->ss->expr->where); callee_alloc, &se->ss->expr->where);
/* Pass the temporary as the first argument. */ /* Pass the temporary as the first argument. */
tmp = info->descriptor; result = info->descriptor;
tmp = gfc_build_addr_expr (NULL_TREE, tmp); tmp = gfc_build_addr_expr (NULL_TREE, result);
retargs = gfc_chainon_list (retargs, tmp); retargs = gfc_chainon_list (retargs, tmp);
} }
else if (!comp && sym->result->attr.dimension) else if (!comp && sym->result->attr.dimension)
...@@ -3334,8 +3337,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, ...@@ -3334,8 +3337,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
callee_alloc, &se->ss->expr->where); callee_alloc, &se->ss->expr->where);
/* Pass the temporary as the first argument. */ /* Pass the temporary as the first argument. */
tmp = info->descriptor; result = info->descriptor;
tmp = gfc_build_addr_expr (NULL_TREE, tmp); tmp = gfc_build_addr_expr (NULL_TREE, result);
retargs = gfc_chainon_list (retargs, tmp); retargs = gfc_chainon_list (retargs, tmp);
} }
else if (ts.type == BT_CHARACTER) else if (ts.type == BT_CHARACTER)
...@@ -3487,7 +3490,36 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, ...@@ -3487,7 +3490,36 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
/* Follow the function call with the argument post block. */ /* Follow the function call with the argument post block. */
if (byref) if (byref)
gfc_add_block_to_block (&se->pre, &post); {
gfc_add_block_to_block (&se->pre, &post);
/* Transformational functions of derived types with allocatable
components must have the result allocatable components copied. */
arg = expr->value.function.actual;
if (result && arg && expr->rank
&& expr->value.function.isym
&& expr->value.function.isym->transformational
&& arg->expr->ts.type == BT_DERIVED
&& arg->expr->ts.u.derived->attr.alloc_comp)
{
tree tmp2;
/* Copy the allocatable components. We have to use a
temporary here to prevent source allocatable components
from being corrupted. */
tmp2 = gfc_evaluate_now (result, &se->pre);
tmp = gfc_copy_alloc_comp (arg->expr->ts.u.derived,
result, tmp2, expr->rank);
gfc_add_expr_to_block (&se->pre, tmp);
tmp = gfc_copy_allocatable_data (result, tmp2, TREE_TYPE(tmp2),
expr->rank);
gfc_add_expr_to_block (&se->pre, tmp);
/* Finally free the temporary's data field. */
tmp = gfc_conv_descriptor_data_get (tmp2);
tmp = gfc_deallocate_with_status (tmp, NULL_TREE, true, NULL);
gfc_add_expr_to_block (&se->pre, tmp);
}
}
else else
gfc_add_block_to_block (&se->post, &post); gfc_add_block_to_block (&se->post, &post);
...@@ -4906,6 +4938,15 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2) ...@@ -4906,6 +4938,15 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
gfc_conv_array_parameter (&se, expr1, ss, 0, NULL, NULL, NULL); gfc_conv_array_parameter (&se, expr1, ss, 0, NULL, NULL, NULL);
if (expr1->ts.type == BT_DERIVED
&& expr1->ts.u.derived->attr.alloc_comp)
{
tree tmp;
tmp = gfc_deallocate_alloc_comp (expr1->ts.u.derived, se.expr,
expr1->rank);
gfc_add_expr_to_block (&se.pre, tmp);
}
se.direct_byref = 1; se.direct_byref = 1;
se.ss = gfc_walk_expr (expr2); se.ss = gfc_walk_expr (expr2);
gcc_assert (se.ss != gfc_ss_terminator); gcc_assert (se.ss != gfc_ss_terminator);
......
2010-01-14 Paul Thomas <pault@gcc.gnu.org> 2010-01-14 Paul Thomas <pault@gcc.gnu.org>
PR fortran/41478
* gfortran.dg/alloc_comp_scalar_1.f90: New test.
* gfortran.dg/alloc_comp_transformational_1.f90: New test.
2010-01-14 Paul Thomas <pault@gcc.gnu.org>
PR fortran/42481 PR fortran/42481
* gfortran.dg/generic_19.f90 : New test. * gfortran.dg/generic_19.f90 : New test.
......
! { dg-do run }
! Test the fix for comment #8 of PR41478, in which copying
! allocatable scalar components caused a segfault.
!
! Contributed by Tobias Burnus <burnus@gcc.gnu.org>
!
program main
type :: container_t
integer, allocatable :: entry
end type container_t
type(container_t), dimension(1) :: a1, a2
allocate (a1(1)%entry, a2(1)%entry)
a2(1)%entry = 1
a1(1:1) = pack (a2(1:1), mask = [.true.])
deallocate (a2(1)%entry)
if (a1(1)%entry .ne. 1) call abort
end program main
! { dg-do run }
! Tests the fix for PR41478, in which double frees would occur because
! transformational intrinsics did not copy the allocatable components
! so that they were (sometimes) freed twice on exit. In addition,
! The original allocatable components of a1 were not freed, so that
! memory leakage occurred.
!
! Contributed by Juergen Reuter <reuter@physik.uni-freiburg.de>
!
type :: container_t
integer, dimension(:), allocatable :: entry
integer index
end type container_t
call foo
call bar
contains
!
! This is the reported problem.
!
subroutine foo
type(container_t), dimension(4) :: a1, a2, a3
integer :: i
do i = 1, 4
allocate (a1(i)%entry (2), a2(i)%entry (2), a3(i)%entry (2))
a1(i)%entry = [1,2]
a2(i)%entry = [3,4]
a3(i)%entry = [4,5]
a1(i)%index = i
a2(i)%index = i
a3(i)%index = i
end do
a1(1:2) = pack (a2, [.true., .false., .true., .false.])
do i = 1, 4
if (.not.allocated (a1(i)%entry)) call abort
if (i .gt. 2) then
if (any (a1(i)%entry .ne. [1,2])) call abort
else
if (any (a1(i)%entry .ne. [3,4])) call abort
end if
end do
!
! Now check unpack
!
a1 = unpack (a1, [.true., .true., .false., .false.], a3)
if (any (a1%index .ne. [1,3,3,4])) call abort
do i = 1, 4
if (.not.allocated (a1(i)%entry)) call abort
if (i .gt. 2) then
if (any (a1(i)%entry .ne. [4,5])) call abort
else
if (any (a1(i)%entry .ne. [3,4])) call abort
end if
end do
end subroutine
!
! Other all transformational intrinsics display it. Having done
! PACK and UNPACK, just use TRANSPOSE as a demonstrator.
!
subroutine bar
type(container_t), dimension(2,2) :: a1, a2
integer :: i, j
do i = 1, 2
do j = 1, 2
allocate (a1(i, j)%entry (2), a2(i, j)%entry (2))
a1(i, j)%entry = [i,j]
a2(i, j)%entry = [i,j]
a1(i,j)%index = j + (i - 1)*2
a2(i,j)%index = j + (i - 1)*2
end do
end do
a1 = transpose (a2)
do i = 1, 2
do j = 1, 2
if (a1(i,j)%index .ne. i + (j - 1)*2) call abort
if (any (a1(i,j)%entry .ne. [j,i])) call abort
end do
end do
end subroutine
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment