| Bug #18435 | 5.0.19 libmysqlclient not ABI-compatible with 5.0.18 | ||
|---|---|---|---|
| Submitted: | 22 Mar 2006 20:03 | Modified: | 27 Mar 2006 8:59 |
| Reporter: | Lenz Grimmer | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server | Severity: | S1 (Critical) |
| Version: | 5.0.19 | OS: | |
| Assigned to: | Michael Widenius | CPU Architecture: | Any |
[22 Mar 2006 20:03]
Lenz Grimmer
[22 Mar 2006 21:19]
Michael Widenius
As info_buffer is not used in the not embedded version of libmysqlclient it should be safe to do a patch so that the extra info_buffer member is not used in clients < 5.1.0. This will ensure that clients linked with either 5.0.18 or 5.0.19 should work with 5.0.20
[23 Mar 2006 5:08]
[ name withheld ]
Hi Michael, Unfortunately, it's not that easy because the 5.0.19 libmysqlclient *does* access the added field. If it didn't, I'd never have noticed the problem ... but it tries to zero the field at mysql_init and then free() the pointer value at shutdown. The crash I saw in mysql-python came about because mysql-python has its own pointer variable just after the MYSQL struct and the extra free() is inappropriate.
[23 Mar 2006 8:17]
Michael Widenius
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.
If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information
about accessing the source trees is available at
http://www.mysql.com/doc/en/Installing_source_tree.html
Additional info:
Fix will be in 5.0.20
[25 Mar 2006 0:07]
[ name withheld ]
I looked at the fix and don't find it makes me comfortable. The problem is that the mysql.h file still exports a struct definition that is bigger than it was before, and this results in ABI breaks for anything incorporating that. An example of the risk is that recompiling just one of the source files for mysql-python would result in a non-working mysql-python build, because that source file would have a different idea about sizeof(MYSQL) and thus about the offsets of fields in mysql-python's structs. I really want to see something like #ifdef EMBEDDED_SERVER in the .h file, not only in the .c files.
[27 Mar 2006 8:59]
Bugs System
A patch for this bug has been committed. After review, it may be pushed to the relevant source trees for release in the next version. You can access the patch from: http://lists.mysql.com/commits/4182
[27 Mar 2006 8:59]
Michael Widenius
Thank you for your bug report. This issue has been committed to our
source repository of that product and will be incorporated into the
next release.
If necessary, you can access the source repository and build the latest
available version, including the bugfix, yourself. More information
about accessing the source trees is available at
http://www.mysql.com/doc/en/Installing_source_tree.html
Additional info:
In general there should not have beeen be any risk of
incompatibilities between releases after this patch.
The reason for this are:
- The new element in the MySQL structure is last and there is thus
no changes in any offset for any old fields.
- It's normally perfectly safe to make a structure bigger as long as
you don't write anything to the new members. (The idea of the patch I
made was to ensure we don't write anything to the new info_buffer
member).
The fact that sizeof() changes does not affect any old program using
the shared library as they don't know anything about the size change.
Any new compiled program will pick up the new size, but this safe to use
both with a old and new libmysqlclient.so library.
The only incompatibility I can think of just now are:
a) If you have a client that have a lot of different parts that are
compiled with different mysql.h header files (before and after the
change) and you in one of them that is compiled with the newer size do
a memset(&mysql, 0, sizeof(*mysql)) on a staticly allocated structure
from a object file that uses the smaller version.
b) If you use the MYSQL structure as part of another global structure
and the clients accessing this structure is compiled at different
times with different header files.
Neither of the above is something that we recommend as this would
cause the clients to break for every major MySQL release and many
alpha and beta releases, while we are fine tuning structures.
The right way would be to use mysql_init() to allocate and populate
the MySQL structure. This would make the client safe against most
upgrades as we always try to do structure changes by adding things last
into the structures.
I did check of how MySQL python allocates it's structure and did
notice that it declares it connection structure the following way,
which is almost a conflict according to b):
typedef struct {
PyObject_HEAD
MYSQL connection;
int open;
PyObject *converter;
} _mysql_ConnectionObject;
I think the old patch is still safe for MySQL-python because
_mysql_ConnectionObject it's not a global structure and is thus not
used between different programs. In other words, there is no risk of
structure elements shifting as the offset are decided at compile time
and in this case only one mysql.h header is in use. The external size
of the MYSQL structure is also irrelevant as the MySQL client library
will not overwrite anything outside of the the old size of the MYSQL
structure.
I agree that in general to fix issue b), there is no other easy option
than to add an #ifdef EMBEDDED_SERVER around the new element in the
MySQL INFO structure :(
While doing the patch, I did not anticipate usage of the MySQL structure as
used by MySQL-python. To feel safer against things like this, I have
now added
#if defined(EMBEDDED_LIBRARY) || defined(EMBEDDED_LIBRARY_COMPATIBLE) || MYSQL_VERSION_ID >= 50100
around the new element in MYSQL. The define
"EMBEDDED_LIBRARY_COMPATIBLE" can be used by develeopers if they want
to e able to decide on link time to use the normal client library or
the embedded client library.
The other actions that should be taken are:
- We will contact they Python maintainer and ask them to change the
MYSQL connection argument to be a pointer instead of a structure as
this will make the connection object more safe against struct updates
in the future.
- We will look at accelerate our own plans to make the MySQL external
structures 'abstract' structures so that we can do changes in the
structures without causing any incompatibilities with existing
clients.
Thanks Tom for making us aware of the 'unexpected' way MySQL-Python allocates
and uses the MYSQL structure!
Regards,
Monty
