Skip to content

Commit 35aae92

Browse files
authored
Merge pull request #8571 from aafemt/postfix8145
Postfixes for PR#8145
2 parents 3c119c2 + a1a0a2f commit 35aae92

File tree

16 files changed

+173
-52
lines changed

16 files changed

+173
-52
lines changed

src/common/cvt.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

src/common/cvt.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ Firebird::Decimal128 CVT_get_dec128(const dsc*, Firebird::DecimalStatus, ErrorFu
9595
Firebird::Int128 CVT_get_int128(const dsc*, SSHORT, Firebird::DecimalStatus, ErrorFunction);
9696
Firebird::Int128 CVT_hex_to_int128(const char* str, USHORT len);
9797
USHORT CVT_make_string(const dsc*, USHORT, const char**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
98-
void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*);
99-
void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction);
98+
void CVT_move_common(const dsc*, dsc*, Firebird::DecimalStatus, Firebird::Callbacks*, bool trustedSource = false);
99+
void CVT_move(const dsc*, dsc*, Firebird::DecimalStatus, ErrorFunction, bool trustedSource = false);
100100
SSHORT CVT_decompose(const char*, USHORT, Firebird::Int128*, ErrorFunction);
101101
USHORT CVT_get_string_ptr(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, ErrorFunction);
102102
USHORT CVT_get_string_ptr_common(const dsc*, USHORT*, UCHAR**, vary*, USHORT, Firebird::DecimalStatus, Firebird::Callbacks*);

src/dsql/ExprNodes.cpp

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9982,6 +9982,19 @@ ParameterNode* ParameterNode::pass1(thread_db* tdbb, CompilerScratch* csb)
99829982
status_exception::raise(Arg::Gds(isc_ctxnotdef) << Arg::Gds(isc_random) << Arg::Str("Outer parameter has no outer scratch"));
99839983
}
99849984

9985+
const dsc& desc = format->fmt_desc[argNumber];
9986+
if (desc.isText())
9987+
{
9988+
// Remember expected maximum length in characters to be able to recognize format of the real data buffer later
9989+
const CharSet* charSet = INTL_charset_lookup(tdbb, desc.getCharSet());
9990+
USHORT length = TEXT_LEN(&desc);
9991+
if (charSet->isMultiByte())
9992+
{
9993+
length /= charSet->maxBytesPerChar();
9994+
}
9995+
maxCharLength = length;
9996+
}
9997+
99859998
return this;
99869999
}
998710000

@@ -10045,9 +10058,6 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1004510058
{
1004610059
if (impureForOuter)
1004710060
EVL_make_value(tdbb, retDesc, impureForOuter);
10048-
10049-
if (retDesc->dsc_dtype == dtype_text)
10050-
INTL_adjust_text_descriptor(tdbb, retDesc);
1005110061
}
1005210062

