Unparsed heredocs during string and list interpolation error recovery strand PM_LEX_HEREDOC

Đang mở
#4,362 0 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
48/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c, ruby
Lĩnh vực
backend, compilers, testing

Hướng nghiên cứu

Start with the error-recovery paths in parse_string_part, parse_interpolated_symbol_array, and parse_interpolated_string_array, where the issue says PM_TOKEN_HEREDOC_START is sent to parser_lex instead of parse_heredoc. Trace how PM_LEX_EMBEXPR and PM_LEX_HEREDOC are managed on parser->lex_modes, then reproduce the supplied input and check that parsed node locations stay within the source length. Add regression coverage for the interpolation forms listed in the issue.

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

Mô tả

Fuzzing find on bdbd482dc.

When parse_statements(parser, PM_CONTEXT_EMBEXPR, ...) inside an interpolated string, regexp, backtick, %W[...] string array, or %I[...] symbol array stops early via context_recoverable (because it encounters a closing token belonging to an outer enclosing context, such as )), PM_LEX_EMBEXPR remains active on parser->lex_modes. The enclosing string/list loop then calls parse_string_part (or the token switch in parse_interpolated_symbol_array / parse_interpolated_string_array) to drain the remaining tokens of the unclosed interpolation.

When one of those remaining tokens is PM_TOKEN_HEREDOC_START, parse_string_part, parse_interpolated_symbol_array, and parse_interpolated_string_array hit their default: error-recovery branch and call parser_lex(parser) instead of parse_heredoc. This strands PM_LEX_HEREDOC on parser->lex_modes, which later rewinds parser->next_start backwards in the middle of parsing a subsequent construct and underflows uint32_t location.length.

Reproduction

(Interactive simulation in Prism Loupe)

#include "prism.h"
#include <inttypes.h>
#include <stdio.h>
#include <string.h>

static pm_visit_result_t
check_bounds(const pm_node_t *node, void *data) {
    size_t source_len = *(const size_t *) data;
    uint64_t end = (uint64_t) node->location.start + (uint64_t) node->location.length;

    if (end > source_len) {
        printf(
            "%-16s start=%" PRIu32 " length=%" PRIu32 " (0x%08" PRIx32 ") end=%" PRIu64 " > source_len=%zu\n",
            pm_node_type(node->type),
            node->location.start,
            node->location.length,
            node->location.length,
            end,
            source_len
        );
    }

    return PM_VISIT_DESCEND;
}

int main(void) {
    const char *src = "->x:\"#{)<<\"\n#{f\n\"#{a}\"C{";
    size_t len = strlen(src);

    pm_arena_t *arena = pm_arena_new();
    pm_parser_t *parser = pm_parser_new(arena, (const uint8_t *) src, len, NULL);
    pm_node_t *root = pm_parse(parser);

    pm_visit_node(root, check_bounds, &len);

    pm_parser_free(parser);
    pm_arena_free(arena);
    return 0;
}

Building and running against libprism.a:

cc -Iinclude check.c build/libprism.a -o check && ./check

Output on the 24-byte input (0..24):

PM_CALL_NODE     start=22 length=4294967286 (0xfffffff6) end=4294967308 > source_len=24
PM_BLOCK_NODE    start=23 length=4294967285 (0xfffffff5) end=4294967308 > source_len=24
Ngôn ngữ chính
C
Star
1k
Fork
202
Merge trung bình
5 giờ 55 phút
Pull request đã merge (30 ngày)
85

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 ruby/prism

Tất cả issue của ruby/prism

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.