Bug #24751 Possible infinite loop in init_io_cache() when insufficient memory
Submitted: 1 Dec 2006 13:00 Modified: 1 Feb 2007 2:38
Reporter: Tomash Brechko
Status: Closed
Category:Server: General Severity:S3 (Non-critical)
Version:4.1, 5.0, 5.1 OS:Linux (Linux)
Assigned to: Kristofer Pettersson Target Version:

[1 Dec 2006 13:00] Tomash Brechko
Description:
There's a possibility for an infinite loop in init_io_cache() on insufficient memory
condition.

How to repeat:
Under bash do 'ulimit -S -v 110000' before running mysqld, then start the server and run
the attached script.

Suggested fix:
In mysys/mf_iocache.c there is the code:

    for (;;)
    {
      uint buffer_block;
(1)   cachesize=(uint) ((ulong) (cachesize + min_cache-1) &
			(ulong) ~(min_cache-1));
      if (cachesize < min_cache)
	cachesize = min_cache;

    ...

      if (cachesize == min_cache)
	DBUG_RETURN(2);				/* Can't alloc cache */
(2)   cachesize= (uint) ((long) cachesize*3/4); /* Try with less memory */
    }

Now imagine if min_cache == 100b, and cachesize == 1100b.  At (1) we mask do
((1100b+100b-1)==1111b) & (~(100b-1)==1100b)==1100b, so cachesize is unchanged.  At (2)
1100b*3/4 == 1001b.  Then back at (1):

  ((1001b+100b-1)==1100b) & 1100b == 1100b

I.e. we got the same chachesize we had started with.  Hence infinite loop.

So the fix might be to change (2) to (more aggressive decline than 3/4)

  cachesize= (uint) ((long) cachesize*3/4 & (ulong) ~(min_cache - 1));

or simply (less aggressive decline)

  cachesize-= min_cache;
[1 Dec 2006 13:02] Tomash Brechko
Test script.

Attachment: bug24751.pl (application/octet-stream, text), 1.31 KiB.

[1 Dec 2006 23:06] Sveta Smirnova
Thank you for the report.

Verified as described using code analysis.
[10 Jan 2007 19:11] Tomash Brechko
Reviewed by e-mail.
[31 Jan 2007 20:11] Chad MILLER
Available in 4.1.23, 5.0.36, 5.1.15-beta.
[1 Feb 2007 2:38] Jon Stephens
Thank you for your bug report. This issue has been committed to our source repository of
that product and will be incorporated into the next release.

If necessary, you can access the source repository and build the latest available version,
including the bug fix. More information about accessing the source trees is available at

    http://dev.mysql.com/doc/en/installing-source.html

Documented as "If there was insufficient memory available to mysqld, this could sometimes
cause the server to hang during startup" in 4.1.23, 5.0.36, and 5.1.15 changelogs. 

Please advise if my interpretation of this bug report was incorrect. Thanks!