racket/draw: fix memory-management problems with JPEG binding
This commit is contained in:
parent
d54f51ab79
commit
c5c5e6959d
|
@ -45,7 +45,7 @@
|
||||||
(define JPOOL_NUMPOOLS 2)
|
(define JPOOL_NUMPOOLS 2)
|
||||||
(define JMSG_LENGTH_MAX 200)
|
(define JMSG_LENGTH_MAX 200)
|
||||||
|
|
||||||
(define-cstruct _jpeg_error_mgr ([error_exit (_fun _j_common_ptr -> _void)]
|
(define-cstruct _jpeg_error_mgr ([error_exit _fpointer] ; (_fun _j_common_ptr -> _void)
|
||||||
[emit_message _pointer]
|
[emit_message _pointer]
|
||||||
[output_message _pointer]
|
[output_message _pointer]
|
||||||
[format_message (_fun _j_common_ptr _pointer -> _void)]
|
[format_message (_fun _j_common_ptr _pointer -> _void)]
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
(let ([m (cast (malloc dummy-size 'raw) _pointer _jpeg_any_struct-pointer)]
|
(let ([m (cast (malloc dummy-size 'raw) _pointer _jpeg_any_struct-pointer)]
|
||||||
[e (cast (malloc sizeof_jpeg_error_mgr 'raw) _pointer _jpeg_error_mgr-pointer)])
|
[e (cast (malloc sizeof_jpeg_error_mgr 'raw) _pointer _jpeg_error_mgr-pointer)])
|
||||||
(set-jpeg_any_struct-err! m (jpeg_std_error e))
|
(set-jpeg_any_struct-err! m (jpeg_std_error e))
|
||||||
(set-jpeg_error_mgr-error_exit! e error-exit)
|
(set-jpeg_error_mgr-error_exit! e (cast error-exit (_fun _j_common_ptr -> _void) _fpointer))
|
||||||
(let ([s (with-handlers ([exn:fail? (lambda (exn) (exn-message exn))])
|
(let ([s (with-handlers ([exn:fail? (lambda (exn) (exn-message exn))])
|
||||||
(jpeg_CreateDecompress/test m 0 dummy-size)
|
(jpeg_CreateDecompress/test m 0 dummy-size)
|
||||||
"")])
|
"")])
|
||||||
|
@ -327,11 +327,11 @@
|
||||||
|
|
||||||
(define-cstruct _jpeg_source_mgr ([next_input_byte _pointer] ;; /* => next byte to read from buffer */
|
(define-cstruct _jpeg_source_mgr ([next_input_byte _pointer] ;; /* => next byte to read from buffer */
|
||||||
[bytes_in_buffer _size_t] ;; /* # of bytes remaining in buffer */
|
[bytes_in_buffer _size_t] ;; /* # of bytes remaining in buffer */
|
||||||
[init_source (_fun _j_decompress_ptr -> _void)]
|
[init_source _fpointer] ; (_fun _j_decompress_ptr -> _void)
|
||||||
[fill_input_buffer (_fun _j_decompress_ptr -> _jbool)]
|
[fill_input_buffer _fpointer] ; (_fun _j_decompress_ptr -> _jbool)
|
||||||
[skip_input_data (_fun _j_decompress_ptr _long -> _void)]
|
[skip_input_data _fpointer] ; (_fun _j_decompress_ptr _long -> _void)
|
||||||
[resync_to_restart (_fun _j_decompress_ptr _int -> _jbool)]
|
[resync_to_restart _fpointer] ; (_fun _j_decompress_ptr _int -> _jbool)
|
||||||
[term_source (_fun _j_decompress_ptr -> _void)]
|
[term_source _fpointer] ; (_fun _j_decompress_ptr -> _void)
|
||||||
;; extra fields specific to this binding:
|
;; extra fields specific to this binding:
|
||||||
[buffer _pointer]))
|
[buffer _pointer]))
|
||||||
|
|
||||||
|
@ -532,9 +532,9 @@
|
||||||
|
|
||||||
(define-cstruct _jpeg_destination_mgr ([next_output_byte _pointer] ;; /* => next byte to write in buffer */
|
(define-cstruct _jpeg_destination_mgr ([next_output_byte _pointer] ;; /* => next byte to write in buffer */
|
||||||
[free_in_buffer _size_t] ;; /* # of byte spaces remaining in buffer */
|
[free_in_buffer _size_t] ;; /* # of byte spaces remaining in buffer */
|
||||||
[init_destination (_fun _j_compress_ptr -> _void)]
|
[init_destination _fpointer] ; (_fun _j_compress_ptr -> _void)
|
||||||
[empty_output_buffer (_fun _j_compress_ptr -> _jbool)]
|
[empty_output_buffer _fpointer] ; (_fun _j_compress_ptr -> _jbool)
|
||||||
[term_destination (_fun _j_compress_ptr -> _void)]
|
[term_destination _fpointer] ; (_fun _j_compress_ptr -> _void)
|
||||||
;; extra fields specific to this binding:
|
;; extra fields specific to this binding:
|
||||||
[buffer _pointer]))
|
[buffer _pointer]))
|
||||||
|
|
||||||
|
@ -552,7 +552,7 @@
|
||||||
(let* ([s (jpeg_decompress_struct-src m)]
|
(let* ([s (jpeg_decompress_struct-src m)]
|
||||||
[b (jpeg_source_mgr-buffer s)]
|
[b (jpeg_source_mgr-buffer s)]
|
||||||
[bstr (scheme_make_sized_byte_string b BUFFER-SIZE 0)]
|
[bstr (scheme_make_sized_byte_string b BUFFER-SIZE 0)]
|
||||||
[in (ptr-ref (jpeg_decompress_struct-client_data m) _scheme)])
|
[in (car (ptr-ref (jpeg_decompress_struct-client_data m) _scheme))])
|
||||||
(let* ([len (read-bytes! bstr in)]
|
(let* ([len (read-bytes! bstr in)]
|
||||||
[len (if (zero? len)
|
[len (if (zero? len)
|
||||||
(begin
|
(begin
|
||||||
|
@ -571,7 +571,7 @@
|
||||||
(begin
|
(begin
|
||||||
(set-jpeg_source_mgr-next_input_byte! s (ptr-add (jpeg_source_mgr-next_input_byte s) len))
|
(set-jpeg_source_mgr-next_input_byte! s (ptr-add (jpeg_source_mgr-next_input_byte s) len))
|
||||||
(set-jpeg_source_mgr-bytes_in_buffer! s (- avail len)))
|
(set-jpeg_source_mgr-bytes_in_buffer! s (- avail len)))
|
||||||
(let ([in (ptr-ref (jpeg_decompress_struct-client_data m) _scheme)])
|
(let ([in (car (ptr-ref (jpeg_decompress_struct-client_data m) _scheme))])
|
||||||
(read-bytes (- len avail) in)
|
(read-bytes (- len avail) in)
|
||||||
(set-jpeg_source_mgr-next_input_byte! s #f)
|
(set-jpeg_source_mgr-next_input_byte! s #f)
|
||||||
(set-jpeg_source_mgr-bytes_in_buffer! s 0)
|
(set-jpeg_source_mgr-bytes_in_buffer! s 0)
|
||||||
|
@ -580,7 +580,7 @@
|
||||||
(define (term-source m)
|
(define (term-source m)
|
||||||
;; Maybe add support to optionally close port as early as possible?
|
;; Maybe add support to optionally close port as early as possible?
|
||||||
(when #f
|
(when #f
|
||||||
(let ([in (ptr-ref (jpeg_decompress_struct-client_data m) _scheme)])
|
(let ([in (car (ptr-ref (jpeg_decompress_struct-client_data m) _scheme))])
|
||||||
(close-input-port in))))
|
(close-input-port in))))
|
||||||
|
|
||||||
(define (init-destination m)
|
(define (init-destination m)
|
||||||
|
@ -594,7 +594,7 @@
|
||||||
BUFFER-SIZE
|
BUFFER-SIZE
|
||||||
(- BUFFER-SIZE (jpeg_destination_mgr-free_in_buffer d)))
|
(- BUFFER-SIZE (jpeg_destination_mgr-free_in_buffer d)))
|
||||||
0)]
|
0)]
|
||||||
[out (ptr-ref (jpeg_compress_struct-client_data m) _scheme)])
|
[out (car (ptr-ref (jpeg_compress_struct-client_data m) _scheme))])
|
||||||
(write-bytes bstr out)
|
(write-bytes bstr out)
|
||||||
(set-jpeg_destination_mgr-next_output_byte! d b)
|
(set-jpeg_destination_mgr-next_output_byte! d b)
|
||||||
(set-jpeg_destination_mgr-free_in_buffer! d BUFFER-SIZE)
|
(set-jpeg_destination_mgr-free_in_buffer! d BUFFER-SIZE)
|
||||||
|
@ -607,7 +607,7 @@
|
||||||
(do-empty-output-buffer m #f)
|
(do-empty-output-buffer m #f)
|
||||||
;; Maybe add support to optionally close port as early as possible?
|
;; Maybe add support to optionally close port as early as possible?
|
||||||
(when #f
|
(when #f
|
||||||
(let ([in (ptr-ref (jpeg_decompress_struct-client_data m) _scheme)])
|
(let ([in (car (ptr-ref (jpeg_decompress_struct-client_data m) _scheme))])
|
||||||
(close-input-port in))))
|
(close-input-port in))))
|
||||||
|
|
||||||
(define (ptr-cast p t) (cast p _pointer t))
|
(define (ptr-cast p t) (cast p _pointer t))
|
||||||
|
@ -627,20 +627,31 @@
|
||||||
(let ([m (ptr-cast (malloc _jpeg_decompress_struct 'raw) _jpeg_decompress_struct-pointer)]
|
(let ([m (ptr-cast (malloc _jpeg_decompress_struct 'raw) _jpeg_decompress_struct-pointer)]
|
||||||
[s (ptr-cast (malloc _jpeg_source_mgr 'raw) _jpeg_source_mgr-pointer)]
|
[s (ptr-cast (malloc _jpeg_source_mgr 'raw) _jpeg_source_mgr-pointer)]
|
||||||
[e (ptr-cast (malloc sizeof_jpeg_error_mgr 'raw) _jpeg_error_mgr-pointer)]
|
[e (ptr-cast (malloc sizeof_jpeg_error_mgr 'raw) _jpeg_error_mgr-pointer)]
|
||||||
[b (malloc 'raw BUFFER-SIZE)])
|
[b (malloc 'raw BUFFER-SIZE)]
|
||||||
|
[funs (box null)])
|
||||||
(set-jpeg_decompress_struct-err! m (jpeg_std_error e))
|
(set-jpeg_decompress_struct-err! m (jpeg_std_error e))
|
||||||
(set-jpeg_error_mgr-error_exit! e error-exit)
|
(set-jpeg_error_mgr-error_exit! e (cast error-exit
|
||||||
|
(_fun #:keep funs _j_common_ptr -> _void)
|
||||||
|
_fpointer))
|
||||||
(jpeg_CreateDecompress m JPEG_LIB_VERSION (ctype-sizeof _jpeg_decompress_struct))
|
(jpeg_CreateDecompress m JPEG_LIB_VERSION (ctype-sizeof _jpeg_decompress_struct))
|
||||||
(set-jpeg_decompress_struct-src*! m s)
|
(set-jpeg_decompress_struct-src*! m s)
|
||||||
(set-jpeg_source_mgr-buffer! s b)
|
(set-jpeg_source_mgr-buffer! s b)
|
||||||
(set-jpeg_decompress_struct-client_data! m (malloc-immobile-cell in))
|
(set-jpeg_decompress_struct-client_data! m (malloc-immobile-cell (cons in funs)))
|
||||||
(set-jpeg_source_mgr-next_input_byte! s #f)
|
(set-jpeg_source_mgr-next_input_byte! s #f)
|
||||||
(set-jpeg_source_mgr-bytes_in_buffer! s 0)
|
(set-jpeg_source_mgr-bytes_in_buffer! s 0)
|
||||||
(set-jpeg_source_mgr-init_source! s init-source)
|
(set-jpeg_source_mgr-init_source! s (cast init-source
|
||||||
(set-jpeg_source_mgr-fill_input_buffer! s fill-input-buffer)
|
(_fun #:keep funs _j_decompress_ptr -> _void)
|
||||||
(set-jpeg_source_mgr-skip_input_data! s skip-input-data)
|
_fpointer))
|
||||||
|
(set-jpeg_source_mgr-fill_input_buffer! s (cast fill-input-buffer
|
||||||
|
(_fun #:keep funs _j_decompress_ptr -> _jbool)
|
||||||
|
_fpointer))
|
||||||
|
(set-jpeg_source_mgr-skip_input_data! s (cast skip-input-data
|
||||||
|
(_fun #:keep funs _j_decompress_ptr _long -> _void)
|
||||||
|
_fpointer))
|
||||||
(set-jpeg_source_mgr-resync_to_restart! s jpeg_resync_to_restart)
|
(set-jpeg_source_mgr-resync_to_restart! s jpeg_resync_to_restart)
|
||||||
(set-jpeg_source_mgr-term_source! s term-source)
|
(set-jpeg_source_mgr-term_source! s (cast term-source
|
||||||
|
(_fun #:keep funs _j_decompress_ptr -> _void)
|
||||||
|
_fpointer))
|
||||||
m))))
|
m))))
|
||||||
|
|
||||||
(define destroy-compress
|
(define destroy-compress
|
||||||
|
@ -658,18 +669,27 @@
|
||||||
(let ([m (ptr-cast (malloc _jpeg_compress_struct 'raw) _jpeg_compress_struct-pointer)]
|
(let ([m (ptr-cast (malloc _jpeg_compress_struct 'raw) _jpeg_compress_struct-pointer)]
|
||||||
[d (ptr-cast (malloc _jpeg_destination_mgr 'raw) _jpeg_destination_mgr-pointer)]
|
[d (ptr-cast (malloc _jpeg_destination_mgr 'raw) _jpeg_destination_mgr-pointer)]
|
||||||
[e (ptr-cast (malloc sizeof_jpeg_error_mgr 'raw) _jpeg_error_mgr-pointer)]
|
[e (ptr-cast (malloc sizeof_jpeg_error_mgr 'raw) _jpeg_error_mgr-pointer)]
|
||||||
[b (malloc 'raw BUFFER-SIZE)])
|
[b (malloc 'raw BUFFER-SIZE)]
|
||||||
|
[funs (box null)])
|
||||||
(set-jpeg_compress_struct-err! m (jpeg_std_error e))
|
(set-jpeg_compress_struct-err! m (jpeg_std_error e))
|
||||||
(set-jpeg_error_mgr-error_exit! e error-exit)
|
(set-jpeg_error_mgr-error_exit! e (cast error-exit
|
||||||
|
(_fun #:keep funs _j_common_ptr -> _void)
|
||||||
|
_fpointer))
|
||||||
(jpeg_CreateCompress m JPEG_LIB_VERSION (ctype-sizeof _jpeg_compress_struct))
|
(jpeg_CreateCompress m JPEG_LIB_VERSION (ctype-sizeof _jpeg_compress_struct))
|
||||||
(set-jpeg_compress_struct-dest*! m d)
|
(set-jpeg_compress_struct-dest*! m d)
|
||||||
(set-jpeg_destination_mgr-buffer! d b)
|
(set-jpeg_destination_mgr-buffer! d b)
|
||||||
(set-jpeg_compress_struct-client_data! m (malloc-immobile-cell out))
|
(set-jpeg_compress_struct-client_data! m (malloc-immobile-cell (cons out funs)))
|
||||||
(set-jpeg_destination_mgr-next_output_byte! d b)
|
(set-jpeg_destination_mgr-next_output_byte! d b)
|
||||||
(set-jpeg_destination_mgr-free_in_buffer! d BUFFER-SIZE)
|
(set-jpeg_destination_mgr-free_in_buffer! d BUFFER-SIZE)
|
||||||
(set-jpeg_destination_mgr-init_destination! d init-destination)
|
(set-jpeg_destination_mgr-init_destination! d (cast init-destination
|
||||||
(set-jpeg_destination_mgr-empty_output_buffer! d empty-output-buffer)
|
(_fun #:keep funs _j_compress_ptr -> _void)
|
||||||
(set-jpeg_destination_mgr-term_destination! d term-destination)
|
_fpointer))
|
||||||
|
(set-jpeg_destination_mgr-empty_output_buffer! d (cast empty-output-buffer
|
||||||
|
(_fun #:keep funs _j_compress_ptr -> _jbool)
|
||||||
|
_fpointer))
|
||||||
|
(set-jpeg_destination_mgr-term_destination! d (cast term-destination
|
||||||
|
(_fun #:keep funs _j_compress_ptr -> _void)
|
||||||
|
_fpointer))
|
||||||
m))))
|
m))))
|
||||||
|
|
||||||
(define (create-jpeg-sample-array m len)
|
(define (create-jpeg-sample-array m len)
|
||||||
|
@ -683,7 +703,7 @@
|
||||||
(values samps (scheme_make_sized_byte_string (ptr-ref samps _pointer) len 0))))
|
(values samps (scheme_make_sized_byte_string (ptr-ref samps _pointer) len 0))))
|
||||||
|
|
||||||
(define-jpeg/private jpeg_CreateDecompress (_fun _j_decompress_ptr _int _int -> _void))
|
(define-jpeg/private jpeg_CreateDecompress (_fun _j_decompress_ptr _int _int -> _void))
|
||||||
(define-jpeg/private jpeg_resync_to_restart (_fun _j_decompress_ptr _int -> _jbool))
|
(define-jpeg/private jpeg_resync_to_restart _fpointer) ; (_fun _j_decompress_ptr _int -> _jbool))
|
||||||
(define-jpeg jpeg_read_header (_fun _j_decompress_ptr _jbool -> _void))
|
(define-jpeg jpeg_read_header (_fun _j_decompress_ptr _jbool -> _void))
|
||||||
(define-jpeg jpeg_start_decompress (_fun _j_decompress_ptr -> _void))
|
(define-jpeg jpeg_start_decompress (_fun _j_decompress_ptr -> _void))
|
||||||
(define-jpeg jpeg_read_scanlines (_fun _j_decompress_ptr _pointer _int -> _void))
|
(define-jpeg jpeg_read_scanlines (_fun _j_decompress_ptr _pointer _int -> _void))
|
||||||
|
|
34
collects/tests/gracket/jpeg-stress.rkt
Normal file
34
collects/tests/gracket/jpeg-stress.rkt
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require racket/class
|
||||||
|
racket/draw
|
||||||
|
racket/file)
|
||||||
|
|
||||||
|
;; Check memory-management in the JPEG library by reading and writing
|
||||||
|
;; in many threads at the same time.
|
||||||
|
|
||||||
|
(define ts
|
||||||
|
(for/list ([i (in-range 40)])
|
||||||
|
(thread
|
||||||
|
(lambda()
|
||||||
|
(for ([i (in-range 10)])
|
||||||
|
(define bm (read-bitmap (collection-file-path "plt.jpg" "icons")))
|
||||||
|
(define t (make-temporary-file))
|
||||||
|
(send bm save-file t 'jpeg)
|
||||||
|
(define bm2 (read-bitmap t))
|
||||||
|
(define w (send bm get-width))
|
||||||
|
(define h (send bm get-width))
|
||||||
|
(define s1 (make-bytes (* w h 4)))
|
||||||
|
(define s2 (make-bytes (* w h 4)))
|
||||||
|
(send bm get-argb-pixels 0 0 w h s1)
|
||||||
|
(send bm2 get-argb-pixels 0 0 w h s2)
|
||||||
|
;; JPEG is lossy, so use a fuzzy compare:
|
||||||
|
(define diff (for/sum ([b1 (in-bytes s1)]
|
||||||
|
[b2 (in-bytes s2)])
|
||||||
|
(- b2 b1)))
|
||||||
|
(unless ((abs diff) . < . (* w h 1))
|
||||||
|
(error 'jpeg-stree "mismatch ~s ~s ~e" w h diff))
|
||||||
|
(delete-file t))))))
|
||||||
|
|
||||||
|
(for ([t (in-list ts)]) (sync t))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user