In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/207cc8dfc710475ee7d8b4dd64a522bd1cf442d3?hp=dc88277553b8a9ac3a811430ac94cdcd73f44e69>
- Log ----------------------------------------------------------------- commit 207cc8dfc710475ee7d8b4dd64a522bd1cf442d3 Author: David Mitchell <da...@iabyn.com> Date: Tue Apr 16 16:49:47 2019 +0100 fix leak when $LANG unset The following leaked: LANG= perl -e1 because in S_emulate_setlocale(), it was 1) making a copy of $ENV{"LANG"}; 2) throwing that copy away and replacing it with "C" when it discovered that the string was empty. A little judicious reordering of that chunk of code makes the issue go away. Showed up as failures of lib/locale_threads.t under valgrind / ASan. commit 2bfe2a2773c59588ac2bf11b5d9439c92d86fb62 Author: David Mitchell <da...@iabyn.com> Date: Tue Apr 16 15:48:39 2019 +0100 fix locale leaks on utf8 strings For example the following leaked: require POSIX; import POSIX ':locale_h'; setlocale(&POSIX::LC_ALL, 'aa_DJ.iso88591') or die; use locale; my $ok = 'A' lt chr 0x100; Some code in Perl__mem_collxfrm() does a couple of for (j = 1; j < 256; j++) { ... } loops where for each chr(j) character it recursively calls itself, and records the index of the 'smallest' / 'largest' result. However, when updating cur_min_x / cur_max_x, it wasn't freeing the previous value. The symptoms were that valgrind / Address Sanitizer found fault with lib/locale.t commit 44955e7de88913c476b06c9046ed65775b693da7 Author: David Mitchell <da...@iabyn.com> Date: Tue Apr 16 15:28:16 2019 +0100 fix locale leak on zero-length strings For example the following leaked: use locale; my $le = "" le ""; When a comparison is done within locale scope, PERL_MAGIC_collxfrm magic is added to the SV. However, the value set for mg_len is the length of the collated string, not the malloced size of the buffer. This means that mg_len can be set to zero, which by convention, means that mg_ptr shouldn't be freed. For now, fix by putting special-cased code in S_mg_free_struct. After 5.30.0 is out, I'll probably add a PERL_MAGIC_collxfrm-specific svt_free vtable method. The symptoms were that valgrind / Address Sanitizer found fault with lib/locale.t ----------------------------------------------------------------------- Summary of changes: locale.c | 21 ++++++++++----------- mg.c | 8 +++++++- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/locale.c b/locale.c index 81aa00e33f..c3ce587981 100644 --- a/locale.c +++ b/locale.c @@ -769,22 +769,19 @@ S_emulate_setlocale(const int category, const char * default_name; - /* To minimize other threads messing with the environment, we copy - * the variable, making it a temporary. But this doesn't work upon - * program initialization before any scopes are created, and at - * this time, there's nothing else going on that would interfere. - * So skip the copy in that case */ - if (PL_scopestack_ix == 0) { - default_name = PerlEnv_getenv("LANG"); - } - else { - default_name = savepv(PerlEnv_getenv("LANG")); - } + default_name = PerlEnv_getenv("LANG"); if (! default_name || strEQ(default_name, "")) { default_name = "C"; } else if (PL_scopestack_ix != 0) { + /* To minimize other threads messing with the environment, + * we copy the variable, making it a temporary. But this + * doesn't work upon program initialization before any + * scopes are created, and at this time, there's nothing + * else going on that would interfere. So skip the copy + * in that case */ + default_name = savepv(default_name); SAVEFREEPV(default_name); } @@ -3951,6 +3948,7 @@ Perl__mem_collxfrm(pTHX_ const char *input_string, cur_min_x + COLLXFRM_HDR_LEN)) { PL_strxfrm_NUL_replacement = j; + safefree(cur_min_x); cur_min_x = x; } else { @@ -4106,6 +4104,7 @@ Perl__mem_collxfrm(pTHX_ const char *input_string, cur_max_x + COLLXFRM_HDR_LEN)) { PL_strxfrm_max_cp = j; + safefree(cur_max_x); cur_max_x = x; } else { diff --git a/mg.c b/mg.c index 320e2d39bb..afe452fc5d 100644 --- a/mg.c +++ b/mg.c @@ -556,12 +556,18 @@ S_mg_free_struct(pTHX_ SV *sv, MAGIC *mg) const MGVTBL* const vtbl = mg->mg_virtual; if (vtbl && vtbl->svt_free) vtbl->svt_free(aTHX_ sv, mg); - if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) { + + if (mg->mg_type == PERL_MAGIC_collxfrm && mg->mg_len >= 0) + /* collate magic uses string len not buffer len, so + * free even with mg_len == 0 */ + Safefree(mg->mg_ptr); + else if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) { if (mg->mg_len > 0 || mg->mg_type == PERL_MAGIC_utf8) Safefree(mg->mg_ptr); else if (mg->mg_len == HEf_SVKEY) SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr)); } + if (mg->mg_flags & MGf_REFCOUNTED) SvREFCNT_dec(mg->mg_obj); Safefree(mg); -- Perl5 Master Repository