Skip to content

Commit de20e15

Browse files
committed
Reject lone surrogates in string patterns
Signed-off-by: Christoph Knittel <ck@cca.io>
1 parent ede3c1e commit de20e15

3 files changed

Lines changed: 24 additions & 0 deletions

File tree

compiler/frontend/ast_utf8_string_interp.ml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,10 @@ let transform_pat (p : Parsetree.pattern) s delim : Parsetree.pattern =
319319
match Delim.parse_unprocessed false delim with
320320
| Js ->
321321
let js_str = Ast_utf8_string.transform p.ppat_loc s in
322+
(match String_literal.decode_js_escapes js_str with
323+
| Some _ -> ()
324+
| None ->
325+
Location.raise_errorf ~loc:p.ppat_loc "Invalid string escape sequence");
322326
{
323327
p with
324328
ppat_desc =

compiler/ml/string_literal.mli

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
val decode_js_escapes : string -> string option
2+
(** Decode the escape sequences in a JavaScript string-literal body into its
3+
semantic UTF-8 value. Returns [None] for malformed input or unpaired
4+
UTF-16 surrogates. *)
5+
16
val runtime_value : string -> string option -> string
27
(** Return the runtime value represented by a typed string constant.
38

tests/ounit_tests/ounit_string_literal_tests.ml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,18 @@ let assert_runtime_value ?(delim = Some "*j") ~encoded ~expected () =
77
let assert_same_runtime_value left right =
88
OUnit.assert_equal 0 (String_literal.compare left right)
99

10+
let assert_invalid_backquoted_pattern encoded =
11+
let template_attribute =
12+
(Location.mknoloc "res.template", Parsetree.PStr [])
13+
in
14+
let pattern =
15+
Ast_helper.Pat.constant ~attrs:[template_attribute]
16+
(Parsetree.Pconst_string (encoded, Some "js"))
17+
in
18+
match Ast_utf8_string_interp.transform_pat pattern encoded "js" with
19+
| _ -> OUnit.assert_failure "expected an invalid string escape"
20+
| exception Location.Error _ -> ()
21+
1022
let suites =
1123
__FILE__
1224
>::: [
@@ -55,6 +67,9 @@ let suites =
5567
{|\uD800\u0041|};
5668
{|\uDC00\uD800|};
5769
] );
70+
( "backquoted patterns reject lone surrogate escapes" >:: fun _ ->
71+
assert_invalid_backquoted_pattern {|\uD800|};
72+
assert_invalid_backquoted_pattern {|\uDC00|} );
5873
( "comparison uses runtime values" >:: fun _ ->
5974
assert_same_runtime_value ("a", Some "*j") ({|\x61|}, Some "*j");
6075
assert_same_runtime_value ("😀", None) ({|\u{1f600}|}, Some "*j");

0 commit comments

Comments
 (0)