https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96024

Jakub Jelinek <jakub at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|FIXED                       |---
                 CC|                            |jakub at gcc dot gnu.org

--- Comment #17 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
The new testcase seems to fail on big-endian hosts.  I've analyzed this on 11
branch:

3190          /* For a constant string constructor, make sure the length is
3191             correct; truncate of fill with blanks if needed.  */
3192          if (this_comp->ts.type == BT_CHARACTER &&
!this_comp->attr.allocatable
3193              && this_comp->ts.u.cl && this_comp->ts.u.cl->length
3194              && this_comp->ts.u.cl->length->expr_type == EXPR_CONSTANT
3195              && actual->expr->ts.type == BT_CHARACTER
3196              && actual->expr->expr_type == EXPR_CONSTANT)
3197            {
3198              ptrdiff_t c, e1;
3199              c = gfc_mpz_get_hwi
(this_comp->ts.u.cl->length->value.integer);
3200              e1 = actual->expr->value.character.length;
3201    
3202              if (c != e1)
3203                {
3204                  ptrdiff_t i, to;
3205                  gfc_char_t *dest;
3206                  dest = gfc_get_wide_string (c + 1);

*this_comp->ts.u.cl->length
$20 = {expr_type = EXPR_CONSTANT, ts = {type = BT_CHARACTER, kind = 1 ... }
Because it is a BT_CHARACTER EXPR_CONSTANTS, simplify_achar_char initialized it
as
813       result = gfc_get_character_expr (kind, &e->where, NULL, 1);
814       result->value.character.string[0] = mpz_get_ui (e->value.integer);
i.e. using the value.character union member.
But the code assumes it is an integral constant instead and uses value.integer
instead.
p this_comp->ts.u.cl->length->value.character
$22 = {length = 1, string = 0x2aa02ab2de0}
where string points to array of unsigned int, big endian, so contains value
0x00000001 followed by garbage, which happens to be 0, so bytes 0, 0, 0, 1, 0,
0, 0, 0
Now
p this_comp->ts.u.cl->length->value.integer
$23 = {{_mp_alloc = 0, _mp_size = 1, _mp_d = 0x2aa02ab2de0}}
(note, _mp_alloc and _mp_size are both 32-bit while length is 64-bit) and _mp_d
points to array of mp_limb_t, which is unsigned long.
So, this means c is 0x100000000 and we try to allocate 0x100000001 * 4 bytes ==
17179869188.
Now, on x86_64 string also points to array of unsigned int, but because it is
little endian, the value 1 is there 1, 0, 0, 0, 0, 0, 0, 0, 0 (the last 4 bytes
random garbage),
so c is 1 rather than 0x100000000 and it allocates 2 * 4 bytes.

So, presumably we need in addition to the
&& this_comp->ts.u.cl->length->expr_type == EXPR_CONSTANT
check also test that the constant uses value.integer union member rather than
some other one.  Would
&& this_comp->ts.u.cl->length->ts.type == BT_INTEGER
be the right test for it or something else?

Reply via email to