Bug #69379 MySQL clients return bogus errno for host-not-found errors on Ubuntu 13.04
Submitted: 2 Jun 2013 8:00 Modified: 3 Jun 2013 15:15
Reporter: Laurynas Biveinis (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Errors Severity:S3 (Non-critical)
Version:5.1 OS:Linux (Ubuntu 13.04)
Assigned to:
Tags: client, errno, gethostbyname_r, my_gethostbyname_r
Triage: Needs Triage: D4 (Minor)

[2 Jun 2013 8:00] Laurynas Biveinis
Description:
lp:mysql-server/5.1 revno 3997, compiled with BUILD/compile-amd64-debug-max-no-ndb fails mysql and mysql_upgrade testcases with what appears to be wrong errno value -1 in the client.

A quick analysis suggests that it's caused by a gethostbyname_r call that returns -1 (NETDB_INTERNAL) in the errno arg, which then means that the real errno should be read from the global errno var. If that's true, then still no idea why it's returning NETDB_INTERNAL in the first place.

How to repeat:
5.1$ bzr revno
3997
5.1$ BUILD/compile-amd64-debug-max-no-ndb
...
5.1$ cd mysql-test
5.1/mysql-test$ ./mysql-test-run --mem mysql
...
@@ -162,14 +162,14 @@
 ERROR 1049 (42000) at line 1: Unknown database 'invalid'
 Test connect with dbname + hostname
 Test connect with dbname + _invalid_ hostname
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (-1)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (-1)
 The commands reported in the bug report
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyril has found a bug :)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyril has found a bug :)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (-1)
 Too long dbname
 ERROR 1102 (42000) at line 1: Incorrect database name 'test_really_long_dbnamexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 Too long hostname
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (-1)
 1
 1
 ERROR at line 1: DELIMITER cannot contain a backslash character
@@ -198,7 +198,7 @@
 1
 COUNT (*)
 1
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (-1)
 End of 5.0 tests
 WARNING: --server-arg option not supported in this configuration.
 Warning (Code 1286): Unknown table engine 'nonexistent'

mysqltest: Result content mismatch

5.1/mysql-test$ ./mysql-test-run --mem mysql_upgrade

@@ -94,7 +94,7 @@
 mysql.user                                         OK
 DROP USER mysqltest1@'%';
 Run mysql_upgrade with a non existing server socket
-mysqlcheck: Got error: 2005: Unknown MySQL server host 'not_existing_host' (errno) when trying to connect
+mysqlcheck: Got error: 2005: Unknown MySQL server host 'not_existing_host' (-1) when trying to connect
 FATAL ERROR: Upgrade failed
 set GLOBAL sql_mode='STRICT_ALL_TABLES,ANSI_QUOTES,NO_ZERO_DATE';
 mtr.global_suppressions                            OK

Suggested fix:
Will be provided below if my analysis works out.
[2 Jun 2013 8:54] Laurynas Biveinis
It appears that there are two issues.

1) gethostbyname_r returning -1 in h_errno, as described above

If this is fixed to copy errno to h_errno in my_gethostbyname_r(), then the following testcase failure still remains:

 The commands reported in the bug report
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyril has found a bug :)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyril has found a bug :)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (-1)
 Too long dbname
 ERROR 1102 (42000) at line 1: Incorrect database name 'test_really_long_dbnamexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 Too long hostname
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (-1)
 1

Thus,
2) this appears to be caused by gethostbyname_r returning 0 (success), but setting hostent *result to NULL.
[2 Jun 2013 9:00] Laurynas Biveinis
The following fixes the testsuite failures for me. I have no idea whether that's really correct, as I was not find info under what circumstances gethostbyname_r returns such values. Also the *h_errno = errno copying makes the my_gethostbyname_r() interface deviate from the underlying gethostbyname_r() interface, which is also suboptimal I guess.

This appears to be a 5.1-only issue BTW.

