Bug #31566 my_write(fd, 0x0, 0, flags) fails with EFAULT on some platforms
Submitted: 12 Oct 2007 14:23 Modified: 20 Dec 2007 0:38
Reporter: Axel Schwenke Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server Severity:S1 (Critical)
Version:5.0.46 OS:Linux ( )
Assigned to: Alexey Kopytov CPU Architecture:Any
Tags: bfsm_2007_10_18
Triage: D2 (Serious)

[12 Oct 2007 14:23] Axel Schwenke
Description:
MySQL did not install on a Debian/Mips64 platform. Also the test suite failed in bootstrap phase with error message:

/root/nn/mysql-5.0.46/sql/mysqld --no-defaults --bootstrap --basedir=/root/nn/mysql-5.0.46/mysql-test --datadir=/root/nn/mysql-5.0.46/mysql-test/var/master-data --skip-innodb --skip-ndbcluster --tmpdir=. --core-file --language=/root/nn/mysql-5.0.46/sql/share/english --character-sets-dir=/root/nn/mysql-5.0.46/sql/share/charsets
ERROR: 1051  Unknown table 'db'
071009  9:21:04 [ERROR] Aborting
071009  9:21:04 [Note] /root/nn/mysql-5.0.46/sql/mysqld: Shutdown complete

Running mysqld with trace log enabled showed this:
T@32771: | | | | | | <make_empty_rec
T@32771: | | | | | | >my_write
T@32771: | | | | | | | my: Fd: 6  Buffer: 0x7f5fed90  Count: 2  MyFlags: 4
T@32771: | | | | | | <my_write
T@32771: | | | | | | >my_write
T@32771: | | | | | | | my: Fd: 6  Buffer: 0x0  Count: 0  MyFlags: 4
T@32771: | | | | | | | error: Write only -1 bytes, error: 14
T@32771: | | | | | | <my_write

the failed my_write() translates to line 180 in unireg.cc (function mysql_create_frm)

The same my_write() works on Linux i686 and x86_64. Seems the write(2) system call on mips64 checks the buffer address even when length==0 and returns EFAULT when the buffer is at 0x0.

How to repeat:
Try to run MySQL on the mips64 platform.

Suggested fix:
In my_write() test if Count==0 and return immediately in this case.

--- my_write.c.bak      2007-07-19 23:37:06.000000000 +0200
+++ my_write.c  2007-10-12 16:05:39.000000000 +0200
@@ -29,6 +29,9 @@
                   Filedes, (long) Buffer, Count, MyFlags));
   errors=0; written=0L;
 
+  if (Count == 0)
+    DBUG_RETURN(0);                    /* nothing to write */
+
   for (;;)
   {
     if ((writenbytes = (uint) write(Filedes, Buffer, Count)) == Count)
[12 Oct 2007 15:50] Konstantin Osipov
Chad, please treat this as a community contribution.
[15 Oct 2007 15:45] 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/35578

ChangeSet@1.2535, 2007-10-15 19:44:58+04:00, kaa@polly.(none) +1 -0
  Fix for bug #31566: my_write(fd, 0x0, 0, flags) fails with EFAULT on
  some platforms
  
  Since the behavior of write(fd, buf, 0) is undefined, it may fail with
  EFAULT on some architectures when buf == NULL. The error was propagated
  up to a caller, since my_write() code did not handle it properly.
  
  Fixed by checking the 'number of bytes' argument in my_write() and
  returning before calling the write() system call when there is nothing
  to write.
[24 Oct 2007 17:16] 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/36287

ChangeSet@1.2535, 2007-10-24 21:16:20+04:00, kaa@polly.(none) +1 -0
  Fix for bug #31566: my_write(fd, 0x0, 0, flags) fails with EFAULT on
  some platforms
  
  Since the behavior of write(fd, buf, 0) is undefined, it may fail with
  EFAULT on some architectures when buf == NULL. The error was propagated
  up to a caller, since my_write() code did not handle it properly.
  
  Fixed by checking the 'number of bytes' argument in my_write() and
  returning before calling the write() system call when there is nothing
  to write.
[25 Oct 2007 4:57] 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/36317

ChangeSet@1.2551, 2007-10-25 08:19:57+04:00, kaa@polly.(none) +1 -0
  Replaced 'return' with DBUG_RETURN() in the fix for bug #31566.
[7 Dec 2007 23:08] Bugs System
Pushed into 6.0.5-alpha
[7 Dec 2007 23:09] Bugs System
Pushed into 5.1.23-rc
[7 Dec 2007 23:10] Bugs System
Pushed into 5.0.54
[20 Dec 2007 0:38] Paul Dubois
Noted in 5.0.54, 5.1.23, 6.0.5 changelogs.

The internal my_write() function was made more robust against
non-portable behavior of the write() system call for a buffer length 
of 0.