1

I'm trying to assign a value to the member of an union which is member of a struct, but the value doesn't seem to be assigned. I've stepped through the program, and right after the assignation, len_param.data value seems to be some sort of pointer (see GDB output at the end of the post)

Also, if I printf, it runs normally:

len_param.data.v_int = 4;

// If I uncomment this line, IT RUNS FINE! WHY?
// printf("len_param.data.v_int: %i \n", len_param.data.v_int);

The type of len_param is as follow:

struct Parameter {
    enum {
        NORMAL, ARRAY, SKIP,
    } type;

    GIDirection direction;

    GIArgument data;
};

And GIArgument definition:

union _GIArgument
{
  gboolean v_boolean;
  gint8    v_int8;
  guint8   v_uint8;
  gint16   v_int16;
  guint16  v_uint16;
  gint32   v_int32;
  guint32  v_uint32;
  gint64   v_int64;
  guint64  v_uint64;
  gfloat   v_float;
  gdouble  v_double;
  gshort   v_short;
  gushort  v_ushort;
  gint     v_int;
  guint    v_uint;
  glong    v_long;
  gulong   v_ulong;
  gssize   v_ssize;
  gsize    v_size;
  gchar *  v_string;
  gpointer v_pointer;
};
typedef _GIArgument GIArgument;

The complete file can be found here: https://gist.github.com/romgrk/642388914a9ff412eb5683fca44009d7#file-function-cc-L255

And my GDB output when I step at that line is:

Thread 1 "node" hit Breakpoint 1, GNodeJS::FunctionInvoker (info=...) at ../src/function.cc:256
256                     len_param.data.v_int = GetV8ArrayLength(info[in_arg]);
(gdb) step
GNodeJS::GetV8ArrayLength (value=...) at ../src/function.cc:25
25  static int GetV8ArrayLength (Local<Value> value) {
(gdb) finish
Run till exit from #0  GNodeJS::GetV8ArrayLength (value=...) at ../src/function.cc:25
GNodeJS::FunctionInvoker (info=...) at ../src/function.cc:260
260                     callable_arg_values[length_i].v_pointer = &len_param.data;
Value returned is $1 = 4
(gdb) p len_param.data.v_int
$2 = -17928
(gdb) p len_param
$3 = {
  type = GNodeJS::Parameter::SKIP, 
  direction = GI_DIRECTION_INOUT, 
  data = {
    v_boolean = -17928, 
    v_int8 = -8 '\370', 
    v_uint8 = 248 '\370', 
    v_int16 = -17928, 
    v_uint16 = 47608, 
    v_int32 = -17928, 
    v_uint32 = 4294949368, 
    v_int64 = 140737488337400, 
    v_uint64 = 140737488337400, 
    v_float = -nan(0x7fb9f8), 
    v_double = 6.9533558069492434e-310, 
    v_short = -17928, 
    v_ushort = 47608, 
    v_int = -17928, 
    v_uint = 4294949368, 
    v_long = 140737488337400, 
    v_ulong = 140737488337400, 
    v_ssize = 140737488337400, 
    v_size = 140737488337400, 
    v_string = 0x7fffffffb9f8 "\t\357\304\303J\a", 
    v_pointer = 0x7fffffffb9f8
  }
}
Rom Grk
  • 526
  • 5
  • 15
  • 6
    Probably as-if rule, if the value is not being used it does not have to store it e.g. [Loop with a zero execution time](https://stackoverflow.com/q/26771692/1708801) – Shafik Yaghmour Jun 21 '18 at 21:39
  • 1
  • well the thing is I'm trying to use the value of that variable later in the code, and it it's not assigned to the correct value. Is it possible that it's the *as-if* rule even there? – Rom Grk Jun 21 '18 at 21:50
  • I see a union type called _GIArgument and a structure member of GIArgument type, which we don't know what it is. – Kyle Huff Jun 21 '18 at 22:03
  • Updated, added missing `typedef` – Rom Grk Jun 21 '18 at 22:05
  • 1
    Without the code you debug its impossible to tell what's going on... – Michael Beer Jun 21 '18 at 23:07
  • Can you give us enough code to replicate the problem? We can't debug code we can't see. – David Schwartz Jun 21 '18 at 23:47
  • After the gdb command `finish`, the program is normally stopped at the CPU instruction immediately after the CALL that invoked that function. This would mean the calling code has not yet had the chance to store the return value in a variable. That is, if I have `var = func();` and I `finish` out of `func`, I would expect the `var = value;` assignment has not yet happened. Try stepping with `n` to the next line only. – aschepler Jun 22 '18 at 00:02

1 Answers1

1

The problem might be that nothing is ever done with len_param.data except to take its address just before it goes out of scope and the lifetime of len_param expires. So the compiler figures there's no point storing anything there.

Here's the code snippet where len_param is defined, used and dies (with unnecessary code elided and some annotation comments added):

if (param.type == Parameter::ARRAY) {

    // ... 

    Parameter len_param = call_parameters[length_i];    // len_param is defined

    if (len_param.direction == GI_DIRECTION_IN) {
        // ...
    }
    else if (len_param.direction == GI_DIRECTION_INOUT) {

        len_param.data.v_int = GetV8ArrayLength(info[in_arg]);

        callable_arg_values[length_i].v_pointer = &len_param.data;
    }
}       // len_param goes out of scope, so it's no longer alive
        // and the pointer that got placed in `callable_arg_values[length_i].v_pointer`
        // is pointing to garbage

The root problem is that the pointer in callable_arg_values[length_i].v_pointer isn't valid moments after it gets stored.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • But isn't len_param a reference to an element of call_parameters? – Rom Grk Jun 26 '18 at 01:16
  • According to what you have posted, `len_param` is not a reference to anything - it's an object of type `struct Parameter` whose lifetime lasts until the end of the block it's declared in. It is initialized to be a copy of `call_parameters[length_i]`. Maybe all you need to do is turn it into a reference: `Parameter& len_param = call_parameters[length_i];`. – Michael Burr Jun 26 '18 at 05:24
  • 1
    Using a reference as you described in your last comment did the trick, thanks! – Rom Grk Jun 27 '18 at 17:47