Skip to content

Handling of compatible structure types under C23 semantics #1950

@jprotopopov-ut

Description

@jprotopopov-ut

C23 has relaxed rules for struct type compatibility making the following code snippet legal:

typedef void (*func_t)(void);

struct A {
    func_t f;
};

void test1(struct A {
    func_t f;
} *b) {
    b->f();
}

void dummy() {}

int main() {
    struct A arg = {dummy};
    test1(&arg);
    return 0;
}

Goblint (revision e816b4a) fails to recognize that b->f is initialized to dummy and outputs

[Warning][Unsound][Call] No suitable function to be called at call site. Continuing with state before call

C23 standard (section 6.2.7) specifies:

Moreover, two complete structure, union, or enumerated types declared with the
same tag are compatible if members satisfy the following requirements:
— there shall be a one-to-one correspondence between their members such that each pair of
corresponding members are declared with compatible types;
— if one member of the pair is declared with an alignment specifier, the other is declared with an
equivalent alignment specifier;
— and, if one member of the pair is declared with a name, the other is declared with the same
name

More discussion is also available in the following proposal.

This issue has surfaced when trying to analyze rsync version from AnalyzeThat. The linked code is in fact even more liberal in using pointers to incompatible struct types, as it declares these struct types with different tags (for example, see the type of the first parameter in the call to deflateInit_ from compress2).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions