Bug or undefined behaviour?

Bug or undefined behaviour?

Hi,

In integrating a third party C library into our product, I came across a fragment of code where inside a function, a struct is defined that includes a variable length array, the length of which depends on a parameter of that function. Incrementing a pointer s to such a struct works differently depending on whether you write ++s or s += 1 on the one hand, or s = s + 1 on the other hand. The code is similar to the following:

#include <stdio.h>
typedef struct {
    int   ndim;
    void  *firstmember, *lastmember;
} Container;
#define N_MEMBERS 5
#define TYPEDEFMEMBER(t)       
    typedef struct {            
        int    n;               
        double data[t->ndim];   
    } Member
void init(Container *t) {
    TYPEDEFMEMBER(t);
    Member *first, *last;
    first = malloc(N_MEMBERS * sizeof(Member));
    last  = first + N_MEMBERS - 1;
    t->firstmember = first;
    t->lastmember  = last;
}
void process(Container *t) {
    TYPEDEFMEMBER(t);
    Member *s, *first, *last;
    first = t->firstmember;
    last  = t->lastmember;
    printf("t->ndim = %d, with ++s:n", t->ndim);
    for (s = first; s <= last; ++s) {
        printf("s: %pn", s);
    }
    printf("t->ndim = %d, with s += 1:n", t->ndim);
    for (s = first; s <= last; s += 1) {
        printf("s: %pn", s);
    }
    printf("t->ndim = %d, with s = s + 1:n", t->ndim);
    for (s = first; s <= last; s = s + 1) {
        printf("s: %pn", s);
    }
}
void destroy(Container *t) {
    free(t->firstmember);
    t->firstmember = 0;
    t->lastmember  = 0;
}
int main(void) {
    Container container;
    Container *containerp = &container;
    container.ndim = 1;
    init(containerp);
    process(containerp);
    destroy(containerp);
    container.ndim = 3;
    init(containerp);
    process(containerp);
    destroy(containerp);
    return 0;
}

On linux on x86_64, both ++s and s += 1 increase s by 8 independent of the value of t->ndim, whereas s = s + 1 increases s by sizeof(Member) == 8 + t->ndim * 8. Clearly the latter is intended. This was compiled icc Version 13.0.1.117 Build 20121010 by the way, without any further options - just icc foo.c && ./a.out.

I'm not entirely sure this code is legal; but I feel that either icc should refuse to compile it, or be consistent between the ways of incrementing s.

Thanks

Erik Postma
Maplesoft

publicaciones de 4 / 0 nuevos
Último envío
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.

Not sure if I can edit my original post - I notice that the line continuation characters in the macro definition of TYPEDEFMEMBER do not show up. There should be a backslash at the end of four lines there - the definition ends with the line "} Member". Similarly but less crucially, there should be backslashes in the printf format strings. Sorry for the confusion.

Erik.

What result do you get with the gcc compiler?

The compiler you are using is a bit old.  The latest one that you could try is icc 13.1.1.163 Build 20130313.

--mark

Hi Mark,

Thanks for your response. gcc does the intended thing: it increases s by sizeof(Member) for each of the methods of increasing s.

Indeed, I have found out since yesterday that this is an undocumented (mis?)feature of gcc specifically; clang, for example, describes it at http://clang.llvm.org/docs/UsersManual.html#intentionally-unsupported-gc... as:

clang does not support the gcc extension that allows variable-length arrays in structures. This is for a few reasons: one, it is tricky to implement, two, the extension is completely undocumented, and three, the extension appears to be rarely used.

I guess this means that the obvious solution for you guys is to just refuse to compile it (which wouldn't solve the issue for me, but that's life I guess).

Erik.

Inicie sesión para dejar un comentario.