From fa9637574255831cf75cc1aad22fe7425878f476 Mon Sep 17 00:00:00 2001 From: Stephen Chang Date: Tue, 19 Jan 2016 16:37:07 -0500 Subject: [PATCH] fix in-vector segfault; document corner cases closes #15227 --- .../scribblings/reference/sequences.scrbl | 18 ++++++++++++--- pkgs/racket-test-core/tests/racket/for.rktl | 23 +++++++++++++++++++ racket/collects/racket/private/for.rkt | 9 ++++---- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/pkgs/racket-doc/scribblings/reference/sequences.scrbl b/pkgs/racket-doc/scribblings/reference/sequences.scrbl index d1353b172e..321450ec6d 100644 --- a/pkgs/racket-doc/scribblings/reference/sequences.scrbl +++ b/pkgs/racket-doc/scribblings/reference/sequences.scrbl @@ -232,9 +232,21 @@ each element in the sequence. greater or equal to @racket[end] if @racket[step] is non-negative, or less or equal to @racket[end] if @racket[step] is negative. - If @racket[start] is not a valid index, or @racket[stop] is not in - [-1, @racket[(vector-length vec)]] then the - @exnraise[exn:fail:contract]. If @racket[start] is less than + If @racket[start] is not a valid index, then the + @exnraise[exn:fail:contract], except when @racket[start], @racket[stop], and + @racket[(vector-length vec)] are equal, in which case the result is an + empty sequence. + + @examples[#:eval sequence-evaluator + (for ([x (in-vector (vector 1) 1)]) x) + (eval:error (for ([x (in-vector (vector 1) 2)]) x)) + (for ([x (in-vector (vector) 0 0)]) x) + (for ([x (in-vector (vector 1) 1 1)]) x)] + + If @racket[stop] is not in [-1, @racket[(vector-length vec)]], + then the @exnraise[exn:fail:contract]. + + If @racket[start] is less than @racket[stop] and @racket[step] is negative, then the @exnraise[exn:fail:contract:mismatch]. Similarly, if @racket[start] is more than @racket[stop] and @racket[step] is positive, then the diff --git a/pkgs/racket-test-core/tests/racket/for.rktl b/pkgs/racket-test-core/tests/racket/for.rktl index ffd8d4c455..9b537e7c90 100644 --- a/pkgs/racket-test-core/tests/racket/for.rktl +++ b/pkgs/racket-test-core/tests/racket/for.rktl @@ -369,6 +369,7 @@ (test '() 'in-empty-vector (let ([v (in-vector '#())]) (for/list ([e v]) e))) (test '() 'in-empty-vector (let ([v (in-vector '#() 0)]) (for/list ([e v]) e))) (test '() 'in-empty-vector (let ([v (in-vector '#() 0 0)]) (for/list ([e v]) e))) +(test '() 'in-empty-vector (let ([v (in-vector '#(1) 1)]) (for/list ([e v]) e))) (test '() 'in-empty-vector (let ([v (in-vector '#(1) 1 1)]) (for/list ([e v]) e))) (test '() 'in-empty-vector (let ([v (in-vector '#(1) 0 0)]) (for/list ([e v]) e))) (test '(1) 'in-empty-vector (let ([v (in-vector '#(1) 0 1)]) (for/list ([e v]) e))) @@ -523,6 +524,28 @@ exn:fail:contract:arity? #rx"expected number of values not received") +(err/rt-test (for/sum ([x (in-vector (vector 1 2) 2 -1 -1)]) x) ; pr 15227 + exn:fail:contract? + #rx"starting index is out of range") +(err/rt-test (for/sum ([x (in-vector (vector) -1 -1 -1)]) x) + exn:fail:contract? + #rx"starting index is out of range") +(err/rt-test (for/sum ([x (in-vector (vector) 1 1 1)]) x) + exn:fail:contract? + #rx"starting index is out of range") +(err/rt-test (for/sum ([x (in-vector (vector 1) 1 2)]) x) + exn:fail:contract? + #rx"starting index is out of range") +(err/rt-test (for/sum ([x (in-vector (vector 1) 0 2)]) x) + exn:fail:contract? + #rx"stopping index is out of range") +(err/rt-test (for/sum ([x (in-vector (vector 1) 0 -1)]) x) + exn:fail:contract? + #rx"starting index more than stopping index, but given a positive step") +(err/rt-test (for/sum ([x (in-vector (vector 1) 0 1 -1)]) x) + exn:fail:contract? + #rx"starting index less than stopping index, but given a negative step") + ;; for/fold syntax checking (syntax-test #'(for/fold () bad 1) #rx".*bad sequence binding clauses.*") diff --git a/racket/collects/racket/private/for.rkt b/racket/collects/racket/private/for.rkt index cd85fa3432..54013ea1de 100644 --- a/racket/collects/racket/private/for.rkt +++ b/racket/collects/racket/private/for.rkt @@ -809,21 +809,22 @@ ;; the largest fixnum, after running these checks start, ;; stop, and step are guaranteed to be fixnums. (define (check-ranges who vec start stop step len) - (unless (and (exact-nonnegative-integer? start) (<= start len)) - (raise-range-error who "vector" "starting " start vec 0 len)) + (unless (and (exact-nonnegative-integer? start) + (or (< start len) (= len start stop))) + (raise-range-error who "vector" "starting " start vec 0 (sub1 len))) (unless (and (exact-integer? stop) (<= -1 stop) (<= stop len)) (raise-range-error who "vector" "stopping " stop vec -1 len)) (unless (and (exact-integer? step) (not (zero? step))) (raise-argument-error who "(and/c exact-integer? (not/c zero?))" step)) (when (and (< start stop) (< step 0)) (raise-arguments-error who - "starting index less then stopping index, but given a negative step" + "starting index less than stopping index, but given a negative step" "starting index" start "stopping index" stop "step" step)) (when (and (< stop start) (> step 0)) (raise-arguments-error who - "starting index more then stopping index, but given a positive step" + "starting index more than stopping index, but given a positive step" "starting index" start "stopping index" stop "step" step)))