You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Commit edae243 attempted to fix a leak and double free, but didn't
properly understand what was going on, causing a reference count mistake
and subsequent segfault in this case.
The first mistake of that commit is that the reference count should've
been increased because we're reusing a phar object. The error handling
path should've gotten changed instead to undo this refcount increase
instead of not refcounting at all (root cause of this bug).
The second mistake is that the alias isn't supposed to be transferred or
whatever, that just doesn't make sense. The reason the test
bug69958.phpt originally leaked is because in the non-reuse case we
borrowed the alias and otherwise we own the alias. If we own the alias
the alias information shouldn't get deleted anyway as that would desync
the alias map.
Fixing these will reveal a third issue in which the alias memory is not
always properly in sync with the persistence-ness of the phar, fix this
as well.
ClosesphpGH-17150.
if (PHAR_G(manifest_cached) &&NULL!= (pphar=zend_hash_str_find_ptr(&cached_phars, newpath, phar->fname_len))) {
2115
-
efree(oldpath);
2116
2115
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, new phar name is in phar.cache_list", phar->fname);
2117
-
returnNULL;
2116
+
goto err_oldpath;
2118
2117
}
2119
2118
2120
2119
if (NULL!= (pphar=zend_hash_str_find_ptr(&(PHAR_G(phar_fname_map)), newpath, phar->fname_len))) {
/* FIX: GH-10755 Double-free issue caught by ASAN check */
2130
-
pphar->alias=phar->alias; /* Transfer alias to pphar to */
2131
-
phar->alias=NULL; /* avoid being free'd twice */
2128
+
/* The alias is not owned by the phar, so set it to NULL to avoid freeing it. */
2129
+
phar->alias=NULL;
2132
2130
phar_destroy_phar_data(phar);
2133
2131
*sphar=NULL;
2134
2132
phar=pphar;
2133
+
/* NOTE: this phar is now reused, so the refcount must be increased. */
2134
+
phar->refcount++;
2135
2135
newpath=oldpath;
2136
2136
goto its_ok;
2137
2137
}
2138
2138
}
2139
2139
2140
-
efree(oldpath);
2141
2140
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "Unable to add newly converted phar \"%s\" to the list of phars, a phar with that name already exists", phar->fname);
2142
-
returnNULL;
2141
+
goto err_oldpath;
2143
2142
}
2144
2143
its_ok:
2145
2144
if (SUCCESS==php_stream_stat_path(newpath, &ssb)) {
2146
2145
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" exists and must be unlinked prior to conversion", newpath);
2147
-
efree(oldpath);
2148
-
returnNULL;
2146
+
goto err_reused_oldpath;
2149
2147
}
2150
2148
if (!phar->is_data) {
2151
2149
if (SUCCESS!=phar_detect_phar_fname_ext(newpath, phar->fname_len, (constchar**) &(phar->ext), &ext_len, 1, 1, 1)) {
2152
-
efree(oldpath);
2153
2150
zend_throw_exception_ex(spl_ce_BadMethodCallException, 0, "phar \"%s\" has invalid extension %s", phar->fname, ext);
2154
-
returnNULL;
2151
+
goto err_reused_oldpath;
2155
2152
}
2156
2153
phar->ext_len=ext_len;
2157
2154
2158
-
if (phar->alias) {
2155
+
/* If we are reusing a phar, then the aliases should be already set up correctly,
2156
+
* and so we should not clear out the alias information.
2157
+
* This would also leak memory because, unlike the non-reuse path, we actually own the alias memory. */
0 commit comments