In perl.git, the branch blead has been updated <https://perl5.git.perl.org/perl.git/commitdiff/281cff281e54d71fbedd8c314fe56ae9b58bee67?hp=05d49a9a9b7c8a3b3a1d1b4f1ce46db05b04dcbc>
- Log ----------------------------------------------------------------- commit 281cff281e54d71fbedd8c314fe56ae9b58bee67 Author: David Mitchell <[email protected]> Date: Thu Apr 4 14:38:50 2019 +0100 fix leak in Perl_vload_module() This function allocates a few ops, then calls Perl_utilize(). If the latter function croaks early on, those ops will be leaked, because they won't yet have been linked into the optree. In particular, newUNOP(OP_REQUIRE, ...) can die if passed a non-valid module name. This can be fixed by moving the start_subparse() call to the start of Perl_vload_module(), before any op allocations. start_subparse() creates a new PL_compcv, and so any ops allocated afterwards will come from that CV's slab rather than being directly malloc()ed. On death, the CV will be freed and its op slab will be scanned and any ops found there freed. The leak was showing up in ext/XS-APItest/t/load-module.t under ASan. ----------------------------------------------------------------------- Summary of changes: op.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/op.c b/op.c index 3b0cc76423..350032a106 100644 --- a/op.c +++ b/op.c @@ -7706,10 +7706,29 @@ void Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args) { OP *veop, *imop; - OP * const modname = newSVOP(OP_CONST, 0, name); + OP * modname; + I32 floor; PERL_ARGS_ASSERT_VLOAD_MODULE; + /* utilize() fakes up a BEGIN { require ..; import ... }, so make sure + * that it has a PL_parser to play with while doing that, and also + * that it doesn't mess with any existing parser, by creating a tmp + * new parser with lex_start(). This won't actually be used for much, + * since pp_require() will create another parser for the real work. + * The ENTER/LEAVE pair protect callers from any side effects of use. + * + * start_subparse() creates a new PL_compcv. This means that any ops + * allocated below will be allocated from that CV's op slab, and so + * will be automatically freed if the utilise() fails + */ + + ENTER; + SAVEVPTR(PL_curcop); + lex_start(NULL, NULL, LEX_START_SAME_FILTER); + floor = start_subparse(FALSE, 0); + + modname = newSVOP(OP_CONST, 0, name); modname->op_private |= OPpCONST_BARE; if (ver) { veop = newSVOP(OP_CONST, 0, ver); @@ -7732,18 +7751,7 @@ Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args) } } - /* utilize() fakes up a BEGIN { require ..; import ... }, so make sure - * that it has a PL_parser to play with while doing that, and also - * that it doesn't mess with any existing parser, by creating a tmp - * new parser with lex_start(). This won't actually be used for much, - * since pp_require() will create another parser for the real work. - * The ENTER/LEAVE pair protect callers from any side effects of use. */ - - ENTER; - SAVEVPTR(PL_curcop); - lex_start(NULL, NULL, LEX_START_SAME_FILTER); - utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0), - veop, modname, imop); + utilize(!(flags & PERL_LOADMOD_DENY), floor, veop, modname, imop); LEAVE; } -- Perl5 Master Repository
