diff --git a/pkgs/racket-test/tests/file/gzip.rkt b/pkgs/racket-test/tests/file/gzip.rkt index 627d0b095d..9af83eff3c 100644 --- a/pkgs/racket-test/tests/file/gzip.rkt +++ b/pkgs/racket-test/tests/file/gzip.rkt @@ -77,6 +77,26 @@ ;; should be around 6 times smaller (id* (file->bytes big-file) 4)) +(define (test-hang-on-long-filename) + ;; `tar-gzip` was crashing in a background thread due to a very long + ;; filename, leading to a hang in the main thread. Trigger the bug + ;; with a long filename, and check that progress is made in a + ;; reasonable length of time. + (local-require file/tar) + (define long-filename + "extremely-long-file-name-that-exceeds-the-internal-length-limits-on-USTAR-because-of-arcane-decisions-and-bad-choices-of-fixed-width-records-and-so-on-and-so-on") + (define temp-dir (find-system-path 'temp-dir)) + (define long-path (build-path temp-dir long-filename)) + (with-output-to-file long-path (lambda () (write long-filename)) #:exists 'replace) + (define tgz-file (build-path temp-dir "long-filename-test.tgz")) + (when (file-exists? tgz-file) (delete-file tgz-file)) + (define ch (make-channel)) + (thread (lambda () + (with-handlers [(exn:fail? (lambda (_exn) (channel-put ch 'success)))] + (tar-gzip tgz-file long-path) + (channel-put ch 'didnt-fail-in-tar-gzip)))) + (test (sync/timeout 10 ch) => 'success)) + (define (run-tests) (define (rand-bytes) (list->bytes (for/list ([j (in-range (random 1000))]) (random 256)))) @@ -84,7 +104,8 @@ (test-degenerate-input-1) (test-degenerate-input-2) (for ([i (in-range 100)]) (id* (rand-bytes))) - (regression-test)) + (regression-test) + (test-hang-on-long-filename)) (define (regression-test) ;; check for an out-of-range buffer access: diff --git a/racket/collects/file/tar.rkt b/racket/collects/file/tar.rkt index 43a5dee977..a5809d300f 100644 --- a/racket/collects/file/tar.rkt +++ b/racket/collects/file/tar.rkt @@ -180,14 +180,16 @@ #:exists (if exists-ok? 'truncate/replace 'error) (lambda () (let-values ([(i o) (make-pipe (* 1024 1024 32))]) + (define tar-exn #f) (thread (lambda () - (tar->output (pathlist-closure paths - #:follow-links? follow-links? - #:path-filter path-filter) - o - #:path-prefix prefix - #:follow-links? follow-links? - #:get-timestamp get-timestamp) + (with-handlers [((lambda (exn) #t) (lambda (exn) (set! tar-exn exn)))] + (tar->output (pathlist-closure paths + #:follow-links? follow-links? + #:path-filter path-filter) + o + #:path-prefix prefix + #:follow-links? follow-links? + #:get-timestamp get-timestamp)) (close-output-port o))) (gzip-through-ports i (current-output-port) @@ -196,4 +198,5 @@ (path->string tgz-file) tgz-file)) => (lambda (m) (string-append (car m) "tar"))] [else #f]) - (current-seconds)))))) + (current-seconds)) + (when tar-exn (raise tar-exn))))))