1005310063
auto impureFlags = paramRequest->getImpure<USHORT>(
@@ -10057,7 +10067,6 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1005710067
{
1005810068
if (!(request->req_flags & req_null))
1005910069
{
10060-
USHORT maxLen = desc->dsc_length; // not adjusted length
1006110070

1006210071
if (DTYPE_IS_TEXT(retDesc->dsc_dtype))
1006310072
{
@@ -10067,8 +10076,7 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1006710076
switch (retDesc->dsc_dtype)
1006810077
{
1006910078
case dtype_cstring:
10070-
len = static_cast<USHORT>(strnlen((const char*) p, maxLen));
10071-
--maxLen;
10079+
len = static_cast<USHORT>(strnlen((const char*) p, desc->dsc_length));
1007210080
break;
1007310081

1007410082
case dtype_text:
@@ -10078,14 +10086,15 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1007810086
case dtype_varying:
1007910087
len = reinterpret_cast<const vary*>(p)->vary_length;
1008010088
p += sizeof(USHORT);
10081-
maxLen -= sizeof(USHORT);
1008210089
break;
1008310090
}
1008410091

1008510092
auto charSet = INTL_charset_lookup(tdbb, DSC_GET_CHARSET(retDesc));
1008610093

1008710094
EngineCallbacks::instance->validateData(charSet, len, p);
10088-
EngineCallbacks::instance->validateLength(charSet, DSC_GET_CHARSET(retDesc), len, p, maxLen);
10095+
10096+
// Validation of length for user-provided data against user-provided metadata makes a little sense here. Leave it to the real assignment.
10097+
// Besides in some cases overlong values are valid. For example `field like ?`
1008910098
}
1009010099
else if (retDesc->isBlob())
1009110100
{
@@ -10114,6 +10123,25 @@ dsc* ParameterNode::execute(thread_db* tdbb, Request* request) const
1011410123
*impureFlags |= VLU_checked;
1011510124
}
1011610125

10126+
// This block is after validation because having here a malformed data would produce a wrong result
10127+
if (!(request->req_flags & req_null) && retDesc->dsc_dtype == dtype_text && maxCharLength != 0)
10128+
{
10129+
// Data in the message buffer can be in a padded Firebird format or in an application-defined format with real length.
10130+
// API provides no way to distinguish these cases so we must use some heuristics:
10131+
// perform the adjustment only if the data length matches the length that would be expected in the padded format.
10132+
10133+
const CharSet* charSet = INTL_charset_lookup(tdbb, retDesc->getCharSet());
10134+
10135+
if (charSet->isMultiByte() && maxCharLength * charSet->maxBytesPerChar() == retDesc->dsc_length)
10136+
{
10137+
Firebird::HalfStaticArray<UCHAR, BUFFER_SMALL> buffer;
10138+
10139+
retDesc->dsc_length = charSet->substring(retDesc->dsc_length, retDesc->dsc_address,
10140+
retDesc->dsc_length, buffer.getBuffer(retDesc->dsc_length), 0,
10141+
maxCharLength);
10142+
}
10143+
}
10144+
1011710145
return (request->req_flags & req_null) ? nullptr : retDesc;
1011810146
}
1011910147

src/dsql/ExprNodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,7 @@ class ParameterNode final : public TypedNode<ValueExprNode, ExprNode::TYPE_PARAM
16931693
// Message can be modified during merge of SP/view subtrees
16941694
USHORT messageNumber = MAX_USHORT;
16951695
USHORT argNumber = 0;
1696+
USHORT maxCharLength = 0;
16961697
bool outerDecl = false;
16971698
};
16981699

src/gpre/cmp.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,12 +1205,6 @@ static void cmp_procedure( gpre_req* request)
12051205
for (gpre_port* port = request->req_ports; port; port = port->por_next)
12061206
cmp_port(port, request);
12071207

1208-
if (request->req_values)
1209-
{
1210-
request->add_byte(blr_begin);
1211-
make_send(request->req_vport, request);
1212-
}
1213-
12141208
if (gpreGlob.sw_ids)
12151209
{
12161210
request->add_byte(blr_exec_pid);
@@ -1247,8 +1241,6 @@ static void cmp_procedure( gpre_req* request)
12471241
else
12481242
request->add_word(0);
12491243

1250-
if (request->req_values)
1251-
request->add_byte(blr_end);
12521244
request->add_byte(blr_end);
12531245
request->add_byte(blr_eoc);
12541246
request->req_length = request->req_blr - request->req_base;

src/jrd/cvt2.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,17 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
490490
switch (arg1->dsc_dtype)
491491
{
492492
case dtype_ex_timestamp_tz:
493+
{
494+
DSC desc;
495+
MOVE_CLEAR(&desc, sizeof(desc));
496+
desc.dsc_dtype = dtype_ex_timestamp_tz;
497+
ISC_TIMESTAMP_TZ_EX datetime;
498+
desc.dsc_length = sizeof(datetime);
499+
desc.dsc_address = (UCHAR*) &datetime;
500+
CVT_move(arg2, &desc, 0);
501+
return CVT2_compare(arg1, &desc, 0);
502+
}
503+
493504
case dtype_timestamp_tz:
494505
{
495506
DSC desc;
@@ -515,6 +526,17 @@ int CVT2_compare(const dsc* arg1, const dsc* arg2, Firebird::DecimalStatus decSt
515526
}
516527

517528
case dtype_ex_time_tz:
529+
{
530+
DSC desc;
531+
MOVE_CLEAR(&desc, sizeof(desc));
532+
desc.dsc_dtype = dtype_ex_time_tz;
533+
ISC_TIME_TZ_EX atime;
534+
desc.dsc_length = sizeof(atime);
535+
desc.dsc_address = (UCHAR*) &atime;
536+
CVT_move(arg2, &desc, 0);
537+
return CVT2_compare(arg1, &desc, 0);
538+
}
539+
518540
case dtype_sql_time_tz:
519541
{
520542
DSC desc;

src/jrd/exe.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo
462462
}
463463
}
464464

465+
// Strings will be validated in CVT_move()
466+
465467
if (DTYPE_IS_BLOB_OR_QUAD(from_desc->dsc_dtype) || DTYPE_IS_BLOB_OR_QUAD(to_desc->dsc_dtype))
466468
{
467469
// ASF: Don't let MOV_move call blb::move because MOV
@@ -493,6 +495,11 @@ void EXE_assignment(thread_db* tdbb, const ValueExprNode* to, dsc* from_desc, bo
493495
{
494496
MOV_move(tdbb, from_desc, to_desc);
495497
}
498+
else if (DTYPE_IS_TEXT(from_desc->dsc_dtype))
499+
{
500+
// Force slow move to properly handle the case when source string is provided with real length instead of padded length
501+
MOV_move(tdbb, from_desc, to_desc);
502+
}
496503
else if (from_desc->dsc_dtype == dtype_short)
497504
{
498505
*((SSHORT*) to_desc->dsc_address) = *((SSHORT*) from_desc->dsc_address);

src/jrd/jrd.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4152,6 +4152,26 @@ void JRequest::getInfo(CheckStatusWrapper* user_status, int level, unsigned int
41524152

41534153
try
41544154
{
4155+
for (unsigned i = 0; i < itemsLength; ++i)
4156+
{
4157+
if (items[i] == isc_info_message_number || items[i] == isc_info_message_size)
4158+
{
4159+
// For proper return these items require request operation req_send or req_receive
4160+
// Run request from stale status until we get one of these (or end of program)
4161+
// It is up to caller to make sure that there is no heavy operations between req_next
4162+
// and the next SuspendNode/ReceiveNode/SelectMessageNode
4163+
while ((request->req_flags & req_active)
4164+
&& request->req_operation != Request::req_receive
4165+
&& request->req_operation != Request::req_send)
4166+
{
4167+
request->req_flags &= ~req_stall;
4168+
request->req_operation = Request::req_sync;
4169+
EXE_looper(tdbb, request, request->req_next);
4170+
}
4171+
break;
4172+
}
4173+
}
4174+
41554175
INF_request_info(request, itemsLength, items, bufferLength, buffer);
41564176
}
41574177
catch (const Exception& ex)
@@ -4851,6 +4871,7 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
48514871
JTransaction* const jt = getTransactionInterface(user_status, tra);
48524872
EngineContextHolder tdbb(user_status, this, FB_FUNCTION);
48534873

4874+
Request* request = nullptr;
48544875
jrd_tra* transaction = jt->getHandle();
48554876
validateHandle(tdbb, transaction);
48564877
check_database(tdbb);
@@ -4862,7 +4883,6 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
48624883
const MessageNode* inMessage = NULL;
48634884
const MessageNode* outMessage = NULL;
48644885

4865-
Request* request = NULL;
48664886
MemoryPool* new_pool = att->createPool();
48674887

48684888
try
@@ -4888,9 +4908,7 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
48884908
}
48894909
catch (const Exception&)
48904910
{
4891-
if (request)
4892-
CMP_release(tdbb, request);
4893-
else
4911+
if (!request)
48944912
att->deletePool(new_pool);
48954913

48964914
throw;
@@ -4923,6 +4941,15 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
49234941

49244942
if (out_msg_length)
49254943
{
4944+
// Workaround for GPRE that generated unneeded blr_send
4945+
if ((request->req_flags & req_active)
4946+
&& request->req_operation == Request::req_send)
4947+
{
4948+
request->req_flags &= ~req_stall;
4949+
request->req_operation = Request::req_proceed;
4950+
EXE_looper(tdbb, request, request->req_next);
4951+
}
4952+
49264953
memcpy(out_msg, outMessage->getBuffer(request), out_msg_length);
49274954
}
49284955

@@ -4932,6 +4959,9 @@ void JAttachment::transactRequest(CheckStatusWrapper* user_status, ITransaction*
49324959
}
49334960
catch (const Exception& ex)
49344961
{
4962+
if (request)
4963+
CMP_release(tdbb, request);
4964+
49354965
transliterateException(tdbb, ex, user_status, "JAttachment::transactRequest");
49364966
return;
49374967
}

src/jrd/mov.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -438,7 +438,7 @@ Firebird::string MOV_make_string2(Jrd::thread_db* tdbb, const dsc* desc, USHORT
438438
}
439439

440440

441-
void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to)
441+
void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to, bool trustedSource)
442442
{
443443
/**************************************
444444
*
@@ -454,7 +454,7 @@ void MOV_move(Jrd::thread_db* tdbb, /*const*/ dsc* from, dsc* to)
454454
if (DTYPE_IS_BLOB_OR_QUAD(from->dsc_dtype) || DTYPE_IS_BLOB_OR_QUAD(to->dsc_dtype))
455455
Jrd::blb::move(tdbb, from, to);
456456
else
457-
CVT_move(from, to, tdbb->getAttachment()->att_dec_status);
457+
CVT_move_common(from, to, tdbb->getAttachment()->att_dec_status, &Jrd::EngineCallbacks::instance, trustedSource);
458458
}
459459

460460

src/jrd/mov_proto.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ USHORT MOV_make_string(Jrd::thread_db*, const dsc*, USHORT, const char**, vary*,
5252
ULONG MOV_make_string2(Jrd::thread_db*, const dsc*, USHORT, UCHAR**, Jrd::MoveBuffer&, bool = true);
5353
Firebird::string MOV_make_string2(Jrd::thread_db* tdbb, const dsc* desc, USHORT ttype,
5454
bool limit = true);
55-
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*);
55+
void MOV_move(Jrd::thread_db*, /*const*/ dsc*, dsc*, bool trustedSource = false);
5656
Firebird::Decimal64 MOV_get_dec64(Jrd::thread_db*, const dsc*);
5757
Firebird::Decimal128 MOV_get_dec128(Jrd::thread_db*, const dsc*);
5858
Firebird::Int128 MOV_get_int128(Jrd::thread_db*, const dsc*, SSHORT);

0 commit comments

Comments
 (0)