Bug #77877 program terminated by signal BUS in zlib/zutil.c
Submitted: 29 Jul 2015 21:45 Modified: 20 Aug 2015 19:26
Reporter: Dennis Clarke Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: C API (client library) Severity:S2 (Serious)
Version:5.5.45 OS:Solaris (Sparc on Solaris 10)
Assigned to: CPU Architecture:Any
Tags: SIGBUS

[29 Jul 2015 21:45] Dennis Clarke
Description:

Entirely repeatable core dump occurs with a simple web based app that calls mysql_query().

The query string is a simple insert with a few parameters and a long text string which is a base64 encoded representation of a simple PNG image. 

I extracted the mysql 5.5.45 source tree into the expected build path for MySQL GA edition and using dbx on the core file I see ( truncated long lines here ) : 

$ dbx dbs time_1438205239-pid_5874-uid_80-gid_80-fid_dbs.core
Reading dbs
core file header read successfully
Reading ld.so.1
Reading libm.so.2
Reading librt.so.1
Reading libmysqlclient.so.18.0.0
Reading libc.so.1
Reading libaio.so.1
Reading libmd.so.1
Reading libthread.so.1
Reading libnsl.so.1
Reading libsocket.so.1
Reading libc_psr.so.1
t@1 (l@1) program terminated by signal BUS (invalid address alignment)
0xffffffff7e563714: _malloc_unlocked+0x023c:    ldx      [%g5 + 16], %o1
Current function is zcalloc (optimized)
  307                                 (voidpf)calloc(items, size);
(dbx) list                                                                                                                       
  307                                 (voidpf)calloc(items, size);
  308   }
  309   
  310   void  zcfree (opaque, ptr)
  311       voidpf opaque;
  312       voidpf ptr;
  313   {
  314       free(ptr);
  315       if (opaque) return; /* make compiler happy */
  316   }
(dbx) file
zutil.c
(dbx) where
current thread: t@1
  [1] _malloc_unlocked(0x10000, 0x100a445f0, 0x100a445f0, 0x0, 0x0, 0x100a445f0), at 0xffffffff7e563714 
  [2] malloc(0x10000, 0x2400, 0x1dab98, 0xffffffff7e5634c8, 0xffffffff7e73e000, 0x2400), at 0xffffffff7e5634b8 
=>[3] zcalloc(opaque = <value unavailable>, items = 32768U, size = 2U) (optimized), at 0xffffffff7e9524d0 (line ~307) in "zutil.c"
  [4] deflateInit2_(strm = 0xffffffff7ff68520, level = 6, method = <value unavailable>, windowBits = <value unavailable>, memLevel 
  [5] deflateInit_(strm = 0xffffffff7ff68520, level = -1, version = 0xffffffff7e9b96c0 "1.2.3", stream_size = 112) (optimized), at 
  [6] compress2(dest = 0x1009dde90 "", destLen = 0xffffffff7ff686f8, source = <value unavailable>, sourceLen = 8192U, level = -1) (
  [7] compress(dest = 0x1009dde90 "", destLen = 0xffffffff7ff686f8, source = 0x1009dbe77 "@`^B", sourceLen = 8192U) (optimized), at
  [8] my_compress_alloc(packet = 0x1009dbe77 "@`^B", len = 0xffffffff7ff68878, complen = 0xffffffff7ff68870) (optimized), at 0xffff
  [9] my_compress(packet = 0x1009dbe77 "@`^B", len = <value unavailable>, complen = 0xffffffff7ff68870) (optimized), at 0xffffffff7
  [10] net_real_write(net = 0x1001c17e0, packet = 0x1001c5d00 "@`^B", len = 8192U) (optimized), at 0xffffffff7e899828 (line ~611) i
  [11] net_write_buff(net = 0x1001c17e0, packet = 0x100a1e5f0 "insert into objdb.obj ( time_ns, link_id, seqn, sha256, sha512, data
  [12] net_write_command(net = 0x1001c17e0, command = <value unavailable>, header = (nil), head_len = 0, packet = 0x100a1e5f0 "inse
  [13] cli_advanced_command(mysql = 0x1001c17e0, command = <value unavailable>, header = (nil), header_length = 0, arg = 0x100a1e5f
  [14] mysql_send_query(mysql = 0x1001c17e0, query = 0x100a1e5f0 "insert into objdb.obj ( time_ns, link_id, seqn, sha256, sha512, d
  [15] mysql_real_query(mysql = 0x1001c17e0, query = 0x100a1e5f0 "insert into objdb.obj ( time_ns, link_id, seqn, sha256, sha512, d
  [16] mysql_query(mysql = 0x1001c17e0, query = 0x100a1e5f0 "insert into objdb.obj ( time_ns, link_id, seqn, sha256, sha512, data )
  [17] cgiMain(), line 716 in "dbs.c"
  [18] main(argc = 1, argv = 0xffffffff7ffff0d8), line 486 in "cgic.c"

The call to mysql_query() from dbs.c never returns and a sigBUS occurs over and over and only with a particular input.

How to repeat:

I use the web based app dbs wherein I submit a image file test_png_image.png to a file upload control and when the image binary data is converted to base64 encoded string and then inserted into a record in a database we see a sigBUS.  Many other files and file formats are tested and no error occurs.  The app code has not change in many months however with this one particular test image upload the resultant query string results in a sigBUS within the source file : 

/tmp/pb2/build/sb_0-15690336-1435246073.56/mysql-5.5.45/zlib/zutil.c at line 307 thus : 

   300  voidpf zcalloc (opaque, items, size)
   301      voidpf opaque;
   302      unsigned items;
   303      unsigned size;
   304  {
   305      if (opaque) items += size - size; /* make compiler happy */
   306      return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
   307                                (voidpf)calloc(items, size);
   308  }
   309
[5 Aug 2015 0:48] Dennis Clarke
I was able to implement a signal handler to trap both the SIGBUS and the SIGSEGV that would happen from time to time. However, as usual, a signal handler can do very little other than gracefully exit.  This however stops the core dumps and the abnormal Apache 500 Internal Error that a user sees because the MySQL based app seg faulted. 

In any case, as soon as I can isolate a piece of code that triggers the fault I will post the code.

Dennis
[20 Aug 2015 19:26] Dennis Clarke
This is not a bug in MySQL API.

The call to mysql_real_query uses a pointer to a string and a length of the correct string however a recent code change ( on my end ) causes the insert query to be just slightly longer than the memory region allocated for the string. Therefore mysql API was attempting to access the entire string and the last few bytes may have been outside of the region that was allocated with calloc().  This would result in the sigbus or sigsegv. 

All attempts to create a small sample code example failed because my sample code always allocated the correct memory size.