@@ -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 *
@@ -1669,7 +1669,13 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
16691669 // optimal, it would cost more to find the fast move than the
16701670 // fast move would gain.
16711671
1672- if (DSC_EQUIV (from, to, false ))
1672+ // But do not do it for strings because their length has not been validated until this moment
1673+ // (real source length must be validated against target maximum length
1674+ // and this is the first common place where both are present).
1675+
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 )))
16731679 {
16741680 if (length) {
16751681 memcpy (p, q, length);
@@ -1983,6 +1989,9 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
19831989 if (cb->transliterate (from, to, charset2))
19841990 return ;
19851991
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+
19861995 { // scope
19871996 USHORT strtype_unused;
19881997 UCHAR *ptr;
@@ -1993,8 +2002,23 @@ void CVT_move_common(const dsc* from, dsc* to, DecimalStatus decSt, Callbacks* c
19932002 const USHORT to_size = TEXT_LEN (to);
19942003 CharSet* toCharset = cb->getToCharset (charset2);
19952004
1996- cb->validateData (toCharset, length, q);
1997- 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+ }
19982022
19992023 switch (to->dsc_dtype )
20002024 {
@@ -3777,7 +3801,7 @@ USHORT CVT_get_string_ptr(const dsc* desc, USHORT* ttype, UCHAR** address,
37773801}
37783802
37793803
3780- void CVT_move (const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err)
3804+ void CVT_move (const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err, bool trustedSource )
37813805{
37823806/* *************************************
37833807 *
@@ -3790,5 +3814,5 @@ void CVT_move(const dsc* from, dsc* to, DecimalStatus decSt, ErrorFunction err)
37903814 *
37913815 **************************************/
37923816 CommonCallbacks callbacks (err);
3793- CVT_move_common (from, to, decSt, &callbacks);
3817+ CVT_move_common (from, to, decSt, &callbacks, trustedSource );
37943818}
0 commit comments