Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Function JIT: wrong result (null) from a string-scanning loop with strcspn() after a comment-start byte

Đang mở
#24,578 2 bình luận 0 reaction 0 người được giao Xem trên GitHub

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
54/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
php
Lĩnh vực
performance

Hướng nghiên cứu

Start by reducing the provided reproducer to isolate the strcspn() scanning loop under opcache.jit=function, then compare its result with tracing and disabled JIT modes. The issue names no PHP source files or tests, so first locate the function JIT implementation and its tests for string scanning. Done means both inputs return their full expected strings in function JIT mode, with the other modes still behaving correctly.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Bug Category: JIT Extension: opcache Status: Verified
Description

With opcache.jit=function, the static method Repro::interpolate() below returns null for two inputs that it handles correctly with opcache.jit=tracing and opcache.jit=disable. The two inputs contain a byte that may start a comment (- or /) but no placeholder, so the scanner should copy the whole string.

The following code:

<?php
declare(strict_types=1);

final class Repro {
    public static function skipComment(string $sql, int $position): int {
        $byte = $sql[$position]; $next = $sql[$position + 1] ?? '';
        if ($byte === '/' && $next === '*') { $end = strpos($sql, '*/', $position + 2); return $end === false ? strlen($sql) : $end + 2; }
        $dashes = $byte === '-' && $next === '-' && strspn($sql[$position + 2] ?? "\n", " \t\r\n") === 1;
        if ($byte !== '#' && !$dashes) return $position; $end = strpos($sql, "\n", $position);
        return $end === false ? strlen($sql) : $end + 1; }
    public static function skipQuoted(string $sql, int $position): int {
        $quote = $sql[$position]; $length = strlen($sql); $stops = $quote === '`' ? '`' : $quote . '\\'; $position++;
        while ($position < $length) { $position += strcspn($sql, $stops, $position); if ($position >= $length) break;
            if ($sql[$position] === '\\') $position += 2; elseif (($sql[$position + 1] ?? '') === $quote) $position += 2; else return $position + 1; }
        return $length; }
    public static function literal(mixed $value): ?string {
        if ($value === null) return 'NULL'; if (is_bool($value)) return $value ? '1' : '0'; if (is_int($value)) return (string) $value;
        if (is_float($value)) return is_finite($value) ? var_export($value, true) : null; if (!is_string($value)) return null;
        return $value === '' ? "''" : "'" . addslashes($value) . "'"; }
    public static function interpolate(string $sql, array $params): ?string {
        if (count($params) > 65535 || !array_is_list($params)) return null;
        $length = strlen($sql); $count = count($params); $text = ''; $used = 0; $copied = 0; $position = 0;
        while ($position < $length) { $position += strcspn($sql, "?'\"`#-/", $position); if ($position >= $length) break; $byte = $sql[$position];
            if ($byte === '?') { $literal = $used < $count ? self::literal(value: $params[$used]) : null; if ($literal === null) return null;
                $text .= substr($sql, $copied, $position - $copied) . $literal; $used++; $position++; $copied = $position;
            } elseif ($byte === "'" || $byte === '"' || $byte === '`') $position = self::skipQuoted(sql: $sql, position: $position);
            else { $after = self::skipComment(sql: $sql, position: $position); $position = $after === $position ? $position + 1 : $after; }
        }
        return $used === $count ? $text . substr($sql, $copied) : null;
    }
}
echo json_encode([Repro::interpolate('SELECT ? AS v', [3]), Repro::interpolate('SELECT 5 -', []), Repro::interpolate('SELECT 5 / 2', [])]), "\n";

Run with:

php -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit=function repro.php

Resulted in this output:

["SELECT 3 AS v",null,null]

But I expected this output instead (what opcache.jit=tracing and opcache.jit=disable print):

["SELECT 3 AS v","SELECT 5 -","SELECT 5 \/ 2"]

Reproduces on PHP 8.5.12 and on master (8.7.0-dev, da7da45a44eb07ac999f5183b232a40d5f857131). The script is a reduced version of a SQL placeholder interpolator.

PHP Version

PHP 8.5.12 (cli) (NTS), built from source; also master 8.7.0-dev at da7da45a44eb07ac999f5183b232a40d5f857131

Operating System

Amazon Linux 2023, aarch64 (container)

Ngôn ngữ chính
C
Star
40.7k
Fork
8.3k
Merge trung bình
2 ngày 20 giờ
Pull request đã merge (30 ngày)
147

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. 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.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của php/php-src

Tất cả issue của php/php-src

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.