=== modified file 'mysys/my_net.c'
--- mysys/my_net.c	2013-03-19 12:29:12 +0000
+++ mysys/my_net.c	2013-06-02 08:56:24 +0000
@@ -60,9 +60,15 @@
 				   int buflen, int *h_errnop)
 {
   struct hostent *hp;
+  int result_hostent;
   DBUG_ASSERT((size_t) buflen >= sizeof(*result));
-  if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
+  result_hostent= gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop);
+  if (unlikely(!result_hostent || !hp)) {
+    if (*h_errnop == NETDB_INTERNAL) {
+      *h_errnop= errno;
+    }
     return 0;
+  }
   return hp;
 }
[2 Jun 2013 9:07] Laurynas Biveinis
Editing the title to show the user, not testsuite/developer impact.
[2 Jun 2013 10:33] Laurynas Biveinis
Inverted error condition typo in the suggested fix :( Also renamed the return value variable for gethostbyname_r to something more reasonable.

@@ -60,9 +60,15 @@
 				   int buflen, int *h_errnop)
 {
   struct hostent *hp;
+  int ret;
   DBUG_ASSERT((size_t) buflen >= sizeof(*result));
-  if (gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop))
+  ret= gethostbyname_r(name,result, buffer, (size_t) buflen, &hp, h_errnop);
+  if (unlikely(ret || !hp)) {
+    if (*h_errnop == NETDB_INTERNAL) {
+      *h_errnop= errno;
+    }
     return 0;
+  }
   return hp;
 }
[3 Jun 2013 12:58] Miguel Solorzano
Not repeatable on CenTOS 6.4 X86_64 with revno 4017:

=============================================================================

TEST                                      RESULT   TIME (ms)
------------------------------------------------------------

worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 13000..13009
main.mysql                               [ pass ]  29641
i_main.mysql                             [ pass ]     72
------------------------------------------------------------
The servers were restarted 0 times
Spent 29.713 of 31 seconds executing testcases

Completed: All 2 tests were successful.

[miguel@tikal mysql-test]$ ./mysql-test-run --mem mysql_upgrade
Logging: ./mysql-test-run  --mem mysql_upgrade
130603  9:23:33 [Note] Plugin 'FEDERATED' is disabled.
MySQL Version 5.1.71
Checking supported features...
 - skipping ndbcluster
 - SSL connections supported
 - binaries are debug compiled
Collecting tests...
vardir: /home/miguel/temp/mysql-5.1/mysql-test/var
Checking leftover processes...
Removing old var directory...
Creating var directory '/home/miguel/temp/mysql-5.1/mysql-test/var'...
 - symlinking 'var' to '/dev/shm/var_auto_wHMb'
Installing system database...
Using server port 34534

==============================================================================

TEST                                      RESULT   TIME (ms)
------------------------------------------------------------

worker[1] Using MTR_BUILD_THREAD 300, with reserved ports 13000..13009
main.mysql_upgrade                       [ pass ]  13458
------------------------------------------------------------
The servers were restarted 0 times
Spent 13.458 of 14 seconds executing testcases

Completed: All 1 tests were successful.

[miguel@tikal mysql-test]$
[3 Jun 2013 13:00] Laurynas Biveinis
Yes, for some reason (glibc version?) this is Ubuntu 13.04-specific. We haven't seen this on any other Linux distribution or any other Ubuntu version.
[3 Jun 2013 15:15] Miguel Solorzano
Thank you for the feedback. Indeed only repeatable on Ubuntu 13.04:

 Too long hostname
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'cyrils_superlonghostnameXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' (-1)
 1
 1
 ERROR at line 1: DELIMITER cannot contain a backslash character
@@ -198,7 +198,7 @@
 1
 COUNT (*)
 1
-ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (errno)
+ERROR 2005 (HY000) at line 1: Unknown MySQL server host 'invalid_hostname' (-1)
 End of 5.0 tests
 WARNING: --server-arg option not supported in this configuration.
 Warning (Code 1286): Unknown table engine 'nonexistent'

mysqltest: Result content mismatch

 - saving '/home/miguel/mysql-5.1/mysql-test/var/log/main.mysql/' to '/home/miguel/mysql-5.1/mysql-test/var/log/main.mysql/'

Only  1  of 2 completed.
mysql-test-run: *** ERROR: Not all tests completed
miguel@miguel:~/mysql-5.1/mysql-test$ cat /etc/issue
Ubuntu 13.04 \n \l

miguel@miguel:~/mysql-5.1/mysql-test$