Skip to content

Commit e4ec212

Browse files
committed
[Bug #20990] Reject escaped multibyte char with control/meta prefix
1 parent 0ccc765 commit e4ec212

File tree

4 files changed

+51
-1
lines changed

4 files changed

+51
-1
lines changed

parse.y

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8231,6 +8231,10 @@ read_escape(struct parser_params *p, int flags, const char *begin)
82318231
return '\0';
82328232

82338233
default:
8234+
if (!ISASCII(c)) {
8235+
tokskip_mbchar(p);
8236+
goto eof;
8237+
}
82348238
return c;
82358239
}
82368240
}

prism/prism.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9657,7 +9657,8 @@ escape_read_warn(pm_parser_t *parser, uint8_t flags, uint8_t flag, const char *t
96579657
*/
96589658
static void
96599659
escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expression_buffer, uint8_t flags) {
9660-
switch (peek(parser)) {
9660+
uint8_t peeked = peek(parser);
9661+
switch (peeked) {
96619662
case '\\': {
96629663
parser->current.end++;
96639664
escape_write_byte(parser, buffer, regular_expression_buffer, flags, escape_byte('\\', flags));
@@ -10054,6 +10055,11 @@ escape_read(pm_parser_t *parser, pm_buffer_t *buffer, pm_buffer_t *regular_expre
1005410055
}
1005510056
/* fallthrough */
1005610057
default: {
10058+
if ((flags & (PM_ESCAPE_FLAG_CONTROL | PM_ESCAPE_FLAG_META)) && !char_is_ascii_printable(peeked)) {
10059+
size_t width = parser->encoding->char_width(parser->current.end, parser->end - parser->current.end);
10060+
pm_parser_err(parser, parser->current.start, parser->current.end + width, PM_ERR_ESCAPE_INVALID_META);
10061+
return;
10062+
}
1005710063
if (parser->current.end < parser->end) {
1005810064
escape_write_escape_encoded(parser, buffer, regular_expression_buffer, flags);
1005910065
} else {

test/ripper/test_lexer.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,15 @@ def test_invalid_escape_ctrl_mbchar
355355
]
356356

357357
assert_lexer(expected, code)
358+
359+
code = %["\\C-\\\u{3042}"]
360+
expected = [
361+
[[1, 0], :on_tstring_beg, '"', state(:EXPR_BEG)],
362+
[[1, 1], :on_tstring_content, "\\C-\\\u{3042}", state(:EXPR_BEG)],
363+
[[1, 8], :on_tstring_end, '"', state(:EXPR_END)],
364+
]
365+
366+
assert_lexer(expected, code)
358367
end
359368

360369
def test_invalid_escape_meta_mbchar
@@ -366,6 +375,15 @@ def test_invalid_escape_meta_mbchar
366375
]
367376

368377
assert_lexer(expected, code)
378+
379+
code = %["\\M-\\\u{3042}"]
380+
expected = [
381+
[[1, 0], :on_tstring_beg, '"', state(:EXPR_BEG)],
382+
[[1, 1], :on_tstring_content, "\\M-\\\u{3042}", state(:EXPR_BEG)],
383+
[[1, 8], :on_tstring_end, '"', state(:EXPR_END)],
384+
]
385+
386+
assert_lexer(expected, code)
369387
end
370388

371389
def test_invalid_escape_meta_ctrl_mbchar
@@ -377,6 +395,15 @@ def test_invalid_escape_meta_ctrl_mbchar
377395
]
378396

379397
assert_lexer(expected, code)
398+
399+
code = %["\\M-\\C-\\\u{3042}"]
400+
expected = [
401+
[[1, 0], :on_tstring_beg, '"', state(:EXPR_BEG)],
402+
[[1, 1], :on_tstring_content, "\\M-\\C-\\\u{3042}", state(:EXPR_BEG)],
403+
[[1, 11], :on_tstring_end, '"', state(:EXPR_END)],
404+
]
405+
406+
assert_lexer(expected, code)
380407
end
381408

382409
def test_invalid_escape_ctrl_meta_mbchar
@@ -388,6 +415,15 @@ def test_invalid_escape_ctrl_meta_mbchar
388415
]
389416

390417
assert_lexer(expected, code)
418+
419+
code = %["\\C-\\M-\\\u{3042}"]
420+
expected = [
421+
[[1, 0], :on_tstring_beg, '"', state(:EXPR_BEG)],
422+
[[1, 1], :on_tstring_content, "\\C-\\M-\\\u{3042}", state(:EXPR_BEG)],
423+
[[1, 11], :on_tstring_end, '"', state(:EXPR_END)],
424+
]
425+
426+
assert_lexer(expected, code)
391427
end
392428

393429
def test_invalid_escape_string

test/ruby/test_literal.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ def test_string
9797
assert_equal "ab", eval("?a 'b'")
9898
assert_equal "a\nb", eval("<<A 'b'\na\nA")
9999

100+
assert_raise(SyntaxError) {eval('"\C-' "\u3042" '"')}
101+
assert_raise(SyntaxError) {eval('"\C-\\' "\u3042" '"')}
102+
assert_raise(SyntaxError) {eval('"\M-' "\u3042" '"')}
103+
assert_raise(SyntaxError) {eval('"\M-\\' "\u3042" '"')}
100104
ensure
101105
$VERBOSE = verbose_bak
102106
end

0 commit comments

Comments
 (0)