Skip to content

Commit 9f10661

Browse files
committed
disallow unbalanced bidirectional formatting in strings and comments
1 parent 79b0226 commit 9f10661

File tree

2 files changed

+71
-42
lines changed

2 files changed

+71
-42
lines changed

src/julia-parser.scm

Lines changed: 62 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,6 @@
221221

222222
(define (newline? c) (eqv? c #\newline))
223223

224-
(define (skip-to-eol port)
225-
(let ((c (peek-char port)))
226-
(cond ((eof-object? c) c)
227-
((eqv? c #\newline) c)
228-
(else (read-char port)
229-
(skip-to-eol port)))))
230-
231224
(define (op-or-sufchar? c) (or (op-suffix-char? c) (opchar? c)))
232225

233226
(define (read-operator port c0 (postfix? #f))
@@ -495,33 +488,56 @@
495488
(pair? (cadr t)) (eq? (car (cadr t)) 'core)
496489
(memq (cadadr t) '(@int128_str @uint128_str @big_str))))
497490

491+
(define (make-bidi-state) '(0 . 0))
492+
493+
(define (update-bidi-state st c)
494+
(case c
495+
((#\U202A #\U202B #\U202D #\U202E) (cons (+ (car st) 1) (cdr st))) ;; LRE RLE LRO RLO
496+
((#\U2066 #\U2067 #\U2068) (cons (car st) (+ (cdr st) 1))) ;; LRI RLI FSI
497+
((#\U202C) (cons (- (car st) 1) (cdr st))) ;; PDF
498+
((#\U2069) (cons (car st) (- (cdr st) 1))) ;; PDI
499+
((#\newline) '(0 . 0))
500+
(else st)))
501+
502+
(define (bidi-state-terminated? st) (equal? st '(0 . 0)))
503+
504+
(define (skip-line-comment port)
505+
(let ((c (peek-char port)))
506+
(cond ((eof-object? c) c)
507+
((eqv? c #\newline) c)
508+
(else (read-char port)
509+
(skip-line-comment port)))))
510+
511+
(define (skip-multiline-comment port count bds)
512+
(let ((c (read-char port)))
513+
(if (eof-object? c)
514+
(error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl
515+
(if (eqv? c #\=)
516+
(let ((c (peek-char port)))
517+
(if (eqv? c #\#)
518+
(begin
519+
(read-char port)
520+
(if (> count 1)
521+
(skip-multiline-comment port (- count 1) bds)
522+
(if (not (bidi-state-terminated? bds))
523+
(error "unbalanced bidirectional formatting in comment"))))
524+
(skip-multiline-comment port count (update-bidi-state bds c))))
525+
(if (eqv? c #\#)
526+
(skip-multiline-comment port
527+
(if (eqv? (peek-char port) #\=)
528+
(begin (read-char port)
529+
(+ count 1))
530+
count)
531+
bds)
532+
(skip-multiline-comment port count (update-bidi-state bds c)))))))
533+
498534
;; skip to end of comment, starting at #: either #...<eol> or #= .... =#.
499535
(define (skip-comment port)
500-
(define (skip-multiline-comment port count)
501-
(let ((c (read-char port)))
502-
(if (eof-object? c)
503-
(error "incomplete: unterminated multi-line comment #= ... =#") ; NOTE: changing this may affect code in base/client.jl
504-
(begin (if (eqv? c #\=)
505-
(let ((c (peek-char port)))
506-
(if (eqv? c #\#)
507-
(begin
508-
(read-char port)
509-
(if (> count 1)
510-
(skip-multiline-comment port (- count 1))))
511-
(skip-multiline-comment port count)))
512-
(if (eqv? c #\#)
513-
(skip-multiline-comment port
514-
(if (eqv? (peek-char port) #\=)
515-
(begin (read-char port)
516-
(+ count 1))
517-
count))
518-
(skip-multiline-comment port count)))))))
519-
520536
(read-char port) ; read # that was already peeked
521537
(if (eqv? (peek-char port) #\=)
522538
(begin (read-char port) ; read initial =
523-
(skip-multiline-comment port 1))
524-
(skip-to-eol port)))
539+
(skip-multiline-comment port 1 (make-bidi-state)))
540+
(skip-line-comment port)))
525541

526542
(define (skip-ws-and-comments port)
527543
(skip-ws port #t)
@@ -2354,24 +2370,28 @@
23542370
(let loop ((c (read-char p))
23552371
(b (open-output-string))
23562372
(e ())
2357-
(quotes 0))
2373+
(quotes 0)
2374+
(bds (make-bidi-state)))
23582375
(cond
23592376
((eqv? c delim)
23602377
(if (< quotes n)
2361-
(loop (read-char p) b e (+ quotes 1))
2362-
(reverse (cons (io.tostring! b) e))))
2378+
(loop (read-char p) b e (+ quotes 1) bds)
2379+
(begin
2380+
(if (not (bidi-state-terminated? bds))
2381+
(error "unbalanced bidirectional formatting in string literal"))
2382+
(reverse (cons (io.tostring! b) e)))))
23632383

23642384
((= quotes 1)
23652385
(if (not raw) (write-char #\\ b))
23662386
(write-char delim b)
2367-
(loop c b e 0))
2387+
(loop c b e 0 (update-bidi-state bds c)))
23682388

23692389
((= quotes 2)
23702390
(if (not raw) (write-char #\\ b))
23712391
(write-char delim b)
23722392
(if (not raw) (write-char #\\ b))
23732393
(write-char delim b)
2374-
(loop c b e 0))
2394+
(loop c b e 0 (update-bidi-state bds c)))
23752395

23762396
((eqv? c #\\)
23772397
(if raw
@@ -2384,19 +2404,19 @@
23842404
(io.write b (string.rep "\\" (div count 2)))
23852405
(if (odd? count)
23862406
(begin (write-char delim b)
2387-
(loop (read-char p) b e 0))
2388-
(loop nxch b e 0)))
2407+
(loop (read-char p) b e 0 bds))
2408+
(loop nxch b e 0 bds)))
23892409
(else
23902410
(io.write b (string.rep "\\" count))
23912411
(write-char nxch b)
2392-
(loop (read-char p) b e 0))))
2412+
(loop (read-char p) b e 0 (update-bidi-state bds nxch)))))
23932413
(let ((nxch (not-eof-for delim (read-char p))))
23942414
(write-char #\\ b)
23952415
(if (eqv? nxch #\return)
2396-
(loop nxch b e 0)
2416+
(loop nxch b e 0 bds)
23972417
(begin
23982418
(write-char nxch b)
2399-
(loop (read-char p) b e 0))))))
2419+
(loop (read-char p) b e 0 (update-bidi-state bds nxch)))))))
24002420

24012421
((and (eqv? c #\$) (not raw))
24022422
(let* ((ex (parse-interpolate s))
@@ -2406,19 +2426,19 @@
24062426
(loop (read-char p)
24072427
(open-output-string)
24082428
(list* ex (io.tostring! b) e)
2409-
0)))
2429+
0 bds)))
24102430

24112431
; convert literal \r and \r\n in strings to \n (issue #11988)
24122432
((eqv? c #\return) ; \r
24132433
(begin
24142434
(if (eqv? (peek-char p) #\linefeed) ; \r\n
24152435
(read-char p))
24162436
(write-char #\newline b)
2417-
(loop (read-char p) b e 0)))
2437+
(loop (read-char p) b e 0 bds)))
24182438

24192439
(else
24202440
(write-char (not-eof-for delim c) b)
2421-
(loop (read-char p) b e 0)))))
2441+
(loop (read-char p) b e 0 (update-bidi-state bds c))))))
24222442

24232443
(define (not-eof-1 c)
24242444
(if (eof-object? c)

test/syntax.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,3 +3060,12 @@ end
30603060
@test err == 5 + 6
30613061
@test x == 1
30623062
end
3063+
3064+
@test_throws ParseError Meta.parse("""
3065+
function checkUserAccess(u::User)
3066+
if u.accessLevel != "user\u202e \u2066# users are not allowed\u2069\u2066"
3067+
return true
3068+
end
3069+
return false
3070+
end
3071+
""")

0 commit comments

Comments
 (0)