RFA, PR fortran/34686: Aliasing bug when returning character pointers
Richard Sandiford
rsandifo@nildram.co.uk
Tue Jan 8 10:56:00 GMT 2008
char_pointer_func.f90 is failing at -O3 -mabi=32 on mips64-linux-gnu
because of an aliasing bug. We have a function sfoo() that returns a
pointer to a string of length 4:
function sfoo () result (sc1)
character*4, pointer :: sc1
allocate (sc1)
sc1 = "abcd"
end function sfoo
It gets the C prototype:
static void sfoo (character(kind=1)[1:4] * &, integer(kind=4));
However, the first caller is:
c1 = sfoo ()
and it passes a pointer to a 0-based array, pstr.3:
{
character(kind=1)[4] * pstr.3;
sfoo (&pstr.3, 4);
__builtin_memmove ((void *) c1, (void *) pstr.3, 4);
}
So after inlining sfoo(), we get the following code at final_cleanup:
D.617 = (character(kind=1)[1:4] *) D.616;
--> *(character(kind=1)[1:4] * &) &pstr.3 = D.617;
__builtin_memcpy (D.617, &"abcd"[1]{lb: 1 sz: 1}, 4);
__builtin_memmove (c1, pstr.3, 4);
where __builtin_memcpy is small enough to open-code; we do not use a call.
The two pointer types (one to a [4]-based array and one to a [1:4]-based
array) have different alias sets, so in the failing case, we then
schedule the read of pstr.3 before the store to
*(character(kind=1)[1:4] * &) &pstr.3.
The problem appears to be in this part of gfc_conv_function_call.
which deliberately ignores the bounds on the return value:
/* Pass the string length. */
type = gfc_get_character_type (ts.kind, ts.cl);
type = build_pointer_type (type);
/* Return an address to a char[0:len-1]* temporary for
character pointers. */
if (sym->attr.pointer || sym->attr.allocatable)
{
/* Build char[0:len-1] * pstr. */
tmp = fold_build2 (MINUS_EXPR, gfc_charlen_type_node, len,
build_int_cst (gfc_charlen_type_node, 1));
tmp = build_range_type (gfc_array_index_type,
gfc_index_zero_node, tmp);
tmp = build_array_type (gfc_character1_type_node, tmp);
var = gfc_create_var (build_pointer_type (tmp), "pstr");
/* Provide an address expression for the function arguments. */
var = build_fold_addr_expr (var);
}
else
var = gfc_conv_string_tmp (se, type, len);
(I believe TYPE is therefore unused in the sym->attr.pointer
|| sym->attr.allocatable case). It would seem more natural to do:
var = gfc_create_var (type, "pstr");
/* Provide an address expression for the function arguments. */
var = build_fold_addr_expr (var);
which, in combination with the later:
/* Dereference for character pointer results. */
if (sym->attr.pointer || sym->attr.allocatable)
se->expr = build_fold_indirect_ref (var);
else
se->expr = var;
makes sure that se->expr always has type TYPE. This does indeed
fix the problem: pstr.3 is then stored to in its natural type.
(The current 0-based code seems to be mimicking the "str" case of
gfc_conv_string_tmp, but that's creating an on-stack array, rather
than a pointer to an array, and that case still returns a pointer
to a 1-based array.)
Bootstrapped & regression-tested on x86_64-linux-gnu. Also regression-
tested on mips64-linux-gnu (all 3 ABIs). OK to install?
Richard
Index: gcc/fortran/trans-expr.c
===================================================================
--- gcc/fortran/trans-expr.c 2008-01-07 10:48:25.000000000 +0000
+++ gcc/fortran/trans-expr.c 2008-01-07 10:48:29.000000000 +0000
@@ -2660,13 +2660,7 @@ gfc_conv_function_call (gfc_se * se, gfc
character pointers. */
if (sym->attr.pointer || sym->attr.allocatable)
{
- /* Build char[0:len-1] * pstr. */
- tmp = fold_build2 (MINUS_EXPR, gfc_charlen_type_node, len,
- build_int_cst (gfc_charlen_type_node, 1));
- tmp = build_range_type (gfc_array_index_type,
- gfc_index_zero_node, tmp);
- tmp = build_array_type (gfc_character1_type_node, tmp);
- var = gfc_create_var (build_pointer_type (tmp), "pstr");
+ var = gfc_create_var (type, "pstr");
/* Provide an address expression for the function arguments. */
var = build_fold_addr_expr (var);
More information about the Gcc-patches
mailing list