1
 98 static inline int set_hw_br(pid_t tracee, dr7_t *pdr7, void *addr, int dr_index)
 99 {
100     errno = 0;
101     printf("LINE = %d <pid> %d, dr_index= %d addr=%u \n",__LINE__, tracee, dr_index, addr);
102     //if (ptrace(PTRACE_POKEUSER, tracee, offsetof(struct user, u_debugreg[dr_index]), addr))
103     if (ptrace(PTRACE_POKEUSER, tracee, offsetof(struct user, u_debugreg[dr_index]), addr))
104     {
105         int ii = errno;
106         printf("MKH: 22  errno = %d\n", ii);
107         ptrace(PTRACE_DETACH, tracee, 0, 0);
108         return -1;
109     }
110     else
111         printf("PTRACE_POKEUSER passed...\n");

Above code(part of main code) is successfully compiled in GCC compiler. But while compiling through G++, it is giving fillowing error: error: 'dr_index' cannot appear in a constant-expression in line 103. set_hw_br is called from another function.

Any idea why this failing in g++?

Thanks.

  • please post the complete code of the function – mjs Mar 25 '14 at 10:05
  • It depends on the definition of macro offsetof. Show how it is defined. – Vlad from Moscow Mar 25 '14 at 10:15
  • 1
    @VladfromMoscow, with GCC it is defined as [`__builtin_offsetof`](http://gcc.gnu.org/onlinedocs/gcc/Offsetof.html) so seeing the macro definition won't help. – Jonathan Wakely Mar 25 '14 at 10:18
  • It's a broken [GCC extension](http://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions). The C99 language standard requires `offsetof` to produce a constant expression. – Sergey Kalinichenko Mar 25 '14 at 10:29
  • @dasblinkenlight, the error isn't saying `offsetof` doesn't _produce_ a constant expression it's saying an input to it is not a constant expression. The C11 standard requires that for `offsetof` `&t.member-designator` is an address constant, and that's obviously not true for `&t.a[nonconstant]`. The GCC C front-end apparently allows non-constant input, and you get non-constant output. The C++ front-end is stricter, which makes sense given the more extensive rules about constant expressions in C++ – Jonathan Wakely Mar 25 '14 at 10:56
  • @JonathanWakely If my reading of the C99 standard is correct, C requires the input of `offsetof` to be a constant expression as well; GCC's implementation lifts this restriction, but apparently only for C, not for C++. – Sergey Kalinichenko Mar 25 '14 at 12:22

1 Answers1

5

The offsetof macro requires that the member-designator has to produce an address constant (C11 7.19/3):

offsetof(type, member-designator)

which expands to an integer constant expression that has type size_t, the value of which is the offset in bytes, to the structure member (designated by member-designator), from the beginning of its structure (designated by type). The type and member designator shall be such that given

static type t;

then the expression &(t.member-designator) evaluates to an address constant. (If the specified member is a bit-field, the behavior is undefined.)

In your code, t.u_subreg[dr_index] is not a constant, because dr_index is not a constant.

GCC implements offsetof with a compiler intrinsic so what is allowed in an offsetof expression depends on the rules of GCC's intrinsic. As an extension to the standard, the GCC C front-end allows a non-constant expression as input and produces a non-constant result. The C++ front-end does not allow it, giving the error telling you dr_index cannot be used there.

You can change the offsetof expression to only use constants:

offsetof(struct user, u_debugreg[0])

then you can add the index to it, where T is the type in the array u_debugreg:

offsetof(struct user, u_debugreg[0]) + sizeof(T)*dr_index

(This assumes that u_debugreg is an actual array, not a pointer).

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
  • @Yakk, it works either way (with GCC anyway). I kept it there because it keeps the code closer to the original: it's obviously getting the offset of the first array element, and so it's easy to get the Nth element from that too. You are correct that the offset of the array is the same as the offset of the first element, and so both work. – Jonathan Wakely Mar 25 '14 at 10:46