From 32ecda4fd0c9febb101cd3c9a667f93eaa06f688 Mon Sep 17 00:00:00 2001 From: Dorin Marcoci Date: Fri, 2 Oct 2026 15:15:40 +0300 Subject: [PATCH] Fix isc_put_slice storing unaligned VARCHAR array elements without character set conversion An array element of an odd-size VARCHAR (e.g. VARCHAR(3) in a single-byte character set) can start at an odd address. slice_callback wrote such elements with MOV_make_string, which converts through CVT_move and CommonCallbacks, so the slice was copied without transliteration. Move the value with MOV_move into an aligned temporary instead, as for aligned elements, and copy it. --- src/jrd/blb.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/jrd/blb.cpp b/src/jrd/blb.cpp index dfcb58164af..491fe722c2d 100644 --- a/src/jrd/blb.cpp +++ b/src/jrd/blb.cpp @@ -2911,23 +2911,21 @@ static void slice_callback(array_slice* arg, ULONG /*count*/, DSC* descriptors) // The individual elements of a varying string array may not be aligned // correctly. If they aren't, some RISC machines may break. In those - // cases, calculate the actual length and then move the length and text manually. + // cases, move the value into an aligned temporary and then copy the length and text. + // Don't use MOV_make_string here, it doesn't transliterate between character sets. if (array_desc->dsc_dtype == dtype_varying && array_desc->dsc_address != FB_ALIGN(array_desc->dsc_address, (MIN(sizeof(USHORT), FB_ALIGNMENT)))) { - // Note: cannot remove this JRD_get_thread_data without api change - // to slice callback routines - /*thread_db* tdbb = */ JRD_get_thread_data(); - DynamicVaryStr<1024> tmp_buffer; - const USHORT tmp_len = array_desc->dsc_length; - const char* p; - const USHORT len = MOV_make_string(tdbb, slice_desc, array_desc->getTextType(), &p, - tmp_buffer.getBuffer(tmp_len), tmp_len); - memcpy(array_desc->dsc_address, &len, sizeof(USHORT)); - memcpy(array_desc->dsc_address + sizeof(USHORT), p, (int) len); + vary* const tmp = tmp_buffer.getBuffer(array_desc->dsc_length); + + dsc tmp_desc = *array_desc; + tmp_desc.dsc_address = reinterpret_cast(tmp); + MOV_move(tdbb, slice_desc, &tmp_desc); + + memcpy(array_desc->dsc_address, tmp, sizeof(USHORT) + tmp->vary_length); } else {