Bug #42064 low memory crash when importing hex strings, in Item_hex_string::Item_hex_string
Submitted: 12 Jan 2009 21:08 Modified: 14 Oct 2010 13:21
Reporter: Shane Bester (Platinum Quality Contributor) Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: DML Severity:S1 (Critical)
Version:5.0.76, 5.1.30, 5.1.31, 5.1.46, 6.1.10 OS:Any
Assigned to: Alexey Kopytov CPU Architecture:Any

[12 Jan 2009 21:08] Shane Bester
Description:
When importing hex encoded strings or blobs, and memory allocation fails, server crashes:

090112 22:34:17 [ERROR] Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to use
090112 22:34:23 - mysqld got exception 0xc0000005 ;

00489BE4 mysqld-debug.exe!Item_hex_string::Item_hex_string()[item.cc:5062]
007AB08C mysqld-debug.exe!MYSQLparse()[sql_yacc.yy:10743]
0068607F mysqld-debug.exe!parse_sql()[sql_parse.cc:7638]
00681C49 mysqld-debug.exe!mysql_parse()[sql_parse.cc:5751]
0067662A mysqld-debug.exe!dispatch_command()[sql_parse.cc:1200]
00675CE4 mysqld-debug.exe!do_command()[sql_parse.cc:857]
0078B706 mysqld-debug.exe!handle_one_connection()[sql_connect.cc:1115]
0085C196 mysqld-debug.exe!pthread_start()[my_winthread.c:85]
009D2CA1 mysqld-debug.exe!_callthreadstart()[thread.c:293]
009D2C47 mysqld-debug.exe!_threadstart()[thread.c:277]
7D4DFFF1 kernel32.dll!FlsSetValue()
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort...

How to repeat:
run 32-bit version of mysqld and allocate between 1700M -> 2400M for the key_buffer_size.  then import the file listed in the private section.  If crash doesn't occur, then try increase or decrease key_buffer_size to adjust the available memory.   failures to malloc can be at different points on various platforms.   I think, the stack trace+line numbers is good enough to find the bug.

I repeated this on both windows and linux.

Suggested fix:
don't crash, return error message
[15 Jan 2009 13:02] MySQL Verification Team
I wasn't sure if this is a Server:DML bug or Parser bug.  Please set new lead/assignee if it's wrong.
[23 Feb 2009 14:58] Alexey Kopytov
I have problems reproducing this bug with the described symptoms on my local machine, but I believe the crash is caused by memory overcommit (aka not really fixable). Could you try to reproduce it on Linux with vm.overcommit_memory = 2 (echo 2 > /proc/sys/vm/overcommit_memory) and post the results?
[24 Mar 2009 0:00] Bugs System
No feedback was provided for this bug for over a month, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
[23 Sep 2009 21:00] Gurbindar Biln
I was wondering if this bug was fixed.  If you are still having problems reproducing this issue, please speak with Shane Bester or Shawn Green.  They were the ones that helped me with this issue.  Shane was actually able to successfully reproduce this issue.
[29 Dec 2009 6:59] MySQL Verification Team
5.1.41 crashed when importing that dump into a debug build started like this:
mysqld-debug --console --skip-grant-tables --max-allowed-packet=1G --safemalloc-mem-limit=340000000 --skip-name-resolve

mysqld-debug.exe!Lex_input_stream::yyGet()[sql_lex.h:1197]
mysqld-debug.exe!MYSQLlex()[sql_lex.cc:817]
mysqld-debug.exe!MYSQLparse()[sql_yacc.cc:15616]
mysqld-debug.exe!parse_sql()[sql_parse.cc:7839]
mysqld-debug.exe!mysql_parse()[sql_parse.cc:5933]
mysqld-debug.exe!dispatch_command()[sql_parse.cc:1231]
mysqld-debug.exe!do_command()[sql_parse.cc:872]
mysqld-debug.exe!handle_one_connection()[sql_connect.cc:1127]
mysqld-debug.exe!pthread_start()[my_winthread.c:85]
mysqld-debug.exe!_callthreadstart()[thread.c:293]
mysqld-debug.exe!_threadstart()[thread.c:277]

unsigned char yyGet()
{
   char c= *m_ptr++;
   if (m_echo)
     *m_cpp_ptr++ = c; <----------- crash here, null ptr deref
   return c;
}
[30 Dec 2009 22:44] MySQL Verification Team
A X64 5.0 debug server gives the below error message, is necessary more test?

