Skip to content

Instantly share code, notes, and snippets.

@yousong
Last active January 24, 2018 08:54
Show Gist options
  • Save yousong/99e61d79af39786c82d70ee565a789a9 to your computer and use it in GitHub Desktop.
Save yousong/99e61d79af39786c82d70ee565a789a9 to your computer and use it in GitHub Desktop.
memory leak in sort command of coreutils-8.4-31.el6

I noticed this issue when a --merge sort was killed because of oom. It shouldn't.

Sort utility built from vanilla coreutils-8.4.tar.xz was not affected.

Sort utility built from coreutils-8.4-31.el6.src.rpm fails and valgrind show that it was caused by coreutils-i18n.patch

The issue was caused by calls to mbsrtowcs, wcsrtombs which will modify *src to NULL causing later free() to fail.

The code snippet

2371   month = (char *) xmalloc (len + 1);
2372
2373   tmp = (char *) xmalloc (len + 1);
2374   memcpy (tmp, s, len);
2375   tmp[len] = '\0';
2376   pp = (const char **)&tmp;
2377   month_wcs = (wchar_t *) xmalloc ((len + 1) * sizeof (wchar_t));
2378   memset (&state, '\0', sizeof(mbstate_t));
2379
2380   wclength = mbsrtowcs (month_wcs, pp, len + 1, &state);
2381   assert (wclength != (size_t)-1 && *pp == NULL);
2382
2383   for (i = 0; i < wclength; i++)
2384     {
2385       month_wcs[i] = towupper(month_wcs[i]);
2386       if (iswblank (month_wcs[i]))
2387         {
2388           month_wcs[i] = L'\0';
2389           break;
2390         }
2391     }
2392
2393   wpp = (const wchar_t **)&month_wcs;
2394
2395   mblength = wcsrtombs (month, wpp, len + 1, &state);

Valgrind report

==115765== 10,312 bytes in 7 blocks are definitely lost in loss record 18 of 23
==115765==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==115765==    by 0x40ED18: xmalloc (xmalloc.c:45)
==115765==    by 0x4054EF: getmonth_mb (sort.c:2377)
==115765==    by 0x407A19: keycompare_mb (sort.c:2651)
==115765==    by 0x40626F: compare (sort.c:2793)
==115765==    by 0x4080DA: mergefps (sort.c:2995)
==115765==    by 0x408C83: merge (sort.c:3419)
==115765==    by 0x403376: main (sort.c:4340)
==115765==
==115765== 12,374,304 bytes in 37,272 blocks are definitely lost in loss record 20 of 23
==115765==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==115765==    by 0x40ED18: xmalloc (xmalloc.c:45)
==115765==    by 0x4054CB: getmonth_mb (sort.c:2373)
==115765==    by 0x407A19: keycompare_mb (sort.c:2651)
==115765==    by 0x40626F: compare (sort.c:2793)
==115765==    by 0x408250: mergefps (sort.c:3093)
==115765==    by 0x408C83: merge (sort.c:3419)
==115765==    by 0x403376: main (sort.c:4340)
==115765==
==115765== 14,458,553 bytes in 37,273 blocks are definitely lost in loss record 21 of 23
==115765==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==115765==    by 0x40ED18: xmalloc (xmalloc.c:45)
==115765==    by 0x4054CB: getmonth_mb (sort.c:2373)
==115765==    by 0x407A0B: keycompare_mb (sort.c:2651)
==115765==    by 0x40626F: compare (sort.c:2793)
==115765==    by 0x408250: mergefps (sort.c:3093)
==115765==    by 0x408C83: merge (sort.c:3419)
==115765==    by 0x403376: main (sort.c:4340)
==115765==
==115765== 49,497,216 bytes in 37,272 blocks are definitely lost in loss record 22 of 23
==115765==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==115765==    by 0x40ED18: xmalloc (xmalloc.c:45)
==115765==    by 0x4054EF: getmonth_mb (sort.c:2377)
==115765==    by 0x407A19: keycompare_mb (sort.c:2651)
==115765==    by 0x40626F: compare (sort.c:2793)
==115765==    by 0x408250: mergefps (sort.c:3093)
==115765==    by 0x408C83: merge (sort.c:3419)
==115765==    by 0x403376: main (sort.c:4340)
==115765==
==115765== 57,831,180 bytes in 37,271 blocks are definitely lost in loss record 23 of 23
==115765==    at 0x4C29BE3: malloc (vg_replace_malloc.c:299)
==115765==    by 0x40ED18: xmalloc (xmalloc.c:45)
==115765==    by 0x4054EF: getmonth_mb (sort.c:2377)
==115765==    by 0x407A0B: keycompare_mb (sort.c:2651)
==115765==    by 0x40626F: compare (sort.c:2793)
==115765==    by 0x408250: mergefps (sort.c:3093)
==115765==    by 0x408C83: merge (sort.c:3419)
==115765==    by 0x403376: main (sort.c:4340)
==115765==
==115765== LEAK SUMMARY:
==115765==    definitely lost: 134,186,793 bytes in 149,116 blocks
==115765==    indirectly lost: 0 bytes in 0 blocks
==115765==      possibly lost: 4,692 bytes in 4 blocks
==115765==    still reachable: 2,103,088 bytes in 37 blocks
==115765==         suppressed: 0 bytes in 0 blocks
==115765== Reachable blocks (those to which a pointer was found) are not shown.
==115765== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==115765==
==115765== For counts of detected and suppressed errors, rerun with: -v
==115765== ERROR SUMMARY: 11 errors from 11 contexts (suppressed: 0 from 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment