`imagecopyresampled()` silently copies nothing when given negative source width/height (regression in 8.6 after GD 2.4 sync)
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 48/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Lĩnh vực
- computer-graphics
Hướng nghiên cứu
Reproduce the reported flips with the supplied PHP script, then read PHP_FUNCTION(imagecopyresampled) in ext/gd/gd.c and gdImageClipCopyResized() in ext/gd/libgd/gd_intern.h. The issue leaves open whether negative dimensions should remain supported or be deprecated and rejected, so clarify that expected behavior before changing code. Done means the chosen behavior is covered by regression tests and no longer silently leaves the destination blank.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Description
The following code:
<?php
$w = 100;
$h = 100;
$src = imagecreatetruecolor($w, $h);
imagefilledrectangle($src, 0, 0, $w - 1, $h - 1, imagecolorallocate($src, 0, 0, 255)); // blue
imagefilledrectangle($src, 0, 0, 9, 9, imagecolorallocate($src, 255, 0, 0)); // red top-left corner
$cases = [
'horizontal flip (negative src_width)' => [$w - 1, 0, -$w, $h],
'vertical flip (negative src_height)' => [0, $h - 1, $w, -$h],
'both (negative src_width/src_height)' => [$w - 1, $h - 1, -$w, -$h],
];
foreach ($cases as $label => [$src_x, $src_y, $src_w, $src_h]) {
$dst = imagecreatetruecolor($w, $h);
$ret = imagecopyresampled($dst, $src, 0, 0, $src_x, $src_y, $w, $h, $src_w, $src_h);
printf(
"%s: return=%s top-left=%06x top-right=%06x bottom-left=%06x bottom-right=%06x\n",
$label,
var_export($ret, true),
imagecolorat($dst, 0, 0),
imagecolorat($dst, $w - 1, 0),
imagecolorat($dst, 0, $h - 1),
imagecolorat($dst, $w - 1, $h - 1)
);
}
Resulted in this output:
horizontal flip (negative src_width): return=true top-left=000000 top-right=000000 bottom-left=000000 bottom-right=000000
vertical flip (negative src_height): return=true top-left=000000 top-right=000000 bottom-left=000000 bottom-right=000000
both (negative src_width/src_height): return=true top-left=000000 top-right=000000 bottom-left=000000 bottom-right=000000
But I expected this output instead:
horizontal flip (negative src_width): return=true top-left=0000ff top-right=ff0000 bottom-left=0000ff bottom-right=0000ff
vertical flip (negative src_height): return=true top-left=0000ff top-right=0000ff bottom-left=ff0000 bottom-right=0000ff
both (negative src_width/src_height): return=true top-left=0000ff top-right=0000ff bottom-left=0000ff bottom-right=ff0000
Additional context
The output above is from PHP 8.6.0RC4 (gd_info()['GD Version']: bundled (2.4.0 compatible)). The expected output is the actual output of the same script on PHP 8.5.12 (bundled (2.1.0 compatible)).
Since the bundled libgd was synced to 2.4 (GH-22532), imagecopyresampled() no longer copies anything when $src_width or $src_height is negative. It still returns true, so the destination image is left as the blank (black) canvas from imagecreatetruecolor(), and the caller gets no warning or error. Calls with positive dimensions are unaffected: copying the same image with 0, 0, 100, 100 as the source area produces identical output on 8.5 and 8.6.
Passing a negative source width/height with $src_x/$src_y set to the opposite edge "has worked as a way to mirror/flip an image in several PHP releases prior to 8.6 (verified on 7.4, 8.0, 8.4, and 8.5). It was widely used before imageflip() was added in PHP 5.5 and is still in use today.
For example, WordPress core's GD image editor uses it to implement flipping (WP_Image_Editor_GD::flip()). On PHP 8.6 every flipped image comes out solid black. WordPress has flipped images this way since late 2009 and was first shipped in WordPress 2.9, which defined a minimum PHP version of 4.3.
A related report was created for WordPress' own tracking purposes on Trac.
Possible Cause
This appears to be caused by the new gdImageClipCopyResized() helper in ext/gd/libgd/gd_intern.h, which gdImageCopyResampled() now calls before copying any pixels:
if (*dstW <= 0 || *dstH <= 0 || *srcW <= 0 || *srcH <= 0) {
return 0;
}
gdImageCopyResampled() returns void, so the early return can't be detected. PHP_FUNCTION(imagecopyresampled) in ext/gd/gd.c does no validation of its own and unconditionally returns true. By contrast, PHP_FUNCTION(imagecopyresized) already throws a ValueError ("must be greater than 0") for non-positive widths/heights.
This doesn't appear in UPGRADING, and I couldn't find an existing report.
The same helper is on libgd's master branch (unreleased), so builds against an external libgd 2.3.x do not appear to be affected. Only the bundled GD in 8.6 is. However, once libgd 2.4 is released, --with-external-gd builds will be affected too, so it's likely worth fixing upstream in libgd/libgd as well.
Suggested Fix
Ideally, negative source dimensions would keep working as before, given how much existing code relies on them.
If dropping support for negative dimensions is intentional, I'd suggest doing it through the usual deprecation path rather than as a silent behavior change in 8.6:
- Restore the previous behavior in 8.6, and emit an
E_DEPRECATEDdiagnostic when a negative$src_width/$src_heightis passed, so existing code keeps working while affected projects get a clear signal to migrate (for example, toimageflip()). - In a future release, remove support and throw a
ValueErrormatchingimagecopyresized().
If the new behavior is kept as is, it should at least raise a ValueError instead of silently returning true, and be documented in UPGRADING.
PHP Version
PHP 8.6.0RC4 (cli) (built: Oct 28 2026 01:20:17) (ZTS)
Copyright © The PHP Group and Contributors
Built by https://github.com/docker-library/php
Zend Engine v4.6.0RC4, Copyright © Zend by Perforce
with Zend OPcache v8.6.0RC4, Copyright ©, by Zend by Perforce
Operating System
No response
- Ngôn ngữ chính
- C
- Star
- 41.8k
- Fork
- 8.5k
- Merge trung bình
- 2 ngày 13 giờ
- Pull request đã merge (30 ngày)
- 145
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của php/php-src
-
ext/openssl: 8.2.31+/8.3.31+ fail to build against OpenSSL 1.0.2 (ASN1_STRING_get0_data in xp_ssl.c)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 79/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
php/php-src#25397 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
SNMP accepts malformed remote portsCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 62/100
php/php-src#25137 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Bug Status: Needs Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 64/100
Maintainer thường phản hồi trong vòng 1 ngày
-
quoted_printable_encode() produces lines longer than 76 characters for bytes 0xF5 to 0xFFCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
Maintainer thường phản hồi trong vòng 1 ngày
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
-
not for AI lovers
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
OSGeo/gdal#15515 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Template: Bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 83/100
betaflight/betaflight#16014 ·
Maintainer thường phản hồi trong vòng 3 ngày
-
Bug: [BMC] show techsupport logs ERR "BMC instance is not available" on switch host with a SONiC BMCĐang mởBug :bug:
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
sonic-net/sonic-buildimage#30701 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area:tooling bug platform:android
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
maplibre/maplibre-native-ffi#1791 ·
Maintainer thường phản hồi trong vòng 1 ngày