diff options
author | Father Chrysostomos <sprout@cpan.org> | 2012-12-09 06:05:22 -0800 |
---|---|---|
committer | Father Chrysostomos <sprout@cpan.org> | 2012-12-09 18:47:21 -0800 |
commit | 11ddfebc6e521f916fd05108e3faa74e7ed132b8 (patch) | |
tree | 6b2b9261790150d860d432183c3570ce76ca5ae3 /ext/File-Glob/Glob.xs | |
parent | 6e2f1cd4c88b28bee7c3d0d21ce95d5b9fc4f991 (diff) | |
download | perl-11ddfebc6e521f916fd05108e3faa74e7ed132b8.tar.gz |
Don’t leak when partly iterated glob op is freed
File::Glob keeps its own hash of arrays of file names. Each array corresponds to one call site. When iteration finishes, it deletes
the array. But if iteration never finishes, and the op at the call
site is freed, the array remains. So eval "scalar<*>" will cause a
memory leak.
We already have a mechanism for hooking the freeing of ops. So
File::Glob can use that.
Diffstat (limited to 'ext/File-Glob/Glob.xs')
-rw-r--r-- | ext/File-Glob/Glob.xs | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/ext/File-Glob/Glob.xs b/ext/File-Glob/Glob.xs index 50bb2daacf..4c08776215 100644 --- a/ext/File-Glob/Glob.xs +++ b/ext/File-Glob/Glob.xs @@ -312,6 +312,19 @@ doglob_iter_wrapper(pTHX_ AV *entries, SV *patsv) return FALSE; } +static Perl_ophook_t old_ophook; + +static void +glob_ophook(pTHX_ OP *o) +{ + dMY_CXT; + if (MY_CXT.x_GLOB_ENTRIES + && (o->op_type == OP_GLOB || o->op_type == OP_ENTERSUB)) + hv_delete(MY_CXT.x_GLOB_ENTRIES, (char *)&o, sizeof(OP *), + G_DISCARD); + if (old_ophook) old_ophook(aTHX_ o); +} + MODULE = File::Glob PACKAGE = File::Glob int @@ -385,6 +398,10 @@ BOOT: dMY_CXT; MY_CXT.x_GLOB_ENTRIES = NULL; } + OP_REFCNT_LOCK; + old_ophook = PL_opfreehook; + PL_opfreehook = glob_ophook; + OP_REFCNT_UNLOCK; } INCLUDE: const-xs.inc |