From 1cc86d3cea4763d70e4a155e286305215519a23d Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Tue, 14 Oct 2014 05:59:35 -0600 Subject: [PATCH] ffi/unsafe: fix `make-sized-byte-string` on a #f argument In particular, a #f argument can make sense if the length is 0. Technically, a byte string's byte array is supposed to be nul-terminated, but many uses of byte strings get away without that terminator. I've adjust the documentation to note that `bytes-copy` will work with a non-terminated byte string. Merge to v6.1.1 --- .../racket-doc/scribblings/foreign/pointers.scrbl | 6 ++++++ .../racket-test/tests/racket/foreign-test.rktl | 2 ++ racket/src/foreign/foreign.c | 8 +++----- racket/src/foreign/foreign.rktc | 15 ++++++++++----- 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/pkgs/racket-pkgs/racket-doc/scribblings/foreign/pointers.scrbl b/pkgs/racket-pkgs/racket-doc/scribblings/foreign/pointers.scrbl index ba680ff9e0..79ac838cb7 100644 --- a/pkgs/racket-pkgs/racket-doc/scribblings/foreign/pointers.scrbl +++ b/pkgs/racket-pkgs/racket-doc/scribblings/foreign/pointers.scrbl @@ -389,6 +389,12 @@ Returns a byte string made of the given pointer and the given length. No copying is done. This can be used as an alternative to make pointer values accessible in Racket when the size is known. +Beware that the representation of a Racket byte string normally +requires a nul terminator at the end of the byte string (after +@racket[length] bytes), but some function work with a byte-string +representation that has no such terminator---notably +@racket[bytes-copy]. + If @racket[cptr] is an offset pointer created by @racket[ptr-add], the offset is immediately added to the pointer. Thus, this function cannot be used with @racket[ptr-add] to create a substring of a Racket byte diff --git a/pkgs/racket-pkgs/racket-test/tests/racket/foreign-test.rktl b/pkgs/racket-pkgs/racket-test/tests/racket/foreign-test.rktl index bb925aeabf..b2392d64b8 100644 --- a/pkgs/racket-pkgs/racket-test/tests/racket/foreign-test.rktl +++ b/pkgs/racket-pkgs/racket-test/tests/racket/foreign-test.rktl @@ -15,6 +15,8 @@ (test #f malloc 0 _int) (test #f malloc _int 0) +(test 0 bytes-length (make-sized-byte-string #f 0)) + ;; Check integer-range checking: (let () (define (try-int-boundary N _int _uint) diff --git a/racket/src/foreign/foreign.c b/racket/src/foreign/foreign.c index 14cfca29c7..b5be78debf 100644 --- a/racket/src/foreign/foreign.c +++ b/racket/src/foreign/foreign.c @@ -3178,9 +3178,7 @@ static Scheme_Object *foreign_make_sized_byte_string(int argc, Scheme_Object *ar scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv); if (!scheme_get_int_val(argv[1],&len)) wrong_intptr(MYNAME, 1, argc, argv); - if (SCHEME_FALSEP(cp)) return scheme_false; - else return - scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp), + return scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp), len, 0); } #undef MYNAME @@ -3304,9 +3302,9 @@ static void ffi_call_in_orig_place(ffi_cif *cif, void *c_func, intptr_t cfoff, /* Done */ mzrt_mutex_unlock(orig_place_mutex); if (!cached_orig_place_todo) - cached_orig_place_todo = todo; + cached_orig_place_todo = todo; else - free(todo); + free(todo); break; } else { /* Pause to allow actions such as a master GC.... */ diff --git a/racket/src/foreign/foreign.rktc b/racket/src/foreign/foreign.rktc index 5b6f16c03f..f1ded27583 100755 --- a/racket/src/foreign/foreign.rktc +++ b/racket/src/foreign/foreign.rktc @@ -2346,9 +2346,7 @@ static Scheme_Object *do_memop(const char *who, int mode, scheme_wrong_contract(MYNAME, "cpointer?", 0, argc, argv); if (!scheme_get_int_val(argv[1],&len)) wrong_intptr(MYNAME, 1, argc, argv); - if (SCHEME_FALSEP(cp)) return scheme_false; - else return - scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp), + return scheme_make_sized_byte_string(SCHEME_FFIANYPTR_OFFSETVAL(cp), len, 0); } @@ -2415,7 +2413,11 @@ static void ffi_call_in_orig_place(ffi_cif *cif, void *c_func, intptr_t cfoff, void *sh; int ready; - todo = (FFI_Orig_Place_Call *)malloc(sizeof(FFI_Orig_Place_Call)); + if (cached_orig_place_todo) { + todo = cached_orig_place_todo; + cached_orig_place_todo = NULL; + } else + todo = (FFI_Orig_Place_Call *)malloc(sizeof(FFI_Orig_Place_Call)); sh = scheme_get_signal_handle(); todo->signal_handle = sh; todo->needs_queue = 1; @@ -2466,7 +2468,10 @@ static void ffi_call_in_orig_place(ffi_cif *cif, void *c_func, intptr_t cfoff, if (!todo->signal_handle) { /* Done */ mzrt_mutex_unlock(orig_place_mutex); - free(todo); + if (!cached_orig_place_todo) + cached_orig_place_todo = todo; + else + free(todo); break; } else { /* Pause to allow actions such as a master GC.... */