Same f2c generated C code, built with gcc on 2 platforms gives different results

137 views Asked by At

We have a strange issue with our code, we used a same code since several years on several platforms, but this year we needed to build our software on a 64-bit RHEL 8 system.

During build processing, we need to convert some F77 code to C code using f2c tools.

During this convert processing some variables in memory are defined like this in the output C file.

#define v_hhdcb__ ((shortint *)&dovit_1 + 1608) /* works perfectly */
#define v_cncal__ ((integer *)(&dovit_1 + 5)) /* dovit_1 is a an array of short /*

On all of our systems (HP-UX, AIX,Ubuntu, openSUSE) we obtain the good value when we build C code with GCC.

On Opensuse : The read v_cncal value is on dovit_1 address + 5 x short type size (2) == > (10)

But on RHEL the same C code return a bad address value:

On RHEL 8 : The read v_cncal value is at dovit_1 address + 5 x int type size (4) ==> (20) but dovit_1 is a short array and not an int array.

GCC version in both case 8.4 and same f2c compiler

What could be wrong?

UPDATE

During our debugging, we tried to modify manually C code like this :

#define v_cncal__ ((integer *)(&dovit_1 + 5*sizeof(shortint))) /* works */

But this C code is generated by f2c, I think the best way is to ask f2c dev team to known what's happening.

UPDATE 1

How dovit_1 is declared :

/* testdyF.f -- translated by f2c (version 20181026).
   You must link the resulting object file with libf2c:
        on Microsoft Windows system, link with libf2c.lib;
        on Linux or Unix systems, link with .../path/to/libf2c.a -lm
        or, if you install libf2c.a in a standard place, with -lf2c -lm
        -- in that order, at the end of the command line, as in
                cc *.o -lf2c -lm
        Source for libf2c is in /netlib/f2c/libf2c.zip, e.g.,

                http://www.netlib.org/f2c/libf2c.zip
*/

union {
    struct {
        shortint dovita[1];

    } _1;
    struct {
        doublereal eqv_pad[1];

    } _2;
} dovit_;

#define dovit_1 (dovit_._1)
#define dovit_2 (dovit_._2)

/* Table of constant values */

static integer c__9 = 9;
static integer c__1 = 1;
static integer c__2 = 2;
static integer c__3 = 3;

shortint        *__dovit;
#undef dovit_1
#define dovit_1 __dovit[0]

/* CCCC Tag pour ajout routine d attachement shm */
#include <SHM_INIT.c>

/* _SHM_INIT */
/* Main program */ int MAIN__(void)
{
    /* Builtin functions */
    integer s_wsle(cilist *), do_lio(integer *, integer *, char *, ftnlen),
            e_wsle(void);

    /* Local variables */
#define v_pc__ ((shortint *)&dovit_1 + 288100)
#define v_cp__ ((shortint *)&dovit_1 + 288169)
#define v_ct__ ((shortint *)&dovit_1 + 294500)

...
2

There are 2 answers

0
0___________ On

It is Undefined Behaviour as it violates the strict-aliasing rules. when you dereference the integer * (I believe that it is int *)

And the result is one of the most common way how UBs "work" - getting the different results using different compilers on when run on different platforms.

3
tstanisl On

As it was stated in answer that you trigger UB due to violation of strict aliasing rules.

However, I guess you problem may be caused by invalid alignment. Expression (&dovit_1 + 5)) looks very suspicious because it is not properly aligned pointer to 4-byte-long int. Some platforms allow reading only pointer that are correctly aligned and compilers take advantage of that by "adjusting" the pointers.

Btw. v_cncal__ reads a value at dovit_1 address + 5 x short int type size (2)", not just "int (size 4)". Type of dovit_1 is short int as I understand.

I guess that the pointer arithmetic should be done after the cast. Replace

#define v_cncal__ ((integer *)(&dovit_1 + 5)) 

with

#define v_cncal__ ((integer *)&dovit_1 + 5)

Did it help?