Bug #48284 C99 aliasing violation, results in failures in the client library
Submitted: 25 Oct 7:57 Modified: 17 Nov 11:33
Reporter: Davin McCall
Status: Verified
Category:Connector/C Severity:S2 (Serious)
Version:5.1.40 OS:Linux
Assigned to: Target Version:
Triage: D3 (Medium)

[25 Oct 7:57] Davin McCall
Description:
There is a C99 aliasing violation in the source of Mysql 5.1.40 which causes client
errors (specifically with MythTV but probably also with others) when Mysql is compiled
with -O3 optimization (GCC 4.4.2).

The problem is in in libmysql/libmysql.c, in the cli_stmt_execute() function. Line 2553
looks like:

    for (param= stmt->params; param < param_end; param++)
        store_param_type((char**) &net->write_pos, param);

And store_param_type is declared as:

    static void store_param_type(char **pos, MYSQL_BIND *param)
    {
        uint typecode= param->buffer_type | (param->is_unsigned ? 32768 : 0);
        int2store(*pos, typecode);
        *pos+= 2;
    }

However, the real type of net->write_pos is "uchar *" not "char *" and it is referenced
as such elsewhere in the cli_stmt_execute function. The types are incompatible and it is
not legal to access the net->write_pos value as if it were both a "uchar *" and "char *"
(note that if the "char **" cast is removed GCC gives a warning that the types are
incompatible).

The eventual result is that GCC thinks "*pos+=2" can be moved outside the loop and
collapsed to a single store. A bit silly, but that's what happens when you break the
aliasing rules :)

How to repeat:
Compile with GCC 4.4.2, using the Mysql-recommended CFLAGS/CXXFLAGS (I added only
-march=i686).

CXX=gcc CFLAGS="-O3 -march=i686" \
CXXFLAGS="-O3 -felide-constructors -fno-exceptions -fno-rtti -march=i686" \
  ./configure --prefix=/usr --localstatedir=/var/mysql --sysconfdir=/etc \
              --mandir=/usr/share/man \
              --enable-thread-safe-client --enable-assembler --with-gnu-ld \
              --with-mysqld-user=mysql --with-ssl
make
make install

Then run "mythfrontend"...

Suggested fix:
The fix is fairly trivial, two things should be changed:
1) change the declared type of the "pos" parameter in store_param_type from "char **" to
"uchar **"
2) remove the "char **" cast from line 2554 in cli_stmt_execute. (Not strictly necessary,
but GCC gives a warning if you don't).

For a workaround with current version, it's easy just to add "-fno-strict-aliasing" to
CFLAGS.
[17 Nov 11:33] Tonci Grgin
Hi Davin.

Verified just as described by looking into latest 5.1 sources.