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?
In order to match your observations, I posit
char*
has size 8 and alignment 8.int
has size 4 and alignment 4.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 you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With