From dd9ab5fc0b6c0b706288f8f5e20989b6e24921e9 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Tue, 17 May 2022 20:52:44 -0700 Subject: ffi: bugfix: null terminated string as flexible member. * ffi.c (ffi_char_array_get, ffi_zchar_array_get, ffi_wchar_array_get, ffi_bchar_array_get): Rearrange so that we test for tft->null_term first, and not nelem == 0. If nelem happens to be zero, but we are supposed to decode a null-terminated string, we will do the wrong thing and return the null string. (ffi_varray_in): The body can't be conditional on vec being non-nil, because then we do nothing if we don't have a Lisp object, which means we skip the cases when we should decode a null-terminated array. Now if vec is nil, we must guard against calling ffi_varray_dynsize. --- ffi.c | 66 ++++++++++++++++++++++----------------------------- tests/017/ffi-misc.tl | 6 +++++ 2 files changed, 34 insertions(+), 38 deletions(-) diff --git a/ffi.c b/ffi.c index a12ef4a3..c8c8ca82 100644 --- a/ffi.c +++ b/ffi.c @@ -2460,16 +2460,14 @@ static void ffi_struct_release(struct txr_ffi_type *tft, val strct, static val ffi_char_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem) { - if (nelem == 0) { + const char *chptr = coerce(const char *, src); + if (tft->null_term) { + return string_utf8(chptr); + } else if (nelem == 0) { return null_string; } else { - const char *chptr = coerce(const char *, src); - if (tft->null_term) { - return string_utf8(chptr); - } else { - wchar_t *wch = utf8_dup_from_buf(chptr, nelem); - return string_own(wch); - } + wchar_t *wch = utf8_dup_from_buf(chptr, nelem); + return string_own(wch); } } @@ -2496,36 +2494,30 @@ static void ffi_char_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, static val ffi_zchar_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem) { - if (nelem == 0) { + const char *chptr = coerce(const char *, src); + if (tft->null_term) { + return string_utf8(chptr); + } else if (nelem == 0) { return null_string; + } else if (memchr(chptr, 0, nelem)) { + return string_utf8(chptr); } else { - const char *chptr = coerce(const char *, src); - if (tft->null_term) { - return string_utf8(chptr); - } else if (memchr(chptr, 0, nelem)) { - return string_utf8(chptr); - } else { - wchar_t *wch = utf8_dup_from_buf(chptr, nelem); - return string_own(wch); - } + wchar_t *wch = utf8_dup_from_buf(chptr, nelem); + return string_own(wch); } } - static val ffi_wchar_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem, val self) { - if (nelem == 0) { + const wchar_t *wchptr = coerce(const wchar_t *, src); + if (tft->null_term) { + return string(wchptr); + } else if (nelem == 0) { return null_string; } else { - const wchar_t *wchptr = coerce(const wchar_t *, src); - - if (tft->null_term) { - return string(wchptr); - } else { - val ustr = mkustring(num_fast(nelem)); - return init_str(ustr, wchptr, self); - } + val ustr = mkustring(num_fast(nelem)); + return init_str(ustr, wchptr, self); } } @@ -2541,15 +2533,13 @@ static void ffi_wchar_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, static val ffi_bchar_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem) { - if (nelem == 0) { + const unsigned char *chptr = coerce(const unsigned char *, src); + if (tft->null_term) + return string_8bit(chptr); + else if (nelem == 0) return null_string; - } else { - const unsigned char *chptr = coerce(const unsigned char *, src); - if (tft->null_term) - return string_8bit(chptr); - else - return string_8bit_size(chptr, nelem); - } + else + return string_8bit_size(chptr, nelem); } static void ffi_bchar_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, @@ -2858,9 +2848,9 @@ static void ffi_varray_put(struct txr_ffi_type *tft, val vec, mem_t *dst, static val ffi_varray_in(struct txr_ffi_type *tft, int copy, mem_t *src, val vec, val self) { - if (copy && vec) { + if (copy) { struct txr_ffi_type *etft = ffi_type_struct(tft->eltype); - cnum nelem = ffi_varray_dynsize(tft, vec, self) / etft->size; + cnum nelem = if3(vec, ffi_varray_dynsize(tft, vec, self) / etft->size, 0); switch (tft->ch_conv) { case conv_char: diff --git a/tests/017/ffi-misc.tl b/tests/017/ffi-misc.tl index 7053f78e..d0785513 100644 --- a/tests/017/ffi-misc.tl +++ b/tests/017/ffi-misc.tl @@ -88,3 +88,9 @@ (copy-cptr (cptr-int 3)) "#" (copy (cptr-int 3)) "#" (copy-cptr 3) :error) + +(ffi (struct flex (x char) (y (zarray char)))) + +(mtest + (ffi-put (new flex x #\a y "bcd") (ffi (struct flex))) #b'6100000062636400' + (ffi-get #b'6100000062636400' (ffi (struct flex))) #S(flex x #\a y "bcd")) -- cgit v1.2.3