Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does sizeof(struct) help provide ABI compatibility?

Suppose a C library has to share the details of a structure with the application code and has to maintain API and ABI backward compatibility. It tries to do this by checking the size of the structure passed to it.

Say, the following structure needs to be updated. In library version 1,

typedef struct {
    int size;
    char* x;
    int y;
} foo;

In version 2 of the library, it is updated to:

typedef struct {
    int size;
    char* x;
    int y;
    int z;
} foo_2;

Now, library version 2 wants to check if the application is passing the new foo_2 or the old foo as an argument, arg, to a function. It assumes that the application has set arg.size to sizeof(foo) or sizeof(foo_2) and attempts to figure out whether the application code groks version 2.

if(arg.size == sizeof(foo_2)) {
    // The application groks version 2 of the library. So, arg.z is valid. 
} else {
    // The application uses of version 1 of the library. arg.z is not valid.
}

I'm wondering why this won't fail. On GCC 4.6.3, with -O3 flag, both sizeof(foo) and sizeof(foo_2) are 24. So, won't v2 library code fail to understand if the application is passing a struct of type foo or foo_2? If yes, how come this approach seems to have been used?

http://wezfurlong.org/blog/2006/dec/coding-for-coders-api-and-abi-considerations-in-an-evolving-code-base/

http://blogs.msdn.com/b/oldnewthing/archive/2003/12/12/56061.aspx


Follow on question: Is there a good reason to favor the use of sizeof(struct) for version discrimination? As pointed out in the comments, why not use an explicit version member in the shared struct?

like image 528
spiky Avatar asked Sep 29 '22 19:09

spiky


1 Answers

In order to match your observations, I posit

  • char* has size 8 and alignment 8.
  • int has size 4 and alignment 4.
  • Your implementation uses optimal packing.

You are quite right that in that case, both your old and new structure would have the same size, and as your version-discriminator is the structures size, the upgrade is an ABI-breaking change. (Few logic-errors are also syntax-errors, and the former are not diagnosed by a compiler).

Only changes to the structure which result in a bigger size, with the new struct containing all the fields of the old one at the same offsets, can be ABI-compatible under that scheme: Add some dummy variables.


There is one possibility which might save the day though:

  • If a field contains a value which was previously invalid, that might indicate that anything else might have to be interpreted differencty.
like image 65
Deduplicator Avatar answered Oct 03 '22 01:10

Deduplicator