C:\dbs\5.0\bin>mysqld-debug --console --skip-grant-tables --max-allowed-packet=1G --safemalloc-mem-limit=340000000 --skip-n
ame-resolve
InnoDB: The first specified data file .\ibdata1 did not exist:
InnoDB: a new database to be created!
091230 20:36:51  InnoDB: Setting file .\ibdata1 size to 10 MB
InnoDB: Database physically writes the file full: wait...
091230 20:36:51  InnoDB: Log file .\ib_logfile0 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile0 size to 5 MB
InnoDB: Database physically writes the file full: wait...
091230 20:36:51  InnoDB: Log file .\ib_logfile1 did not exist: new to be created
InnoDB: Setting log file .\ib_logfile1 size to 5 MB
InnoDB: Database physically writes the file full: wait...
InnoDB: Doublewrite buffer not found: creating new
InnoDB: Doublewrite buffer created
InnoDB: Creating foreign key constraint system tables
InnoDB: Foreign key constraint system tables created
091230 20:36:52  InnoDB: Started; log sequence number 0 0
091230 20:36:52 [Note] mysqld-debug: ready for connections.
Version: '5.0.90-Win X64-debug'  socket: ''  port: 3306  Source distribution
091230 20:39:24 [ERROR] mysqld-debug: Out of memory at line 201, '.\my_alloc.c'
091230 20:39:24 [ERROR] mysqld-debug: needed 137307568 byte (134090k), memory in use: 284676152 bytes (278005k)
091230 20:39:24 [ERROR] Out of memory; check if mysqld or some other process uses all available memory; if not, you may hav
e to use 'ulimit' to allow mysqld to use more memory or you can add more swap space
091230 20:39:24 [ERROR] mysqld-debug: Out of memory at line 201, '.\my_alloc.c'
[31 Dec 2009 5:52] MySQL Verification Team
Miguel, of course you'll get out of memory messages because you used 
--safemalloc-mem-limit option.  But you got no crash.  Perhaps try increase or decrease it by some kilobytes and check if a crash happens. different versions and different bit's (32/64) will have a different crashing point.  I think the bug might be in parser code maybe.
[12 Mar 2010 2:27] MySQL Verification Team
Back to verified:

Attempting backtrace. You can use the following information to find out
where mysqld died. If you see no messages after this, something went
terribly wrong...
0000000140144C92    mysqld.exe!Lex_input_stream::yyGet()[sql_lex.h:1199]
000000014013EB05    mysqld.exe!MYSQLlex()[sql_lex.cc:817]
00000001403B6C9D    mysqld.exe!MYSQLparse()[sql_yacc.cc:15595]
00000001402194C7    mysqld.exe!parse_sql()[sql_parse.cc:7847]
00000001402135C5    mysqld.exe!mysql_parse()[sql_parse.cc:5934]
000000014020423B    mysqld.exe!dispatch_command()[sql_parse.cc:1235]
00000001402034EA    mysqld.exe!do_command()[sql_parse.cc:874]
00000001400C7235    mysqld.exe!handle_one_connection()[sql_connect.cc:1127]
0000000140604D45    mysqld.exe!pthread_start()[my_winthread.c:85]
00000001405DAFB5    mysqld.exe!_callthreadstart()[thread.c:295]
00000001405DAF87    mysqld.exe!_threadstart()[thread.c:277]
000000007781BE3D    kernel32.dll!BaseThreadInitThunk()
0000000077956A51    ntdll.dll!RtlUserThreadStart()
Trying to get some variables.
Some pointers may be invalid and cause the dump to abort...
thd->query at 0000000015BD00A8=INSERT INTO `files` (`file_id`,`file_name`,`file_type`,`file_size`,`file_content`) VALUES

 (11,'mysqlmonitor-1.3.2.9126-windows-installer.exe','application/octet-stream',68653772,0x4D5A90000300000004000000FFFF0
000B800000000000000400000000000000000000000000000000000000000000000000000000000000000000000000100000E1FBA0E00B409CD21B80
14CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A24000000000000004AE2EF870E838
1D40E8381D40E8381D4759F8DD4068381D48D9F8FD4078381D4E69C8BD4058381D4E69C85D40C8381D40E8381D40D8381D46C9C92D4018381D40E838
0D4048181D4E69C97D41F8381D4E69C94D4DD8381D4B68587D40F8381D4526963680E8381D4000000000000000000000000000000000000000000000
000504500004C0103004DA908480000000000000000E0000F010B010600003009000050000000A0150020D01E0000B0150000E01E000000400000100
000000200000400000000000000040000000000000000301F00001000000000000002000000000010000010000000001000001000000000000010000
0000000000000000000B4281F004C02000000E01E00B4480000000000000000000000000000000000000000000000
thd->thread_id=1
thd->killed=NOT_KILLED
The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains
information that should help you find out what is causing the crash.

C:\DBS\5.1>bin\mysqld --version
bin\mysqld  Ver 5.1.46-Win X64-debug for Win64 on unknown (Source distribution)
[19 May 2010 10:31] Alexey Kopytov
It looks like my requests to re-verify this bug with overcommit disabled were ignored.

The original report says "I repeated this on both windows and linux". Since both Linux and Windows overcommit memory, it is impossible for an application to detect the OOM condition. All allocations will return a valid address, but if the OS has run out of virtual memory, and attempts to write to previously allocated memory will result in a crash. There is nothing an application can do about it, it is a matter of OS configuration.

If this bug is repeatable on Linux, please do:

echo 2 > /proc/sys/vm/overcommit_memory
echo 0 > /proc/sys/vm/overcommit_ratio

and then try to reproduce the bug again.
[19 May 2010 10:51] MySQL Verification Team
5.1.46 still crashes.  This is not related to overcommit.

use a debug server and --safemalloc-mem-limit=340000000 option to invoke the crash.  Can the server return "out of memory" error instead of crashing in this case?

Version: '5.1.46-enterprise-gpl-advanced-debug'  socket: ''  port: 3306  MySQL Enterprise Server - Advanced Edition Debug (GPL)
100519 12:49:40 [ERROR] mysqld-debug: Out of memory at line 201, '.\my_alloc.c'
100519 12:49:40 [ERROR] mysqld-debug: needed 138058432 byte (134823k), memory in use: 284708429 bytes (278036k)
100519 12:49:40 [ERROR] Out of memory; check if mysqld or some other process uses all available memory; if not, you may have to

mysqld-debug.exe!Lex_input_stream::yyGet()[sql_lex.h:1199]
mysqld-debug.exe!MYSQLlex()[sql_lex.cc:817]
mysqld-debug.exe!MYSQLparse()[sql_yacc.cc:15837]
mysqld-debug.exe!parse_sql()[sql_parse.cc:7847]
mysqld-debug.exe!mysql_parse()[sql_parse.cc:5934]
mysqld-debug.exe!dispatch_command()[sql_parse.cc:1233]
mysqld-debug.exe!do_command()[sql_parse.cc:874]
mysqld-debug.exe!handle_one_connection()[sql_connect.cc:1127]
mysqld-debug.exe!pthread_start()[my_winthread.c:85]
mysqld-debug.exe!_callthreadstart()[thread.c:293]
mysqld-debug.exe!_threadstart()[thread.c:277]
kernel32.dll!FlsSetValue()
[19 May 2010 11:46] Alexey Kopytov
The backtrace is different from the one used in the original report. So we are talking about two different issues here. The later one is a bug in the parser code. The original one was related to overcommit and will still be repeatable even when the parser bug is fixed.
[20 May 2010 9:20] Alexey Kopytov
The original backtrace is from 5.0, and is caused purely by overcommit. Item_hex_string::Item_hex_string(const char *str, uint str_length) allocates buffer for the resulting string, malloc() returns a non-NULL pointer even though the system does not have enough memory, then we get a crash when trying to populate this buffer. There is nothing to fix there.

5.1 is a different story. It allocates memory for the input stream in the Lex_stream_constructor (while 5.0 is reusing the existing buffer). The status of this allocation is not checked, so we get crash in case of failure. The fix it to check thd->is_error(), since the allocation is in the constructor and we don't have a return code.
[21 May 2010 11:24] 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/108866

3387 Alexey Kopytov	2010-05-21
      Bug #42064: low memory crash when importing hex strings, in
                  Item_hex_string::Item_hex_string
      
      The status of memory allocation in the Lex_input_stream (called
      from the Parser_state constructor) was not checked which led to
      a parser crash in case of the out-of-memory error.
      
      The solution is to introduce new init() member function in
      Parser_state and Lex_input_stream so that status of memory
      allocation can be returned to the caller.
     @ mysql-test/r/error_simulation.result
        Added a test case for bug #42064.
     @ mysql-test/t/error_simulation.test
        Added a test case for bug #42064.
     @ mysys/my_alloc.c
        Added error injection code for the regression test.
     @ mysys/my_malloc.c
        Added error injection code for the regression test.
     @ mysys/safemalloc.c
        Added error injection code for the regression test.
     @ sql/event_data_objects.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/mysqld.cc
        Added error injection code for the regression test.
     @ sql/sp.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/sql_lex.cc
        Moved memory allocation from constructor to the separate init()
        member function.
        Added error injection code for the regression test.
     @ sql/sql_lex.h
        Moved memory allocation from constructor to the separate init()
        member function.
     @ sql/sql_parse.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/sql_partition.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/sql_prepare.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/sql_trigger.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures.
     @ sql/sql_view.cc
        Use the new init() member function of Parser_state and check
        its return value to handle memory allocation failures..
     @ sql/thr_malloc.cc
        Added error injection code for the regression test.
[12 Jun 2010 5:53] 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/110917

3430 Alexey Kopytov	2010-06-12
      Addendum for the fix for bug #42064:
      
      In Prepared_statement::prepare() bail out as soon as
      parser_state.init() fails, trying to continue leads to crashes.
[17 Jun 2010 6:14] Bugs System
Pushed into 5.5.5-m3 (revid:alexey.kopytov@sun.com-20100615145247-8bj0vmuqlotbqsn9) (version source revid:alexey.kopytov@sun.com-20100612055628-l5kpl6dllvtr8163) (merge vers: 5.5.5-m3) (pib:16)
[17 Jun 2010 6:18] Bugs System
Pushed into mysql-next-mr (revid:alik@sun.com-20100615150216-cubqoyn1fj9b6a2p) (version source revid:alik@sun.com-20100615081608-4ieksdrefamsw3v9) (pib:16)
[29 Jun 2010 8:27] 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/112415

3452 Martin Hansson	2010-06-29
      Fix of bad merge of test case for Bug#42064 (test case moved).
[12 Jul 2010 17:19] Paul DuBois
Noted in 5.5.5 changelog.

The server could crash with an out of memory error when trying to
parse a query that was too long to fit in memory. Now the parser
rejects such queries with an ER_OUT_OF_RESOURCES error. 

Setting report to Need Merge pending further pushes.
[19 Jul 2010 14:37] Bugs System
Pushed into 5.1.49 (revid:build@mysql.com-20100719143034-omcma40sblwmay3x) (version source revid:alexey.kopytov@sun.com-20100612055231-8f2dfgv5tk36sp6b) (merge vers: 5.1.48) (pib:16)
[19 Jul 2010 19:30] Paul DuBois
Noted in 5.1.49 changelog.
[14 Oct 2010 8:39] Bugs System
Pushed into mysql-5.1-telco-7.0 5.1.51-ndb-7.0.20 (revid:martin.skold@mysql.com-20101014082627-jrmy9xbfbtrebw3c) (version source revid:vasil.dimov@oracle.com-20100531152341-x2d4hma644icamh1) (merge vers: 5.5.5-m3) (pib:21)
[14 Oct 2010 8:54] Bugs System
Pushed into mysql-5.1-telco-6.3 5.1.51-ndb-6.3.39 (revid:martin.skold@mysql.com-20101014083757-5qo48b86d69zjvzj) (version source revid:vasil.dimov@oracle.com-20100531152341-x2d4hma644icamh1) (merge vers: 5.5.5-m3) (pib:21)
[14 Oct 2010 9:12] Bugs System
Pushed into mysql-5.1-telco-6.2 5.1.51-ndb-6.2.19 (revid:martin.skold@mysql.com-20101014084420-y54ecj85j5we27oa) (version source revid:vasil.dimov@oracle.com-20100531152341-x2d4hma644icamh1) (merge vers: 5.5.5-m3) (pib:21)
[14 Oct 2010 13:21] Jon Stephens
Already documented in the 5.1.49 changelog; no additional changelog entries required. Set back to Closed state.