summaryrefslogtreecommitdiff
path: root/op.c
diff options
context:
space:
mode:
authorYves Orton <demerphq@gmail.com>2022-11-22 15:41:14 +0100
committerYves Orton <demerphq@gmail.com>2022-11-23 11:28:17 +0100
commita511d7dcd744640a1ebc498a80f1d05411368c83 (patch)
treeb4f1b91e2b01437e9e3b774df713911ef8c076b9 /op.c
parent4d6de2e9446beedb11b442184296d8c374d12741 (diff)
downloadperl-a511d7dcd744640a1ebc498a80f1d05411368c83.tar.gz
op.c - add support for empty RCPV strings.
Currently we have no need for an empty shared string, but there is no reason it should not be possible. This patch reworks the internals so it is possible to create one without triggering asserts. Currently we don't use this, but it seems reasonable that someone might want it in the future. Under DEBUGGING we will still assert if someone tries to create an empty RCPV unless the flag specifies it should be allowed. At the same time the docs for rcpv_new() have been cleaned up a bit to be more correct and reflect what actually happens inside. This changes things so that the len member of the RCPV structure is always non-zero in a well formed structure by accounting for the null we add to the end explicitly. The RCPV_LEN() macro continues to return the old value (not including the null).
Diffstat (limited to 'op.c')
-rw-r--r--op.c52
1 files changed, 39 insertions, 13 deletions
diff --git a/op.c b/op.c
index 4b054480e6..eec6da5067 100644
--- a/op.c
+++ b/op.c
@@ -15255,16 +15255,32 @@ Perl_dup_warnings(pTHX_ char* warnings)
/*
=for apidoc rcpv_new
-Create a new shared memory refcounted string from the argument. If flags is set
-to RCPVf_USE_STRLEN then the len argument is ignored and set using strlen(pv).
-If the pv is NULL returns NULL. The newly created string will have a refcount
-of 1, and is suitable for passing into rcpv_copy() and rcpv_free(). To access
-the RCPV * from the returned value use the RCPVx() macro.
+Create a new shared memory refcounted string with the requested size, and
+with the requested initialization and a refcount of 1. The actual space
+allocated will be 1 byte more than requested and rcpv_new() will ensure that
+the extra byte is a null regardless of any flags settings.
-Note that rcpv_new() does NOT use a hash table or anything like that to dedupe
-inputs given the same text content. Each call with a non-null pv parameter
-will produce a distinct pointer with its own refcount regardless of the input
-content.
+If the RCPVf_NO_COPY flag is set then the pv argument will be
+ignored, otherwise the contents of the pv pointer will be copied into
+the new buffer or if it is NULL the function will do nothing and return NULL.
+
+If the RCPVf_USE_STRLEN flag is set then the len argument is ignored and
+recomputed using C<strlen(pv)>. It is an error to combine RCPVf_USE_STRLEN
+and RCPVf_NO_COPY at the same time.
+
+Under DEBUGGING rcpv_new() will assert() if it is asked to create a 0 length
+shared string unless the RCPVf_ALLOW_EMPTY flag is set.
+
+The return value from the function is suitable for passing into rcpv_copy() and
+rcpv_free(). To access the RCPV * from the returned value use the RCPVx() macro.
+The 'len' member of the RCPV struct stores the allocated length (including the
+extra byte), but the RCPV_LEN() macro returns the requested length (not
+including the extra byte).
+
+Note that rcpv_new() does NOT use a hash table or anything like that to
+dedupe inputs given the same text content. Each call with a non-null pv
+parameter will produce a distinct pointer with its own refcount regardless of
+the input content.
=cut
*/
@@ -15277,23 +15293,32 @@ Perl_rcpv_new(pTHX_ const char *pv, STRLEN len, U32 flags) {
PERL_UNUSED_CONTEXT;
+ /* Musn't use both at the same time */
+ assert((flags & (RCPVf_NO_COPY|RCPVf_USE_STRLEN))!=
+ (RCPVf_NO_COPY|RCPVf_USE_STRLEN));
+
if (!pv && (flags & RCPVf_NO_COPY) == 0)
return NULL;
if (flags & RCPVf_USE_STRLEN)
len = strlen(pv);
- rcpv = (RCPV *)PerlMemShared_malloc(sizeof(struct rcpv) + len + 1);
+ assert(len || (flags & RCPVf_ALLOW_EMPTY));
+
+ len++; /* add one for the null we will add to the end */
+
+ rcpv = (RCPV *)PerlMemShared_malloc(sizeof(struct rcpv) + len);
if (!rcpv)
croak_no_mem();
- rcpv->len = len;
+ rcpv->len = len; /* store length including null,
+ RCPV_LEN() subtracts 1 to account for this */
rcpv->refcount = 1;
if ((flags & RCPVf_NO_COPY) == 0) {
- (void)memcpy(rcpv->pv, pv, len);
- rcpv->pv[len]= '\0';
+ (void)memcpy(rcpv->pv, pv, len-1);
}
+ rcpv->pv[len-1]= '\0'; /* the last byte should always be null */
return rcpv->pv;
}
@@ -15324,6 +15349,7 @@ Perl_rcpv_free(pTHX_ char *pv) {
return NULL;
RCPV *rcpv = RCPVx(pv);
+ assert(rcpv->refcount);
assert(rcpv->len);
OP_REFCNT_LOCK;