static void __unlink_state(binpac_sink* sink, __parser_state* state, hlt_execution_context* ctx) { __parser_state* prev = 0; __parser_state* s = sink->head; while ( s ) { if ( s == state ) break; prev = s; s = s->next; } assert(s); if ( prev ) prev->next = state->next; else sink->head = state->next; GC_CLEAR(state->data, hlt_bytes, ctx); GC_CLEAR(state->resume, hlt_exception, ctx); GC_DTOR_GENERIC(&state->pobj, state->parser->type_info, ctx); state->pobj = 0; GC_CLEAR(state->parser, hlt_BinPACHilti_Parser, ctx); hlt_free(state); }
static void __finish_parser(binpac_sink* sink, __parser_state* state, hlt_exception** excpt, hlt_execution_context* ctx) { if ( state->data && state->resume ) { hlt_bytes_freeze(state->data, 1, excpt, ctx); // TODO: Not sure if we need this wrapping with fiber/excpt here // (neither in main write function). hlt_fiber* saved_fiber = ctx->fiber; ctx->fiber = 0; hlt_exception* sink_excpt = 0; // We may trigger a safepoint so make sure we refcount our locoal. GC_CCTOR(sink, binpac_sink, ctx); __cctor_state(state, ctx); (state->parser->resume_func_sink)(state->resume, &sink_excpt, ctx); GC_DTOR(sink, binpac_sink, ctx); __dtor_state(state, ctx); GC_CLEAR(state->resume, hlt_exception, ctx); __hlt_context_clear_exception(ctx); ctx->fiber = saved_fiber; // TODO: Not quite sure why the yield exception can occur here, but // we ignore it. // // Update: Actually I think I do: when two separate filters (like // first for a sink and then for the unit connected to it) filter the // same data, the frozen flags doesn't get propagated. // // We forbid that for now and hope it won't be used ... // // sink-unit-filter.pac2 tests for this but is currently disabled ... if ( sink_excpt && sink_excpt->type == &hlt_exception_yield ) { assert(false); } else if ( sink_excpt && sink_excpt->type == &binpac_exception_parserdisabled ) { // Disabled, nothing to do. DBG_LOG("binpac-sinks", "- final writing to sink %p disabled for parser %p", sink, state->pobj); GC_DTOR(sink_excpt, hlt_exception, ctx); } else *excpt = sink_excpt; } __unlink_state(sink, state, ctx); }
void binpac_sink_dtor(hlt_type_info* ti, binpac_sink* sink, hlt_execution_context* ctx) { // TODO: This is not consistnely called because HILTI is actually using // its own type info for the dummy struct type. We should unify that, but // it's not clear how .. For now, we can't rely on this running. #if 0 while ( sink->head ) __unlink_state(sink, sink->head); GC_CLEAR(sink->filter, binpac_filter, ctx); __trim(sink, UINT64_MAX, user, excpt, ctx); assert(! sink->first_chunk); assert(! sink->last_chunk); #endif }
void binpachilti_filter_close(binpac_filter* head, hlt_exception** excpt, hlt_execution_context* ctx) { if ( ! head ) return; binpac_filter* prev = 0; binpac_filter* n = 0; for ( binpac_filter* f = head; f; f = n ) { n = f->next; (*f->def->close)(f, excpt, ctx); (*f->def->dtor)(0, f, ctx); if ( f != head ) // The reference to the first filter is owned by the struct. GC_CLEAR(f, binpac_filter, ctx); } }
void binpachilti_sink_close(binpac_sink* sink, void* user, hlt_exception** excpt, hlt_execution_context* ctx) { DBG_LOG("binpac-sinks", "closing sink %p", sink); if ( sink->filter ) { binpachilti_filter_close(sink->filter, excpt, ctx); GC_CLEAR(sink->filter, binpac_filter, ctx); } while( sink->head ) __finish_parser(sink, sink->head, excpt, ctx); __trim(sink, UINT64_MAX, user, excpt, ctx); assert(! sink->first_chunk); assert(! sink->last_chunk); sink->cur_rseq = 0; sink->last_reassem_rseq = 0; sink->trim_rseq = 0; DBG_LOG("binpac-sinks", "closed sink %p, disconnected all parsers", sink); }
static int8_t __deliver_chunk(binpac_sink* sink, hlt_bytes* data, uint64_t rseq, uint64_t rupper, void* user, hlt_exception** excpt, hlt_execution_context* ctx) { if ( ! data ) { // A gap. DBG_LOG("binpac-sinks", "hit gap with sink %p at rseq %" PRIu64, sink, rseq); if ( sink->cur_rseq != rupper ) { __report_gap(sink, rseq, (rupper - rseq), user, excpt, ctx); sink->cur_rseq = rupper; if ( sink->auto_trim ) // We trim just up to the gap here, excluding the gap itself. This // will prevent future data beyond the gap from being delivered until // we explicitly skip over it. __trim(sink, rseq, user, excpt, ctx); } return 0; } DBG_LOG("binpac-sinks", "starting to deliver to sink %p at rseq %" PRIu64, sink, rseq); // If the HILTI function that we'll call suspends, it will change the // yield/resume fields. We need to reset them when we leave this // function. hlt_fiber* saved_fiber = ctx->fiber; __hlt_thread_mgr_blockable* saved_blockable = ctx->blockable; ctx->fiber = 0; ctx->blockable = 0; binpac_dbg_deliver(sink, data, 0, excpt, ctx); if ( sink->filter ) { hlt_bytes* decoded = binpachilti_filter_decode(sink->filter, data, excpt, ctx); // &noref! if ( ! decoded ) goto exit; data = decoded; } sink->size += hlt_bytes_len(data, excpt, ctx); if ( *excpt ) goto exit; if ( ! sink->head ) { DBG_LOG("binpac-sinks", "done delivering to sink %p, no parser connected", sink); goto exit; } // data at +1 here. __parser_state* s = sink->head; // Now pass it onto parsers. while ( s ) { if ( s->disconnected ) continue; hlt_exception* sink_excpt = 0; if ( ! s->data ) { // First chunk. DBG_LOG("binpac-sinks", "- start delivering to sink %p for parser %p", sink, s->pobj); s->data = hlt_bytes_copy(data, excpt, ctx); GC_CCTOR(s->data, hlt_bytes, ctx); if ( hlt_bytes_is_frozen(data, excpt, ctx) ) hlt_bytes_freeze(s->data, 1, excpt, ctx); // We may trigger a safepoint so make sure we refcount our locoal. GC_CCTOR(sink, binpac_sink, ctx); GC_CCTOR(data, hlt_bytes, ctx); __cctor_state(s, ctx); (s->parser->parse_func_sink)(s->pobj, s->data, user, &sink_excpt, ctx); GC_DTOR(sink, binpac_sink, ctx); GC_DTOR(data, hlt_bytes, ctx); __dtor_state(s, ctx); } else { if ( ! s->resume ) { // Parsing has already finished for this parser. We ignore this here, // as otherwise we'd have to throw an exception and thus abort the // other parsers as well. s = s->next; continue; } DBG_LOG("binpac-sinks", "- resuming delivering to sink %p for parser %p", sink, s->pobj); // Subsequent chunk, resume. hlt_bytes_append(s->data, data, excpt, ctx); if ( hlt_bytes_is_frozen(data, excpt, ctx) ) hlt_bytes_freeze(s->data, 1, excpt, ctx); // We may trigger a safepoint so make sure we refcount our locoal. GC_CCTOR(sink, binpac_sink, ctx); GC_CCTOR(data, hlt_bytes, ctx); __cctor_state(s, ctx); (s->parser->resume_func_sink)(s->resume, &sink_excpt, ctx); GC_DTOR(sink, binpac_sink, ctx); GC_DTOR(data, hlt_bytes, ctx); __dtor_state(s, ctx); GC_CLEAR(s->resume, hlt_exception, ctx); } // Clear any left-over exceptions. __hlt_context_clear_exception(ctx); if ( sink_excpt && sink_excpt->type == &hlt_exception_yield ) { // Suspended. DBG_LOG("binpac-sinks", "- delivering to sink %p suspended for parser %p", sink, s->pobj); GC_CCTOR(sink_excpt, hlt_exception, ctx); s->resume = sink_excpt; s = s->next; sink_excpt = 0; } else if ( sink_excpt && sink_excpt->type == &binpac_exception_parserdisabled ) { // Disabled DBG_LOG("binpac-sinks", "- writing to sink %p disabled for parser %p", sink, s->pobj); GC_DTOR(sink_excpt, hlt_exception, ctx); sink_excpt = 0; __parser_state* next = s->next; // This guy is finished, remove. __unlink_state(sink, s, ctx); s = next; } else { DBG_LOG("binpac-sinks", "- delivering to sink %p finished for parser %p", sink, s->pobj); __parser_state* next = s->next; // This guy is finished, remove. __unlink_state(sink, s, ctx); s = next; } if ( sink_excpt ) { // Error, abort. *excpt = sink_excpt; goto exit; } } // Savely delete disconnected parsers. int done = 0; while ( ! done ) { done = 1; for ( __parser_state* s = sink->head; s; s = s->next ) { if ( s->disconnected ) { // We ignore parse error triggered by the disconnect. hlt_exception* ignore_excpt = 0; __finish_parser(sink, s, &ignore_excpt, ctx); if ( ignore_excpt ) GC_DTOR(ignore_excpt, hlt_exception, ctx); done = 0; break; } } } exit: ctx->fiber = saved_fiber; ctx->blockable = saved_blockable; sink->cur_rseq = rupper; sink->last_reassem_rseq = rupper; if ( sink->auto_trim ) __trim(sink, rupper, user, excpt, ctx); DBG_LOG("binpac-sinks", "done delivering to sink %p", sink); return 1; }
void __mime_parser_dtor(hlt_type_info* ti, __mime_parser* mime_parser, hlt_execution_context* ctx) { GC_CLEAR(mime_parser->parser, hlt_BinPACHilti_Parser, ctx); GC_CLEAR(mime_parser->next, __mime_parser, ctx); }
void __hlt_context_clear_exception(hlt_execution_context* ctx) { GC_CLEAR(ctx->excpt, hlt_exception, ctx); }