summaryrefslogtreecommitdiff
path: root/regexp.h
diff options
context:
space:
mode:
authorDavid Mitchell <davem@iabyn.com>2017-02-01 15:50:14 +0000
committerDavid Mitchell <davem@iabyn.com>2017-02-01 16:09:07 +0000
commitf8def6c7f38b614db0e8ac0ba76999e9b8cfd1d6 (patch)
tree1cd07aad8b9ed74e2bbb3154195fe15da2244eb1 /regexp.h
parentdc0dad9b91adb09c774c7248bc91a44b7a777d4d (diff)
downloadperl-f8def6c7f38b614db0e8ac0ba76999e9b8cfd1d6.tar.gz
avoid double-freeing regex code blocks
RT #130650 heap-use-after-free in S_free_codeblocks When compiling qr/(?{...})/, a reg_code_blocks structure is allocated and various SVs are attached to it. Initially this is set to be freed via a destructor on the savestack, in case of early dying. Later the structure is attached to the compiling regex, and a boolean flag in the structure, 'attached', is set to true to show that the destructor no longer needs to free the struct. However, it is possible to get three orders of destruction: 1) allocate, push destructor, die early 2) allocate, push destructor, attach to regex, die 2) allocate, push destructor, attach to regex, succeed In 2, the regex is freed (via the savestack) before the destructor is called. In 3, the destructor is called, then later the regex is freed. It turns out perl can't currently handle case 2: qr'(?{})\6' Fix this by turning the 'attached' boolean field into an integer refcount, then keep a count of whether the struct is referenced from the savestack and/or the regex. Since it normally has a value of 1 or 2, it's similar to a boolean flag, but crucially it no longer just indicates that the regex has a pointer to it ('attached'), but that at least one of the savestack and regex have a pointer to it. So order of freeing no longer matters. I also updated S_free_codeblocks() so that it nulls out SV pointers in the reg_code_blocks struct before freeing them. This is is generally good practice to avoid double frees, although is probably not needed at the moment.
Diffstat (limited to 'regexp.h')
-rw-r--r--regexp.h2
1 files changed, 1 insertions, 1 deletions
diff --git a/regexp.h b/regexp.h
index 601a214207..9a2b61a18e 100644
--- a/regexp.h
+++ b/regexp.h
@@ -88,7 +88,7 @@ struct reg_code_block {
/* array of reg_code_block's plus header info */
struct reg_code_blocks {
- bool attached; /* we're attached to a regex (don't need freeing) */
+ int refcnt; /* we may be pointed to from a regex and from the savestack */
int count; /* how many code blocks */
struct reg_code_block *cb; /* array of reg_code_block's */
};