0

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)

...
phuclv
  • 37,963
  • 15
  • 156
  • 475
FMousnier
  • 1
  • 1
  • 1
    how `dovit_1` is declared? what are `shortint` and `integer`? `short int` and `int` respectively? – tstanisl Sep 17 '21 at 10:08
  • What does "return a bad address value" mean? Is this a compiler or linker message? Or maybe a segmentation fault, when you run the program? – Olaf Dietsche Sep 17 '21 at 10:22
  • no segmentation fault, return a value but not the good value because, pointer is not well calculated. During our debbuging we try to modify C code generated by f2c like this #define v_cncal__ ((integer *)(&dovit_1 + 5*sizeof(shortint))) and it works, but it's not possible to do that on each file. – FMousnier Sep 17 '21 at 10:36
  • please add an **exact** definition of `dovit_1` to the question. It really matter for understanding the problem – tstanisl Sep 17 '21 at 10:45
  • If you handle two consecutive `int16_t` values as one `int32_t` value, the result will be platform-dependent: on _little-endian:_ first+65536*second, on _big-endian:_ first*65536+second – Lorinczy Zsigmond Sep 17 '21 at 11:49
  • I add dovit_1 definition in UPDATE 1 – FMousnier Sep 17 '21 at 11:57
  • `shortint`, `doublereal` or `integer` aren't C types. You need to show their definition and also a [mcve] – phuclv Sep 17 '21 at 13:00

2 Answers2

0

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.

0___________
  • 60,014
  • 4
  • 34
  • 74
0

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?

tstanisl
  • 13,520
  • 2
  • 25
  • 40