[PATCH] gconv: Check reference count in __gconv_release_cache [BZ #24677]
Carlos O'Donell
carlos@redhat.com
Thu Jul 25 21:41:00 GMT 2019
On 7/25/19 5:31 PM, Florian Weimer wrote:
> * Carlos O'Donell:
>
>> On 7/18/19 12:21 PM, Florian Weimer wrote:
>>> This fixes a regression introduced in commit
>>> 7e740ab2e7be7d83b75513aa406e0b10875f7f9c ("libio: Fix gconv-related
>>> memory leak [BZ #24583]").
>>>
>>> __gconv_release_cache is only ever called with heap-allocated
>>> arrays which contain at least one member. The statically allocated
>>> ASCII steps are filtered out by __wcsmbs_close_conv.
>>>
>>> [This variant cleans up __gconv_release_cache somewhat and includes the
>>> test modification suggested by Yann.
>>>
>>> The test does not work due to bug 24824. I think installing all locales
>>> unconditionally is too costly timewise. Suggestions how to proceed are
>>> very welcome.]
>>>
>>> 2019-07-18 Florian Weimer <fweimer@redhat.com>
>>>
>>> [BZ #24677]
>>> * iconv/gconv_cache.c (__gconv_release_cache): Check reference
>>> counter before freeing array.
>>> * libio/Makefile (tests-container): Add tst-wfile-fclose-exit.
>>> * libio/tst-wfile-fclose-exit.c: New file.
>>> * libio/tst-wfile-fclose-exit.root/postclean.req: Likewise.
>>
>> Please post a v2 without a test case.
>
> Thanks. Please see below.
>
>> You'll have to confirm this works by hand and I'm OK with that for
>> now.
>
> valgrind is clean, but __libc_freeres is not fully effective:
I expected something like this would happen.
> ==2503== 208 bytes in 1 blocks are still reachable in loss record 1 of 2
> ==2503== at 0x480B80B: malloc (vg_replace_malloc.c:309)
> ==2503== by 0x4847876: __gconv_lookup_cache (gconv_cache.c:366)
> ==2503== by 0x483F9A1: __gconv_find_transform (gconv_db.c:733)
> ==2503== by 0x48C8847: __wcsmbs_getfct (wcsmbsload.c:92)
> ==2503== by 0x48C89A9: __wcsmbs_load_conv (wcsmbsload.c:186)
> ==2503== by 0x48C8C26: get_gconv_fcts (wcsmbsload.h:75)
> ==2503== by 0x48C8C26: __wcsmbs_clone_conv (wcsmbsload.c:222)
> ==2503== by 0x4890B50: _IO_fwide (iofwide.c:79)
> ==2503== by 0x488E359: __wuflow (wgenops.c:225)
> ==2503== by 0x488C447: getwc (getwc.c:39)
> ==2503== by 0x402581: do_test (tst-wfile-fclose-exit.c:45)
> ==2503== by 0x403044: support_test_main (support_test_main.c:350)
> ==2503== by 0x4023C4: main (test-driver.c:168)
> ==2503==
> ==2503== 208 bytes in 1 blocks are still reachable in loss record 2 of 2
> ==2503== at 0x480B80B: malloc (vg_replace_malloc.c:309)
> ==2503== by 0x48477AE: __gconv_lookup_cache (gconv_cache.c:366)
> ==2503== by 0x483F9A1: __gconv_find_transform (gconv_db.c:733)
> ==2503== by 0x48C8847: __wcsmbs_getfct (wcsmbsload.c:92)
> ==2503== by 0x48C89C6: __wcsmbs_load_conv (wcsmbsload.c:189)
> ==2503== by 0x48C8C26: get_gconv_fcts (wcsmbsload.h:75)
> ==2503== by 0x48C8C26: __wcsmbs_clone_conv (wcsmbsload.c:222)
> ==2503== by 0x4890B50: _IO_fwide (iofwide.c:79)
> ==2503== by 0x488E359: __wuflow (wgenops.c:225)
> ==2503== by 0x488C447: getwc (getwc.c:39)
> ==2503== by 0x402581: do_test (tst-wfile-fclose-exit.c:45)
> ==2503== by 0x403044: support_test_main (support_test_main.c:350)
> ==2503== by 0x4023C4: main (test-driver.c:168)
>
> Note that this leak is only visibile with --leak-check=full
> --show-reachable, and only affects programs which use wide streams in
> certain ways.
That's fine. Thanks for checking. It's much better than double-free.
> So we may have to tweak the code that frees the gconv cache. This is
> quite risky because at that point, the steps array is still referenced
> from the current locale. For glibc 2.31, we should perhaps switch to
> the C locale at the start of __libc_free as a fix. (In glibc 2.29 and
> earlier, I believe we free the gconv cache even though its entries are
> still in use.)
Yes, I assume you mean __libc_freeres? Yes, in __libc_freeres we can do
all sorts of things like switch to the C locale, and then free all the
objects.
> Florian
>
> gconv: Check reference count in __gconv_release_cache [BZ #24677]
>
> This fixes a regression introduced in commit
> 7e740ab2e7be7d83b75513aa406e0b10875f7f9c ("libio: Fix gconv-related
> memory leak [BZ #24583]").
>
> __gconv_release_cache is only ever called with heap-allocated
> arrays which contain at least one member. The statically allocated
> ASCII steps are filtered out by __wcsmbs_close_conv.
>
> 2019-07-25 Florian Weimer <fweimer@redhat.com>
>
> [BZ #24677]
> * iconv/gconv_cache.c (__gconv_release_cache): Check reference
> counter before freeing array.
>
> diff --git a/iconv/gconv_cache.c b/iconv/gconv_cache.c
> index 9a456bf825..4db7287cee 100644
> --- a/iconv/gconv_cache.c
> +++ b/iconv/gconv_cache.c
> @@ -446,9 +446,12 @@ __gconv_lookup_cache (const char *toset, const char *fromset,
> void
> __gconv_release_cache (struct __gconv_step *steps, size_t nsteps)
> {
> - if (gconv_cache != NULL)
> - /* The only thing we have to deallocate is the record with the
> - steps. */
> + /* The only thing we have to deallocate is the record with the
> + steps. But do not do this if the reference counter is still
> + positive. This can happen if the steps array was cloned by
> + __wcsmbs_clone_conv. (The array elements have separate __counter
> + fields, but they are only out of sync temporarily.) */
> + if (gconv_cache != NULL && steps->__counter == 0)
> free (steps);
> }
>
>
OK. Please commit to master.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
--
Cheers,
Carlos.
More information about the Libc-alpha
mailing list