diff --git a/src/rose/match.c b/src/rose/match.c index 9163cba3..9ff7db06 100644 --- a/src/rose/match.c +++ b/src/rose/match.c @@ -599,6 +599,12 @@ int roseRunBoundaryProgram(const struct RoseEngine *rose, u32 program, scratch->deduper.som_log_dirty = 0; } + // Keep assertions in program report path happy. At offset zero, there can + // have been no earlier reports. At EOD, all earlier reports should have + // been handled and we will have been caught up to the stream offset by the + // time we are running boundary report programs. + scratch->tctxt.minMatchOffset = stream_offset; + const size_t match_len = 0; const char in_anchored = 0; hwlmcb_rv_t rv = roseRunProgram(rose, scratch, program, stream_offset, diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index bb11b1a7..51a0eeef 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -2486,6 +2486,30 @@ void makeDedupeSom(const ReportID id, vector &report_block) { report_block.push_back(move(ri)); } +static +void makeCatchup(RoseBuildImpl &build, build_context &bc, + const flat_set &reports, + vector &program) { + if (!bc.needs_catchup) { + return; + } + + // Everything except the INTERNAL_ROSE_CHAIN report needs catchup to run + // before reports are triggered. + + auto report_needs_catchup = [&](const ReportID &id) { + const Report &report = build.rm.getReport(id); + return report.type != INTERNAL_ROSE_CHAIN; + }; + + if (!any_of(begin(reports), end(reports), report_needs_catchup)) { + DEBUG_PRINTF("none of the given reports needs catchup\n"); + return; + } + + program.emplace_back(ROSE_INSTR_CATCH_UP); +} + static void makeReport(RoseBuildImpl &build, build_context &bc, const ReportID id, const bool has_som, vector &program) { @@ -2503,13 +2527,6 @@ void makeReport(RoseBuildImpl &build, build_context &bc, const ReportID id, report_block.push_back(move(ri)); } - // Catch up -- everything except the INTERNAL_ROSE_CHAIN report needs this. - // TODO: this could be floated in front of all the reports and only done - // once. - if (bc.needs_catchup && report.type != INTERNAL_ROSE_CHAIN) { - report_block.emplace_back(ROSE_INSTR_CATCH_UP); - } - // If this report has an exhaustion key, we can check it in the program // rather than waiting until we're in the callback adaptor. if (report.ekey != INVALID_EKEY) { @@ -2651,7 +2668,10 @@ void makeRoleReports(RoseBuildImpl &build, build_context &bc, RoseVertex v, has_som = true; } - for (ReportID id : g[v].reports) { + const auto &reports = g[v].reports; + makeCatchup(build, bc, reports, program); + + for (ReportID id : reports) { makeReport(build, bc, id, has_som, program); } } @@ -2860,6 +2880,10 @@ u32 writeBoundaryProgram(RoseBuildImpl &build, build_context &bc, return 0; } + // Note: no CATCHUP instruction is necessary in the boundary case, as we + // should always be caught up (and may not even have the resources in + // scratch to support it). + const bool has_som = false; vector program; for (const auto &id : reports) { @@ -3565,8 +3589,11 @@ vector makeEodAnchorProgram(RoseBuildImpl &build, makeRoleCheckNotHandled(bc, v, program); } + const auto &reports = g[v].reports; + makeCatchup(build, bc, reports, program); + const bool has_som = false; - for (const auto &id : g[v].reports) { + for (const auto &id : reports) { makeReport(build, bc, id, has_som, program); }