]> git.kaiwu.me - nginx.git/commitdiff
Perl: fixed $r->print() zero copy with mutable scalars
authorDavid Carlier <devnexen@gmail.com>
Tue, 21 Jul 2026 03:35:57 +0000 (04:35 +0100)
committerVadimZhestikov <108960056+VadimZhestikov@users.noreply.github.com>
Fri, 24 Jul 2026 15:42:30 +0000 (08:42 -0700)
Since d9b7669666c8, the single-SV zero copy path in $r->print() no
longer required the SV to be read-only.  Reference counting introduced
by that change keeps the SV alive, but not its string buffer: modifying
a mutable scalar after $r->print() overwrites the buffer in place or
reallocates it, while nginx might still have it queued in r->out, since
small responses are postponed by ngx_http_write_filter().  This resulted
in corrupted responses, and in freed memory being sent to the client
when the scalar was grown.

The SV is now required to be read-only again.  Reference counting is
still needed here, as a read-only SV in an eval() might be freed with
the eval's op tree.

src/http/modules/perl/nginx.xs

index af854966132b5a5b0e8907d943062c2b0fcc97ec..efbab280a70731a0805a1ecee6f71c9fdf2501cf 100644 (file)
@@ -692,7 +692,7 @@ print(r, ...)
     if (items == 2) {
 
         /*
-         * do zero copy for prolate single SV:
+         * single read-only SV:
          *     $r->print("some text\n");
          */
 
@@ -702,7 +702,7 @@ print(r, ...)
             sv = SvRV(sv);
         }
 
-        if (SvPOK(sv)) {
+        if (SvREADONLY(sv) && SvPOK(sv)) {
 
             p = (u_char *) SvPV(sv, len);
 
@@ -728,7 +728,7 @@ print(r, ...)
             b->end = b->last;
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                           "$r->print: single SV: %z", len);
+                           "$r->print: read-only SV: %z", len);
 
             goto out;
         }