diff options
author | Florian Weimer <fweimer@redhat.com> | 2019-07-18 17:27:24 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2019-07-26 00:24:59 +0200 |
commit | 50ce3eae5ba304650459d4441d7d246a7cefc26f (patch) | |
tree | e3679754b8b812c4468fe77156a1b31d5ecf1b2f | |
parent | 7e681561a3aea7aa8f21fb031a7c778147dfdf5b (diff) | |
download | glibc-50ce3eae5ba304650459d4441d7d246a7cefc26f.tar.gz glibc-50ce3eae5ba304650459d4441d7d246a7cefc26f.tar.xz glibc-50ce3eae5ba304650459d4441d7d246a7cefc26f.zip |
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.
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | iconv/gconv_cache.c | 9 |
2 files changed, 12 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog index 31a6b38bd5..dbdb85de6a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2019-07-25 Florian Weimer <fweimer@redhat.com> + + [BZ #24677] + * iconv/gconv_cache.c (__gconv_release_cache): Check reference + counter before freeing array. + 2019-07-24 H.J. Lu <hongjiu.lu@intel.com> [BZ #24603] 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); } |