@@ -1648,7 +1648,7 @@ double CVT_get_double(const dsc* desc, DecimalStatus decSt, ErrorFunction err, b
16481648}
16491649
16501650
1651- void CVT_move_common (const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* cb)
1651+ void CVT_move_common (const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* cb, bool trustedSource )
16521652{
16531653/* *************************************
16541654 *
@@ -1673,7 +1673,9 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
16731673 // (real source length must be validated against target maximum length
16741674 // and this is the first common place where both are present).
16751675
1676- if (DSC_EQUIV (from, to, false ) && !DTYPE_IS_TEXT (from->dsc_dtype ))
1676+ // ...unless these strings are coming from a trusted source (for example a cached record buffer)
1677+
1678+ if (DSC_EQUIV (from, to, false ) && (trustedSource || !DTYPE_IS_TEXT (from->dsc_dtype )))
16771679 {
16781680 if (length) {
16791681 memcpy (p, q, length);
@@ -1987,6 +1989,9 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
19871989 if (cb->transliterate (from, to, charset2))
19881990 return ;
19891991
1992+ // At this point both `from` and `to` are guaranteed to have the same charset and this is stored in charset2
1993+ // Because of this we can freely use `toCharset` against `from`.
1994+
19901995 { // scope
19911996 USHORT strtype_unused;
19921997 UCHAR *ptr;
@@ -1997,8 +2002,23 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
19972002 const USHORT to_size = TEXT_LEN (to);
19982003 CharSet* toCharset = cb->getToCharset (charset2);
19992004
2000- cb->validateData (toCharset, length, q);
2001- ULONG toLength = cb->validateLength (toCharset, charset2, length, q, to_size);
2005+ ULONG toLength = length;
2006+
2007+ if (!trustedSource)
2008+ {
2009+ // Most likely data already has been validated once or twice, but another validation won't hurt much.
2010+ cb->validateData (toCharset, length, q);
2011+ toLength = cb->validateLength (toCharset, charset2, length, q, to_size);
2012+ }
2013+ else
2014+ {
2015+ // Silently truncate. In the wild this should never happen
2016+ if (length > to_size)
2017+ {
2018+ fb_assert (from->dsc_dtype == dtype_text);
2019+ toLength = to_size;
2020+ }
2021+ }
20022022
20032023 switch (to->dsc_dtype )
20042024 {
@@ -3776,7 +3796,7 @@ USHORT CVT_get_string_ptr(const dsc* desc, USHORT* ttype, UCHAR** address,
37763796}
37773797
37783798
3779- void CVT_move (const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err)
3799+ void CVT_move (const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err, bool trustedSource )
37803800{
37813801/* *************************************
37823802 *
@@ -3789,5 +3809,5 @@ void CVT_move(const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err)
37893809 *
37903810 **************************************/
37913811 CommonCallbacks callbacks (err);
3792- CVT_move_common (from, to, decSt, &callbacks);
3812+ CVT_move_common (from, to, decSt, &callbacks, trustedSource );
37933813}
0 commit comments