Commit ea67883a1ff for php.net

commit ea67883a1ff3528d233491e844549a04da975622
Author: Gina Peter Banyard <girgias@php.net>
Date:   Mon Apr 27 15:05:32 2026 +0100

    ext/phar: refactor phar_create_signature() to return a zend_string* (#21843)

    Instead of using out parameters.

diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 2ab799ab8c8..a81a62a188f 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -2995,17 +2995,12 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *phar, zen

 		switch(phar->sig_flags) {
 			default: {
-				char *digest = NULL;
-				size_t digest_len;
-
 				char *signature_error = NULL;
-				if (FAILURE == phar_create_signature(phar, newfile, &digest, &digest_len, &signature_error)) {
+				zend_string *signature = phar_create_signature(phar, newfile, &signature_error);
+				if (!signature) {
 					spprintf(error, 0, "phar error: unable to write signature: %s", signature_error);
 					efree(signature_error);

-					if (digest) {
-						efree(digest);
-					}
 					if (must_close_old_file) {
 						php_stream_close(oldfile);
 					}
@@ -3013,14 +3008,14 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_flush_ex(phar_archive_data *phar, zen
 					return EOF;
 				}

-				php_stream_write(newfile, digest, digest_len);
-				efree(digest);
+				php_stream_write(newfile, ZSTR_VAL(signature), ZSTR_LEN(signature));
 				if (phar->sig_flags == PHAR_SIG_OPENSSL ||
 					phar->sig_flags == PHAR_SIG_OPENSSL_SHA256 ||
 					phar->sig_flags == PHAR_SIG_OPENSSL_SHA512) {
-					phar_set_32(sig_buf, digest_len);
+					phar_set_32(sig_buf, ZSTR_LEN(signature));
 					php_stream_write(newfile, sig_buf, 4);
 				}
+				zend_string_release_ex(signature, false);
 				break;
 			}
 		}
diff --git a/ext/phar/phar_internal.h b/ext/phar/phar_internal.h
index 36fa2b54350..df4e58c7adb 100644
--- a/ext/phar/phar_internal.h
+++ b/ext/phar/phar_internal.h
@@ -413,7 +413,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(3) zend_result phar_open_executed_filename(char *ali
 zend_result phar_free_alias(const phar_archive_data *phar);
 zend_result phar_get_archive(phar_archive_data **archive, const char *fname, size_t fname_len, const char *alias, size_t alias_len, char **error);
 zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t sig_type, char *sig, size_t sig_len, const char *fname, char **signature, size_t *signature_len, char **error);
-ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error);
+ZEND_ATTRIBUTE_NONNULL zend_string* phar_create_signature(phar_archive_data *phar, php_stream *fp, char **error);

 /* utility functions */
 zend_string *phar_create_default_stub(const zend_string *php_index_str, const zend_string *web_index_str, char **error);
diff --git a/ext/phar/tar.c b/ext/phar/tar.c
index a7c02e35273..761246000dd 100644
--- a/ext/phar/tar.c
+++ b/ext/phar/tar.c
@@ -968,9 +968,8 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, ze
 	phar_entry_info entry = {0};
 	php_stream *oldfile, *newfile;
 	bool must_close_old_file = false;
-	size_t signature_length;
 	struct _phar_pass_tar_info pass;
-	char *buf, *signature, sigbuf[8];
+	char *buf, sigbuf[8];

 	entry.flags = PHAR_ENT_PERM_DEF_FILE;
 	entry.timestamp = time(NULL);
@@ -1168,7 +1167,8 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, ze
 	/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
 	if (!phar->is_data || phar->sig_flags) {
 		char *signature_error = NULL;
-		if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, &signature_error)) {
+		zend_string *signature = phar_create_signature(phar, newfile, &signature_error);
+		if (!signature) {
 			spprintf(error, 0, "phar error: unable to write signature to tar-based phar: %s", signature_error);
 			efree(signature_error);

@@ -1184,7 +1184,7 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, ze
 		if (entry.fp == NULL) {
 			*error = estrdup("phar error: unable to create temporary file");

-			efree(signature);
+			zend_string_release_ex(signature, false);
 			if (must_close_old_file) {
 				php_stream_close(oldfile);
 			}
@@ -1203,10 +1203,10 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, ze
 # define PHAR_SET_32(destination, source) memcpy(destination, &source, 4)
 #endif
 		PHAR_SET_32(sigbuf, phar->sig_flags);
-		PHAR_SET_32(sigbuf + 4, signature_length);
+		PHAR_SET_32(sigbuf + 4, ZSTR_LEN(signature));

-		if (8 != php_stream_write(entry.fp, sigbuf, 8) || signature_length != php_stream_write(entry.fp, signature, signature_length)) {
-			efree(signature);
+		if (8 != php_stream_write(entry.fp, sigbuf, 8) || ZSTR_LEN(signature) != php_stream_write(entry.fp, ZSTR_VAL(signature), ZSTR_LEN(signature))) {
+			zend_string_release_ex(signature, false);
 			spprintf(error, 0, "phar error: unable to write signature to tar-based phar %s", ZSTR_VAL(phar->fname));

 			if (must_close_old_file) {
@@ -1218,11 +1218,11 @@ ZEND_ATTRIBUTE_NONNULL_ARGS(1, 4) int phar_tar_flush(phar_archive_data *phar, ze

 		ALLOCA_FLAG(use_heap);
 		ZSTR_ALLOCA_INIT(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1, use_heap);
-		efree(signature);
-		entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
+		entry.uncompressed_filesize = entry.compressed_filesize = ZSTR_LEN(signature) + 8;
 		/* throw out return value and write the signature */
 		phar_tar_writeheaders_int(&entry, &pass);
 		ZSTR_ALLOCA_FREE(entry.filename, use_heap);
+		zend_string_release_ex(signature, false);

 		if (*error) {
 			if (must_close_old_file) {
diff --git a/ext/phar/util.c b/ext/phar/util.c
index 491a07c4dd2..ad7cdd6c9ae 100644
--- a/ext/phar/util.c
+++ b/ext/phar/util.c
@@ -1783,8 +1783,9 @@ zend_result phar_verify_signature(php_stream *fp, size_t end_of_phar, uint32_t s
 }
 /* }}} */

-ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar, php_stream *fp, char **signature, size_t *signature_length, char **error) /* {{{ */
+ZEND_ATTRIBUTE_NONNULL zend_string* phar_create_signature(phar_archive_data *phar, php_stream *fp, char **error) /* {{{ */
 {
+	zend_string *signature = NULL;
 	unsigned char buf[1024];
 	size_t sig_len;

@@ -1807,8 +1808,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 			}

 			PHP_SHA512Final(digest, &context);
-			*signature = estrndup((char *) digest, 64);
-			*signature_length = 64;
+			signature = zend_string_init((const char*)digest, 64, false);
 			break;
 		}
 		default:
@@ -1825,8 +1825,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 			}

 			PHP_SHA256Final(digest, &context);
-			*signature = estrndup((char *) digest, 32);
-			*signature_length = 32;
+			signature = zend_string_init((const char*)digest, 32, false);
 			break;
 		}
 		case PHAR_SIG_OPENSSL_SHA512:
@@ -1852,7 +1851,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar

 			if (in == NULL) {
 				spprintf(error, 0, "unable to write to phar \"%s\" with requested openssl signature", ZSTR_VAL(phar->fname));
-				return FAILURE;
+				return NULL;
 			}

 			key = PEM_read_bio_PrivateKey(in, NULL,NULL, "");
@@ -1860,14 +1859,14 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar

 			if (!key) {
 				*error = estrdup("unable to process private key");
-				return FAILURE;
+				return NULL;
 			}

 			md_ctx = EVP_MD_CTX_create();
 			if (md_ctx == NULL) {
 				EVP_PKEY_free(key);
 				spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", ZSTR_VAL(phar->fname));
-				return FAILURE;
+				return NULL;
 			}

 			siglen = EVP_PKEY_size(key);
@@ -1878,7 +1877,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 				EVP_MD_CTX_destroy(md_ctx);
 				efree(sigbuf);
 				spprintf(error, 0, "unable to initialize openssl signature for phar \"%s\"", ZSTR_VAL(phar->fname));
-				return FAILURE;
+				return NULL;
 			}

 			while ((sig_len = php_stream_read(fp, (char*)buf, sizeof(buf))) > 0) {
@@ -1887,7 +1886,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 					EVP_MD_CTX_destroy(md_ctx);
 					efree(sigbuf);
 					spprintf(error, 0, "unable to update the openssl signature for phar \"%s\"", ZSTR_VAL(phar->fname));
-					return FAILURE;
+					return NULL;
 				}
 			}

@@ -1896,12 +1895,14 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 				EVP_MD_CTX_destroy(md_ctx);
 				efree(sigbuf);
 				spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", ZSTR_VAL(phar->fname));
-				return FAILURE;
+				return NULL;
 			}

 			sigbuf[siglen] = '\0';
 			EVP_PKEY_free(key);
 			EVP_MD_CTX_destroy(md_ctx);
+			signature = zend_string_init((const char*)sigbuf, siglen, false);
+			efree(sigbuf);
 #else
 			size_t siglen;
 			sigbuf = NULL;
@@ -1910,11 +1911,11 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar

 			if (FAILURE == phar_call_openssl_signverify(true, fp, php_stream_tell(fp), PHAR_G(openssl_privatekey), PHAR_G(openssl_privatekey_len), (char **)&sigbuf, &siglen, phar->sig_flags)) {
 				spprintf(error, 0, "unable to write phar \"%s\" with requested openssl signature", ZSTR_VAL(phar->fname));
-				return FAILURE;
+				return NULL;
 			}
+			signature = zend_string_init((const char*)sigbuf, siglen, false);
+			efree(sigbuf);
 #endif
-			*signature = (char *) sigbuf;
-			*signature_length = siglen;
 		}
 		break;
 		case PHAR_SIG_SHA1: {
@@ -1928,8 +1929,7 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 			}

 			PHP_SHA1Final(digest, &context);
-			*signature = estrndup((char *) digest, 20);
-			*signature_length = 20;
+			signature = zend_string_init((const char*)digest, 20, false);
 			break;
 		}
 		case PHAR_SIG_MD5: {
@@ -1943,14 +1943,13 @@ ZEND_ATTRIBUTE_NONNULL zend_result phar_create_signature(phar_archive_data *phar
 			}

 			PHP_MD5Final(digest, &context);
-			*signature = estrndup((char *) digest, 16);
-			*signature_length = 16;
+			signature = zend_string_init((const char*)digest, 16, false);
 			break;
 		}
 	}

-	phar->sig_len = phar_hex_str((const char *)*signature, *signature_length, &phar->signature);
-	return SUCCESS;
+	phar->sig_len = phar_hex_str(ZSTR_VAL(signature), ZSTR_LEN(signature), &phar->signature);
+	return signature;
 }
 /* }}} */

diff --git a/ext/phar/zip.c b/ext/phar/zip.c
index 28e1a3d5641..da934a4c004 100644
--- a/ext/phar/zip.c
+++ b/ext/phar/zip.c
@@ -1148,8 +1148,7 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar
 {
 	/* add signature for executable tars or tars explicitly set with setSignatureAlgorithm */
 	if (!phar->is_data || phar->sig_flags) {
-		size_t signature_length;
-		char *signature, sigbuf[8];
+		char sigbuf[8];
 		phar_entry_info entry = {0};
 		php_stream *newfile;
 		zend_off_t tell;
@@ -1171,11 +1170,10 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar
 		}

 		char *signature_error = NULL;
-		if (FAILURE == phar_create_signature(phar, newfile, &signature, &signature_length, &signature_error)) {
-			if (signature_error) {
-				spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", signature_error);
-				efree(signature_error);
-			}
+		zend_string *signature = phar_create_signature(phar, newfile, &signature_error);
+		if (!signature) {
+			spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar: %s", signature_error);
+			efree(signature_error);

 			php_stream_close(newfile);
 			return FAILURE;
@@ -1185,17 +1183,17 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar
 		entry.fp_type = PHAR_MOD;
 		entry.is_modified = 1;
 		if (entry.fp == NULL) {
-			efree(signature);
+			zend_string_release_ex(signature, false);
 			spprintf(pass->error, 0, "phar error: unable to create temporary file for signature");
 			php_stream_close(newfile);
 			return FAILURE;
 		}

 		PHAR_SET_32(sigbuf, phar->sig_flags);
-		PHAR_SET_32(sigbuf + 4, signature_length);
+		PHAR_SET_32(sigbuf + 4, ZSTR_LEN(signature));

-		if (Z_UL(8) != php_stream_write(entry.fp, sigbuf, 8) || signature_length != php_stream_write(entry.fp, signature, signature_length)) {
-			efree(signature);
+		if (Z_UL(8) != php_stream_write(entry.fp, sigbuf, 8) || ZSTR_LEN(signature) != php_stream_write(entry.fp, ZSTR_VAL(signature), ZSTR_LEN(signature))) {
+			zend_string_release_ex(signature, false);
 			if (pass->error) {
 				spprintf(pass->error, 0, "phar error: unable to write signature to zip-based phar %s", ZSTR_VAL(phar->fname));
 			}
@@ -1206,13 +1204,13 @@ static zend_result phar_zip_applysignature(phar_archive_data *phar, struct _phar

 		ALLOCA_FLAG(use_heap);
 		ZSTR_ALLOCA_INIT(entry.filename, ".phar/signature.bin", sizeof(".phar/signature.bin")-1, use_heap);
-		efree(signature);
-		entry.uncompressed_filesize = entry.compressed_filesize = signature_length + 8;
+		entry.uncompressed_filesize = entry.compressed_filesize = ZSTR_LEN(signature) + 8;
 		entry.phar = phar;
 		/* throw out return value and write the signature */
 		phar_zip_changed_apply_int(&entry, (void *)pass);
 		ZSTR_ALLOCA_FREE(entry.filename, use_heap);
 		php_stream_close(newfile);
+		zend_string_release_ex(signature, false);

 		if (pass->error && *(pass->error)) {
 			/* error is set by writeheaders */