Commit f51a16eb authored by Botond Baranyi's avatar Botond Baranyi
Browse files

added type check to decmatch/@decoded optimization, plus more tests



Change-Id: I7c1497a9848ea7c3b4021e30791f4bc275d7dd0e
Signed-off-by: Botond Baranyi's avatarBotond Baranyi <botond.baranyi@ericsson.com>
parent c453b6bc
......@@ -8540,7 +8540,16 @@ error:
// then the parameter redirect class should use the decoding result
// from the template instead of decoding the parameter again
needs_decode = false;
if (par->get_type()->get_type_refd_last()->get_typetype_ttcn3() == Type::T_USTR) {
Type* decmatch_type = matched_temp->get_decode_target()->get_expr_governor(
Type::EXPECTED_TEMPLATE)->get_type_refd_last();
if (ve->get_dec_type() != decmatch_type) {
// the decmatch template and this parameter redirect decode two
// different types, so just decode the parameter
needs_decode = true;
use_decmatch_result = false;
}
else if (par->get_type()->get_type_refd_last()->get_typetype_ttcn3() ==
Type::T_USTR) {
// for universal charstrings the situation could be trickier
// compare the string encodings
bool different_ustr_encodings = false;
......@@ -8618,7 +8627,12 @@ error:
set_params_str = mputstr(set_params_str, redir_coding_expr.preamble);
}
set_params_str = mputprintf(set_params_str,
"if (ptr_matched_temp->%s().get_selection() == DECODE_MATCH",
"if (ptr_matched_temp->%s().get_selection() == DECODE_MATCH && "
// the type the parameter was decoded to in the template must be the same
// as the type this parameter redirect would decode the redirected parameter to
// (this is checked by comparing the addresses of the type descriptors)
"&%s_descr_ == ptr_matched_temp->%s().get_decmatch_type_descr()",
par_name, ve->get_dec_type()->get_genname_typedescriptor(scope).c_str(),
par_name);
if (redir_coding_expr.expr != NULL) {
set_params_str = mputprintf(set_params_str,
......@@ -9171,7 +9185,16 @@ error:
// then the value redirect class should use the decoding result
// from the template instead of decoding the value again
needs_decode = false;
if (redir_type->get_type_refd_last()->get_typetype_ttcn3() == Type::T_USTR) {
Type* decmatch_type = matched_temp->get_decode_target()->get_expr_governor(
Type::EXPECTED_TEMPLATE)->get_type_refd_last();
if (v[i]->get_dec_type() != decmatch_type) {
// the decmatch template and this value redirect decode two
// different types, so just decode the value
needs_decode = true;
use_decmatch_result = false;
}
else if (redir_type->get_type_refd_last()->get_typetype_ttcn3() ==
Type::T_USTR) {
// for universal charstrings the situation could be trickier
// compare the string encodings
bool different_ustr_encodings = false;
......@@ -9270,7 +9293,14 @@ error:
}
Free(current_ref);
set_values_str = mputprintf(set_values_str,
"(*ptr_matched_temp)%s.get_selection() == DECODE_MATCH", subrefs_str);
"(*ptr_matched_temp)%s.get_selection() == DECODE_MATCH && "
// the type the value was decoded to in the template must be the same
// as the type this value redirect would decode the redirected value to
// (this is checked by comparing the addresses of the type descriptors)
"&%s_descr_ == (*ptr_matched_temp)%s.get_decmatch_type_descr()",
subrefs_str,
v[i]->get_dec_type()->get_genname_typedescriptor(scope).c_str(),
subrefs_str);
if (redir_coding_expr.expr != NULL) {
set_values_str = mputprintf(set_values_str,
" && %s == (*ptr_matched_temp)%s.get_decmatch_str_enc()",
......
......@@ -4582,6 +4582,9 @@ compile_time:
// retrieves the decoding result from the last successful matching
// (used for optimizing decoded value and parameter redirects)
"void* get_dec_res() const { return dec_val; }\n"
// returns a pointer to the type descriptor used in the decoding
// (used for the runtime type check for decoded value and parameter redirects)
"const TTCN_Typedescriptor_t* get_type_descr() const { return &%s_descr_; }\n"
"};\n"
"%s.set_type(DECODE_MATCH);\n"
"{\n", class_tmp_id.c_str(),
......@@ -4591,7 +4594,8 @@ compile_time:
target_type->get_genname_value(my_scope).c_str(),
target_type->get_genname_typedescriptor(my_scope).c_str(),
target_type->get_coding(false).c_str(),
omit_in_value_list ? ", TRUE" : "", type_name.c_str(), name);
omit_in_value_list ? ", TRUE" : "", type_name.c_str(),
target_type->get_genname_typedescriptor(my_scope).c_str(), name);
// generate the decoding target into a temporary
string target_tmp_id = my_scope->get_scope_mod_gen()->get_temporary_id();
......
......@@ -1103,6 +1103,10 @@ public:
* the function returns a void pointer (since the decoding could result in a
* value of any type), which is converted to the required type when used */
virtual void* get_dec_res() const = 0;
/** this returns the decoded type's descriptor, which may be used by value and
* parameter redirect classes to determine whether the redirected value would
* be decoded into the same type as the type used in this decmatch template */
virtual const TTCN_Typedescriptor_t* get_type_descr() const = 0;
virtual ~Dec_Match_Interface() {}
};
......
......@@ -1836,6 +1836,15 @@ void* BITSTRING_template::get_decmatch_dec_res() const
return dec_match->instance->get_dec_res();
}
const TTCN_Typedescriptor_t* BITSTRING_template::get_decmatch_type_descr() const
{
if (template_selection != DECODE_MATCH) {
TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
"bitstring template.");
}
return dec_match->instance->get_type_descr();
}
static const char patterns[] = { '0', '1', '?', '*' };
void BITSTRING_template::log() const
......
......@@ -301,6 +301,7 @@ public:
void set_decmatch(Dec_Match_Interface* new_instance);
void* get_decmatch_dec_res() const;
const TTCN_Typedescriptor_t* get_decmatch_type_descr() const;
void log() const;
void log_match(const BITSTRING& match_value, boolean legacy = FALSE) const;
......
......@@ -2454,6 +2454,15 @@ void* CHARSTRING_template::get_decmatch_dec_res() const
return dec_match->instance->get_dec_res();
}
const TTCN_Typedescriptor_t* CHARSTRING_template::get_decmatch_type_descr() const
{
if (template_selection != DECODE_MATCH) {
TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
"charstring template.");
}
return dec_match->instance->get_type_descr();
}
void CHARSTRING_template::log_pattern(int n_chars, const char *chars_ptr)
{
TTCN_Logger::log_event_str("pattern \"");
......
......@@ -432,6 +432,7 @@ public:
void set_decmatch(Dec_Match_Interface* new_instance);
void* get_decmatch_dec_res() const;
const TTCN_Typedescriptor_t* get_decmatch_type_descr() const;
void log() const;
void log_match(const CHARSTRING& match_value, boolean legacy = FALSE) const;
......
......@@ -1722,6 +1722,15 @@ void* HEXSTRING_template::get_decmatch_dec_res() const
return dec_match->instance->get_dec_res();
}
const TTCN_Typedescriptor_t* HEXSTRING_template::get_decmatch_type_descr() const
{
if (template_selection != DECODE_MATCH) {
TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
"hexstring template.");
}
return dec_match->instance->get_type_descr();
}
void HEXSTRING_template::log() const
{
switch (template_selection) {
......
......@@ -255,6 +255,7 @@ public:
void set_decmatch(Dec_Match_Interface* new_instance);
void* get_decmatch_dec_res() const;
const TTCN_Typedescriptor_t* get_decmatch_type_descr() const;
void log() const;
void log_match(const HEXSTRING& match_value, boolean legacy = FALSE) const;
......
......@@ -1958,6 +1958,15 @@ void* OCTETSTRING_template::get_decmatch_dec_res() const
return dec_match->instance->get_dec_res();
}
const TTCN_Typedescriptor_t* OCTETSTRING_template::get_decmatch_type_descr() const
{
if (template_selection != DECODE_MATCH) {
TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
"octetstring template.");
}
return dec_match->instance->get_type_descr();
}
void OCTETSTRING_template::log() const
{
switch (template_selection) {
......
......@@ -286,6 +286,7 @@ public:
void set_decmatch(Dec_Match_Interface* new_instance);
void* get_decmatch_dec_res() const;
const TTCN_Typedescriptor_t* get_decmatch_type_descr() const;
void log() const;
void log_match(const OCTETSTRING& match_value, boolean legacy = FALSE) const;
......
......@@ -4223,6 +4223,15 @@ CharCoding::CharCodingType UNIVERSAL_CHARSTRING_template::get_decmatch_str_enc()
return dec_match->coding;
}
const TTCN_Typedescriptor_t* UNIVERSAL_CHARSTRING_template::get_decmatch_type_descr() const
{
if (template_selection != DECODE_MATCH) {
TTCN_error("Retrieving the decoded type's descriptor in a non-decmatch "
"universal charstring template.");
}
return dec_match->instance->get_type_descr();
}
void UNIVERSAL_CHARSTRING_template::log() const
{
switch (template_selection) {
......
......@@ -613,6 +613,7 @@ public:
void* get_decmatch_dec_res() const;
CharCoding::CharCodingType get_decmatch_str_enc() const;
const TTCN_Typedescriptor_t* get_decmatch_type_descr() const;
void log() const;
void log_match(const UNIVERSAL_CHARSTRING& match_value, boolean legacy = FALSE) const;
......
......@@ -33,6 +33,18 @@ type record MyRecord3 {
record of MyRecord2 elems
}
type record MyRecord4 {
charstring attr,
octetstring val
}
with {
encode "XML";
variant "name as 'MyRecord2'";
variant (attr) "attribute";
variant (attr) "name as 'num'";
variant (val) "untagged";
}
type octetstring MyOctetstring with { encode "RAW"; }
signature MyProc(in integer Par1,inout charstring Par2,out float Par3)
......@@ -722,10 +734,99 @@ testcase tc_MultiValueRedirect() runs on ProcComponent4 {
}
// tests for decoded parameter and value redirects
// (in these tests the received parameters and values are not matched with a 'decmatch' template)
function DecodedRedirect_behav(in MyRecord2 val, in universal charstring reply_val) runs on ProcComponent4 {
timer tmr := 1.0;
var universal charstring val_enc := encvalue_unichar(val);
var MyRecord2 redir;
// testing parameter redirect in getcall:
tmr.start;
alt {
[] Port4.getcall(MyProc7: { val_enc }) -> param (redir := @decoded x) {
if (redir != val) { setverdict(fail, "Getcall parameter redirect failed: ", redir); }
else {
var MyRecord2 reply_rec := { num := -1, str := reply_val };
Port4.reply(MyProc7: { reply_val } value reply_rec);
Port4.raise(MyProc7, reply_rec);
}
}
[] Port4.getcall(MyProc7: { ? }) { setverdict(fail, "Invalid getcall parameter."); }
[] tmr.timeout { setverdict(fail, "Getcall timed out."); }
}
}
testcase tc_DecodedRedirect() runs on ProcComponent4 {
var ProcComponent4 ct := ProcComponent4.create;
connect(ct:Port4, mtc:Port4);
var MyRecord2 val := { num := 4, str := "stuff" };
// use this string instead of an actual encoded value for reply/getreply and raise/catch,
// because finding a value that can be encoded with UTF-16 or UTF-32 is difficult
// (after this string is decoded into an octetstring, only the octetstring's length is matched)
var universal charstring reply_val := "payload";
ct.start(DecodedRedirect_behav(val, reply_val));
var universal charstring val_enc := encvalue_unichar(val);
var MyOctetstring redir[3];
// these encoding strings are not known at compile-time (the code generated for them is different)
var charstring str_enc8 := "UTF-8", str_enc16 := "UTF-16", str_enc32 := "UTF-32LE";
// testing parameter and (return) value redirect in getreply:
Port4.call(MyProc7: { val_enc }, 1.0) {
[] Port4.getreply(MyProc7: { reply_val }
value MyRecord2: { num := ?, str := reply_val })
-> value (redir[0] := @decoded("UTF-8") str)
param (redir[1] := @decoded(str_enc16) x) {
if (redir[0] != unichar2oct(reply_val, "UTF-8")) {
setverdict(fail, "Getreply parameter redirect failed: ", redir[0]);
}
if (redir[1] != unichar2oct(reply_val, str_enc16)) {
setverdict(fail, "Getreply value redirect failed: ", redir[1]);
}
}
[] Port4.getreply(MyProc7: { decmatch(str_enc16) MyOctetstring: ? length (16) } value MyRecord2: ?) {
setverdict(fail, "Invalid getreply return value.");
}
[] Port4.getreply(MyProc7: { ? } value MyRecord2: ?) {
setverdict(fail, "Invalid getreply parameter.");
}
[] Port4.catch(MyProc7, MyRecord2: ?) {
setverdict(fail, "Exception (MyRecord2) caught in getreply test.");
}
[] Port4.catch(MyProc7, MyRecord3: ?) {
setverdict(fail, "Exception (MyRecord3) caught in getreply test.");
}
[] Port4.catch(timeout) { setverdict(fail, "Getreply test timed out."); }
}
// testing (exception) value redirect in catch:
timer tmr := 1.0;
tmr.start;
alt {
[] Port4.catch(MyProc7, MyRecord2: { num := ?, str := reply_val })
-> value (redir[2] := @decoded(str_enc32) str) {
if (redir[2] != unichar2oct(reply_val, str_enc32)) {
setverdict(fail, "Exception value redirect failed: ", redir[2]);
}
}
[] Port4.catch(MyProc7, MyRecord2: ?) {
setverdict(fail, "Invalid exception value caught.");
}
[] Port4.catch(MyProc7, MyRecord3: ?) {
setverdict(fail, "Invalid type of exception caught.");
}
[] Port4.getreply(MyProc7: { ? } value MyRecord2: ?) {
setverdict(fail, "Reply received in exception test.");
}
[] tmr.timeout { setverdict(fail, "Exception test timed out."); }
}
setverdict(pass);
}
// additional tests for decoded parameter and value redirects
// (in these tests the value and parameter redirects with the '@decoded' modifier
// are optimized to reuse the decoding result in the 'decmatch' template instead of
// decoding the same string twice)
function DecodedRedirect_behav(in MyRecord2 val, in universal charstring reply_val) runs on ProcComponent4 {
function DecodedRedirect2_behav(in MyRecord2 val, in universal charstring reply_val) runs on ProcComponent4 {
timer tmr := 1.0;
var MyRecord2 redir;
......@@ -745,7 +846,7 @@ function DecodedRedirect_behav(in MyRecord2 val, in universal charstring reply_v
}
}
testcase tc_DecodedRedirect() runs on ProcComponent4 {
testcase tc_DecodedRedirect2() runs on ProcComponent4 {
var ProcComponent4 ct := ProcComponent4.create;
connect(ct:Port4, mtc:Port4);
var MyRecord2 val := { num := 4, str := "stuff" };
......@@ -753,7 +854,7 @@ testcase tc_DecodedRedirect() runs on ProcComponent4 {
// because finding a value that can be encoded with UTF-16 or UTF-32 is difficult
// (after this string is decoded into an octetstring, only the octetstring's length is matched)
var universal charstring reply_val := "payload";
ct.start(DecodedRedirect_behav(val, reply_val));
ct.start(DecodedRedirect2_behav(val, reply_val));
var universal charstring val_enc := encvalue_unichar(val);
var MyOctetstring redir[3];
// these encoding strings are not known at compile-time (the code generated for them is different)
......@@ -811,11 +912,11 @@ testcase tc_DecodedRedirect() runs on ProcComponent4 {
setverdict(pass);
}
// additional tests for decoded parameter and value redirects
// further tests for decoded parameter and value redirects
// (in these tests the 'decmatch' templates cannot be identified at compile-time,
// so the decision of whether to decode the redirected value again or use the
// decoding result in the matched template is made at runtime)
function DecodedRedirect2_behav(in MyRecord2 val) runs on ProcComponent4 {
function DecodedRedirect3_behav(in MyRecord2 val) runs on ProcComponent4 {
timer tmr := 1.0;
var MyRecord2 redir;
var template MyProc7 vt_proc7 := { x := decmatch MyRecord2: val };
......@@ -838,11 +939,11 @@ function DecodedRedirect2_behav(in MyRecord2 val) runs on ProcComponent4 {
}
}
testcase tc_DecodedRedirect2() runs on ProcComponent4 {
testcase tc_DecodedRedirect3() runs on ProcComponent4 {
var ProcComponent4 ct := ProcComponent4.create;
connect(ct:Port4, mtc:Port4);
var MyRecord2 val := { num := 4, str := "stuff" };
ct.start(DecodedRedirect2_behav(val));
ct.start(DecodedRedirect3_behav(val));
var universal charstring val_enc := encvalue_unichar(val);
var MyRecord2 redir[3];
var template MyRecord2 vt_rec2 := { num := ?, str := decmatch MyRecord2: val };
......@@ -900,6 +1001,95 @@ testcase tc_DecodedRedirect2() runs on ProcComponent4 {
setverdict(pass);
}
// even more tests for decoded parameter and value redirects
// (in these tests the sent/received strings are decoded into 2 different types:
// the matching 'decmatch' templates decode the strings into MyRecord2, while the
// value and parameter redirects decode the string into MyRecord4)
function DecodedRedirect4_behav(in MyRecord2 val2, in MyRecord4 val4) runs on ProcComponent4 {
timer tmr := 1.0;
var MyRecord4 redir;
// testing parameter redirect in getcall:
tmr.start;
alt {
[] Port4.getcall(MyProc7: { decmatch MyRecord2: val2 }) -> param (redir := @decoded x) {
if (redir != val4) {
setverdict(fail, "Getcall parameter redirect failed: ", redir);
}
else {
var universal charstring val_enc := encvalue_unichar(val2);
var MyRecord2 reply_val := { num := val2.num, str := val_enc };
var MyRecord3 raise_val := { elems := { reply_val } };
Port4.reply(MyProc7: { val_enc } value reply_val);
Port4.raise(MyProc7, raise_val);
}
}
[] Port4.getcall(MyProc7: { ? }) { setverdict(fail, "Invalid getcall parameter."); }
[] tmr.timeout { setverdict(fail, "Getcall timed out."); }
}
}
testcase tc_DecodedRedirect4() runs on ProcComponent4 {
var ProcComponent4 ct := ProcComponent4.create;
connect(ct:Port4, mtc:Port4);
var MyRecord2 val2 := { num := 4, str := "ADDC" };
var MyRecord4 val4 := { attr := "4", val := 'ADDC'O };
ct.start(DecodedRedirect4_behav(val2, val4));
var universal charstring val_enc := encvalue_unichar(val2);
var MyRecord4 redir[3];
// testing parameter and (return) value redirect in getreply:
Port4.call(MyProc7: { val_enc }, 1.0) {
[] Port4.getreply(MyProc7TemplatePard(decmatch MyRecord2: val2)
value MyRecord2: { num := ?, str := decmatch MyRecord2: val2 })
-> value (redir[0] := @decoded str)
param (redir[1] := @decoded x) {
if (redir[0] != val4) {
setverdict(fail, "Getreply parameter redirect failed: ", redir[0]);
}
if (redir[1] != val4) {
setverdict(fail, "Getreply value redirect failed: ", redir[1]);
}
}
[] Port4.getreply(MyProc7TemplatePard(decmatch MyRecord2: val2) value MyRecord2: ?) {
setverdict(fail, "Invalid getreply return value.");
}
[] Port4.getreply(MyProc7: { ? } value MyRecord2: ?) {
setverdict(fail, "Invalid getreply parameter.");
}
[] Port4.catch(MyProc7, MyRecord2: ?) {
setverdict(fail, "Exception (MyRecord2) caught in getreply test.");
}
[] Port4.catch(MyProc7, MyRecord3: ?) {
setverdict(fail, "Exception (MyRecord3) caught in getreply test.");
}
[] Port4.catch(timeout) { setverdict(fail, "Getreply test timed out."); }
}
// testing (exception) value redirect in catch:
var template MyRecord3 vt_rec3 := { elems := { { num := ?, str := decmatch MyRecord2: val2 } } };
timer tmr := 1.0;
tmr.start;
alt {
[] Port4.catch(MyProc7, vt_rec3) -> value (redir[2] := @decoded elems[0].str) {
if (redir[2] != val4) {
setverdict(fail, "Exception value redirect failed: ", redir[2]);
}
}
[] Port4.catch(MyProc7, MyRecord3: ?) {
setverdict(fail, "Invalid exception value caught.");
}
[] Port4.catch(MyProc7, MyRecord2: ?) {
setverdict(fail, "Invalid type of exception caught.");
}
[] Port4.getreply(MyProc7: { ? } value MyRecord2: ?) {
setverdict(fail, "Reply received in exception test.");
}
[] tmr.timeout { setverdict(fail, "Exception test timed out."); }
}
setverdict(pass);
}
control {
execute(tc1_Call());
execute(tc2_Call());
......@@ -917,5 +1107,7 @@ control {
execute(tc_MultiValueRedirect());
execute(tc_DecodedRedirect());
execute(tc_DecodedRedirect2());
execute(tc_DecodedRedirect3());
execute(tc_DecodedRedirect4());
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment