From 6e96eafb9bf087c35cfe8e60196d0a2a1698d22b Mon Sep 17 00:00:00 2001 From: Stefan Radomski Date: Mon, 18 Jan 2016 15:07:16 +0100 Subject: Fixed a memory leak in transformed C scaffolding --- src/uscxml/transform/ChartToC.cpp | 62 ++++++++++++++++++++++----------------- test/src/test-c-machine.cpp | 20 ++++++++----- test/w3c/check-tests.pl | 23 +++++++++++++-- 3 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/uscxml/transform/ChartToC.cpp b/src/uscxml/transform/ChartToC.cpp index aac1acf..f261ffd 100644 --- a/src/uscxml/transform/ChartToC.cpp +++ b/src/uscxml/transform/ChartToC.cpp @@ -216,10 +216,10 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << "typedef struct scxml_elem_foreach scxml_elem_foreach;" << std::endl; stream << std::endl; - stream << "typedef void* (*dequeue_internal_cb_t)(const scxml_ctx* ctx);" << std::endl; - stream << "typedef void* (*dequeue_external_cb_t)(const scxml_ctx* ctx);" << std::endl; - stream << "typedef int (*is_enabled_cb_t)(const scxml_ctx* ctx, const scxml_transition* transition, const void* event);" << std::endl; - stream << "typedef int (*is_true_cb_t)(const scxml_ctx* ctx, const char* expr);" << std::endl; + stream << "typedef void* (*dequeue_internal_t)(const scxml_ctx* ctx);" << std::endl; + stream << "typedef void* (*dequeue_external_t)(const scxml_ctx* ctx);" << std::endl; + stream << "typedef int (*is_enabled_t)(const scxml_ctx* ctx, const scxml_transition* transition, const void* event);" << std::endl; + stream << "typedef int (*is_true_t)(const scxml_ctx* ctx, const char* expr);" << std::endl; stream << "typedef int (*exec_content_t)(const scxml_ctx* ctx, const scxml_state* state, const void* event);" << std::endl; stream << "typedef int (*raise_done_event_t)(const scxml_ctx* ctx, const scxml_state* state, const scxml_elem_donedata* donedata);" << std::endl; stream << "typedef int (*invoke_t)(const scxml_ctx* ctx, const scxml_state* s, const scxml_invoke* x);" << std::endl; @@ -339,10 +339,10 @@ void ChartToC::writeTypes(std::ostream& stream) { stream << " void* user_data;" << std::endl; stream << " void* event;" << std::endl; stream << std::endl; - stream << " dequeue_internal_cb_t dequeue_internal;" << std::endl; - stream << " dequeue_external_cb_t dequeue_external;" << std::endl; - stream << " is_enabled_cb_t is_enabled;" << std::endl; - stream << " is_true_cb_t is_true;" << std::endl; + stream << " dequeue_internal_t dequeue_internal;" << std::endl; + stream << " dequeue_external_t dequeue_external;" << std::endl; + stream << " is_enabled_t is_enabled;" << std::endl; + stream << " is_true_t is_true;" << std::endl; stream << " raise_done_event_t raise_done_event;" << std::endl; stream << std::endl; stream << " exec_content_log_t exec_content_log;" << std::endl; @@ -491,7 +491,12 @@ void ChartToC::writeExecContent(std::ostream& stream) { stream << std::endl; } - bool hasInitialState = false; + /* + gen/c/ecma/test412.scxml (Failed) + gen/c/ecma/test579.scxml (Failed) + */ +#if 0 + bool hasInitialState = false; NodeSet initial = filterChildElements(_nsInfo.xmlNSPrefix + "initial", state); if (initial.size() > 0) { NodeSet initialTransition = filterChildElements(_nsInfo.xmlNSPrefix + "transition", initial); @@ -505,16 +510,16 @@ void ChartToC::writeExecContent(std::ostream& stream) { stream << std::endl; } } - +#endif if (onentry.size() > 0) { stream << "static int " << DOMUtils::idForNode(state) << "_on_entry(const scxml_ctx* ctx, const scxml_state* state, const void* event) {" << std::endl; for (size_t j = 0; j < onentry.size(); j++) { stream << " " << DOMUtils::idForNode(state) << "_on_entry_" << toStr(j) << "(ctx, state, event);" << std::endl; } - if (hasInitialState) { - stream << " " << DOMUtils::idForNode(state) << "_initial" << "(ctx, state, event);" << std::endl; - } +// if (hasInitialState) { +// stream << " " << DOMUtils::idForNode(state) << "_initial" << "(ctx, state, event);" << std::endl; +// } stream << " return SCXML_ERR_OK;" << std::endl; stream << "}" << std::endl; @@ -536,8 +541,8 @@ void ChartToC::writeExecContent(std::ostream& stream) { for (size_t i = 0; i < _transitions.size(); i++) { Element transition(_transitions[i]); - if (iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) - continue; +// if (iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) +// continue; NodeSet execContent = filterChildType(Node_base::ELEMENT_NODE, transition); @@ -1087,30 +1092,33 @@ void ChartToC::writeStates(std::ostream& stream) { void ChartToC::writeTransitions(std::ostream& stream) { -#if 0 // cross reference transition by document order - is this really needed?! std::set elements; elements.insert(_nsInfo.xmlNSPrefix + "transition"); NodeSet transDocOrder = inDocumentOrder(elements, _scxml); - stream << "static const " << _transDataType << " scxml_transitions_doc_order[" << toStr(_transitions.size()) << "] = {" << std::endl; - stream << " "; + std::stringstream transDocOrderSS; std::string seperator = ""; for (size_t i = 0; i < transDocOrder.size(); i++) { Element transition(_transitions[i]); transition.setAttribute("documentOrder", toStr(i)); - stream << seperator << ATTR(transition, "postFixOrder"); + transDocOrderSS << seperator << ATTR(transition, "postFixOrder"); seperator = ", "; } - stream << std::endl << "};" << std::endl; - stream << std::endl; +#if 0 + stream << "static const " << _transDataType << " scxml_transitions_doc_order[" << toStr(_transitions.size()) << "] = {" << std::endl; + stream << " " << transDocOrderSS; + stream << std::endl << "};" << std::endl; + stream << std::endl; #endif stream << "static const scxml_transition scxml_transitions[" << toStr(_transitions.size()) << "] = {" << std::endl; for (size_t i = 0; i < _transitions.size(); i++) { Element transition(_transitions[i]); - stream << " { /* transition number " << ATTR(transition, "documentOrder") << " with priority " << toStr(i) << " */" << std::endl; + stream << " { /* transition number " << ATTR(transition, "documentOrder") << " with priority " << toStr(i) << std::endl; + stream << " target: " << ATTR(transition, "target") << std::endl; + stream << " */" << std::endl; /** uint16_t source; @@ -1167,8 +1175,8 @@ void ChartToC::writeTransitions(std::ostream& stream) { // on transition handlers stream << " /* ontrans */ "; - if (filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, transition).size() > 0 && - !iequals(TAGNAME_CAST(transition.getParentNode()), "initial")) { + if (filterChildType(Arabica::DOM::Node_base::ELEMENT_NODE, transition).size() > 0 /* && + !iequals(TAGNAME_CAST(transition.getParentNode()), "initial") */) { stream << DOMUtils::idForNode(transition) + "_on_trans"; } else { stream << "NULL"; @@ -1525,7 +1533,7 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << "// TAKE_TRANSITIONS:" << std::endl; stream << " for (size_t i = 0; i < SCXML_NUMBER_TRANSITIONS; i++) {" << std::endl; - stream << " if (IS_SET(i, trans_set) && (scxml_transitions[i].type & SCXML_TRANS_HISTORY) == 0) {" << std::endl; + stream << " if (IS_SET(i, trans_set) && (scxml_transitions[i].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) == 0) {" << std::endl; stream << " // call executable content in transition" << std::endl; stream << " if (scxml_transitions[i].on_transition != NULL) {" << std::endl; stream << " if unlikely((err = scxml_transitions[i].on_transition(ctx," << std::endl; @@ -1571,10 +1579,10 @@ void ChartToC::writeFSM(std::ostream& stream) { stream << " }" << std::endl; stream << std::endl; - stream << " // take history transitions" << std::endl; + stream << " // take history and initial transitions" << std::endl; stream << " for (size_t j = 0; j < SCXML_NUMBER_TRANSITIONS; j++) {" << std::endl; stream << " if unlikely(IS_SET(j, trans_set) &&" << std::endl; - stream << " (scxml_transitions[j].type & SCXML_TRANS_HISTORY) &&" << std::endl; + stream << " (scxml_transitions[j].type & (SCXML_TRANS_HISTORY | SCXML_TRANS_INITIAL)) &&" << std::endl; stream << " scxml_states[scxml_transitions[j].source].parent == i) {" << std::endl; stream << " // call executable content in transition" << std::endl; stream << " if (scxml_transitions[j].on_transition != NULL) {" << std::endl; diff --git a/test/src/test-c-machine.cpp b/test/src/test-c-machine.cpp index 35f06a4..33c149a 100644 --- a/test/src/test-c-machine.cpp +++ b/test/src/test-c-machine.cpp @@ -127,7 +127,7 @@ int matches(const char* desc, const char* event) { int exec_content_raise(const scxml_ctx* ctx, const char* event) { Event* e = new Event(); - e->name = strdup(event); + e->name = event; if (boost::starts_with(e->name, "error.")) { e->eventType = Event::PLATFORM; @@ -216,8 +216,10 @@ int raise_done_event(const scxml_ctx* ctx, const scxml_state* state, const scxml void delayedSend(void* ctx, std::string eventName) { tthread::lock_guard lock(USER_DATA(ctx)->mutex); - SendRequest* e = USER_DATA(ctx)->sendIds[eventName]; - if (e->target == "#_internal") { + SendRequest* sr = USER_DATA(ctx)->sendIds[eventName]; + Event* e = new Event(*sr); + + if (sr->target == "#_internal") { e->eventType = Event::INTERNAL; #ifdef SCXML_VERBOSE printf("Pushing Internal Event: %s\n", e->name.c_str()); @@ -231,6 +233,7 @@ void delayedSend(void* ctx, std::string eventName) { USER_DATA(ctx)->eq.push_back(e); } USER_DATA(ctx)->monitor.notify_all(); + delete sr; } int exec_content_cancel(const scxml_ctx* ctx, const char* sendid, const char* sendidexpr) { @@ -300,8 +303,9 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { } else { e->type = "http://www.w3.org/TR/scxml/#SCXMLEventProcessor"; } - } catch (Event e) { - exec_content_raise(ctx, e.name.c_str()); + } catch (Event exc) { + exec_content_raise(ctx, exc.name.c_str()); + delete e; return SCXML_ERR_EXEC_CONTENT; } @@ -317,7 +321,7 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { if (send->eventexpr != NULL) { e->name = USER_DATA(ctx)->datamodel.evalAsString(send->eventexpr); } else { - e->name = strdup(send->event); + e->name = send->event; } try { @@ -367,12 +371,12 @@ int exec_content_send(const scxml_ctx* ctx, const scxml_elem_send* send) { } } - const char* sendid = NULL; + std::string sendid; if (send->id != NULL) { sendid = send->id; e->sendid = sendid; } else { - sendid = strdup(UUID::getUUID().c_str()); + sendid = UUID::getUUID(); if (send->idlocation != NULL) { USER_DATA(ctx)->datamodel.assign(send->idlocation, Data(sendid, Data::VERBATIM)); } else { diff --git a/test/w3c/check-tests.pl b/test/w3c/check-tests.pl index 7299947..71218f4 100755 --- a/test/w3c/check-tests.pl +++ b/test/w3c/check-tests.pl @@ -4,6 +4,13 @@ use strict; use Data::Dumper; use XML::Simple; +my @failed; +# failing for C transformation +# @failed = qw/ +# 187 191 192 207 215 216 220 223 224 225 226 228 229 230 232 233 234 235 +# 236 237 239 240 241 242 243 244 245 247 250 252 253 276 338 347 422 530 +# 554 201 496 500 501 509 510 518 519 520 521 522 531 532 534 567 569 577 +# 301 307 446 552 557 558 561/; my $manifest = XMLin("./manifest.xml"); # print Dumper($manifest->{'assert'}); @@ -17,7 +24,7 @@ my @agnosticTests; my @nullTests; my @manualTests; -for my $testNr (keys $manifest->{'assert'}) { +TESTS: for my $testNr (keys $manifest->{'assert'}) { my @tests; my $thisTest = $manifest->{'assert'}->{$testNr}; if (ref($thisTest->{'test'}->{'start'}) eq "ARRAY") { @@ -25,7 +32,17 @@ for my $testNr (keys $manifest->{'assert'}) { } else { push (@tests, $thisTest->{'test'}->{'start'}); } + for my $t (@tests) { + if ($t->{'uri'} =~ /\/test(.*)\.[txml|txt]/) { + next TESTS if ( grep /^$1$/, @failed ); + $perSpecId->{$thisTest->{'specnum'}.':'.$thisTest->{'specid'}}->{'tests'} .= $1." "; + } else { + die(Dumper($t)); + } + } + $perSpecId->{$thisTest->{'specnum'}.':'.$thisTest->{'specid'}}->{'total'} += @tests; + if ($thisTest->{'test'}->{'manual'} eq "true") { $perSpecId->{$thisTest->{'specnum'}.':'.$thisTest->{'specid'}}->{'manual'} += @tests; push @manualTests, @tests; @@ -43,7 +60,7 @@ for my $testNr (keys $manifest->{'assert'}) { if ($thisTest->{'specid'} eq "#xpath-profile" || $thisTest->{'specid'} !~ /profile$/) { push @xpathTests, @tests; } - + push (@allTests, @tests); push @agnosticTests, @tests if ($thisTest->{'specid'} !~ /profile$/); } @@ -81,7 +98,7 @@ for my $datamodel (keys %datamodels) { } } -# print Dumper(@manualTests); +print Dumper($perSpecId); print "NULL : ".@nullTests."\n"; print "ECMA : ".@ecmaTests."\n"; -- cgit v0.12