X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=liblttng-ust%2Flttng-filter.c;h=a42fe5d7aa830345ffbca64841be73698c914036;hb=56b849af90745087f9a6abb0bed352e6705119aa;hp=b6600b02af75f6e183b655cdcbe837ec03d42080;hpb=da6eed2597e16cf3291e1c0f0f9dcc2323d298cf;p=lttng-ust.git diff --git a/liblttng-ust/lttng-filter.c b/liblttng-ust/lttng-filter.c index b6600b02..a42fe5d7 100644 --- a/liblttng-ust/lttng-filter.c +++ b/liblttng-ust/lttng-filter.c @@ -29,10 +29,9 @@ #include #include #include +#include #include "filter-bytecode.h" -#define DEBUG //TEST - #define NR_REG 2 #ifndef min_t @@ -65,12 +64,21 @@ struct bytecode_runtime { char data[0]; }; +enum reg_type { + REG_S64, + REG_DOUBLE, + REG_STRING, +}; + +/* Validation registers */ +struct vreg { + enum reg_type type; + int literal; /* is string literal ? */ +}; + +/* Execution registers */ struct reg { - enum { - REG_S64, - REG_DOUBLE, - REG_STRING, - } type; + enum reg_type type; int64_t v; double d; @@ -240,18 +248,13 @@ int lttng_filter_interpret_bytecode(void *filter_data, start_pc = &bytecode->data[0]; for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; pc = next_pc) { - if (unlikely(pc >= start_pc + bytecode->len)) { - fprintf(stderr, "[error] filter bytecode overflow\n"); - ret = -EINVAL; - goto end; - } dbg_printf("Executing op %s (%u)\n", print_op((unsigned int) *(filter_opcode_t *) pc), (unsigned int) *(filter_opcode_t *) pc); switch (*(filter_opcode_t *) pc) { case FILTER_OP_UNKNOWN: default: - fprintf(stderr, "[error] unknown bytecode op %u\n", + ERR("unknown bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; @@ -272,22 +275,16 @@ int lttng_filter_interpret_bytecode(void *filter_data, case FILTER_OP_BIN_AND: case FILTER_OP_BIN_OR: case FILTER_OP_BIN_XOR: - fprintf(stderr, "[error] unsupported bytecode op %u\n", + ERR("unsupported bytecode op %u\n", (unsigned int) *(filter_opcode_t *) pc); ret = -EINVAL; goto end; case FILTER_OP_EQ: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '==' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -297,7 +294,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -312,7 +309,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -331,15 +328,9 @@ int lttng_filter_interpret_bytecode(void *filter_data, } case FILTER_OP_NE: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '!=' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -349,7 +340,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -364,7 +355,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -383,15 +374,9 @@ int lttng_filter_interpret_bytecode(void *filter_data, } case FILTER_OP_GT: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '>' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -401,7 +386,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -416,7 +401,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -435,15 +420,9 @@ int lttng_filter_interpret_bytecode(void *filter_data, } case FILTER_OP_LT: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '<' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -453,7 +432,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -468,7 +447,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -487,15 +466,9 @@ int lttng_filter_interpret_bytecode(void *filter_data, } case FILTER_OP_GE: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '>=' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -505,7 +478,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -520,7 +493,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -539,15 +512,9 @@ int lttng_filter_interpret_bytecode(void *filter_data, } case FILTER_OP_LE: { - if (unlikely((reg[REG_R0].type == REG_STRING && reg[REG_R1].type != REG_STRING) - || (reg[REG_R0].type != REG_STRING && reg[REG_R1].type == REG_STRING))) { - fprintf(stderr, "[error] type mismatch for '<=' binary operator\n"); - ret = -EINVAL; - goto end; - } switch (reg[REG_R0].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -557,7 +524,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_S64: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -572,7 +539,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, case REG_DOUBLE: switch (reg[REG_R1].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; @@ -593,29 +560,6 @@ int lttng_filter_interpret_bytecode(void *filter_data, /* unary */ case FILTER_OP_UNARY_PLUS: { - struct unary_op *insn = (struct unary_op *) pc; - - if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", - (unsigned int) insn->reg); - ret = -EINVAL; - goto end; - } - switch (reg[insn->reg].type) { - default: - fprintf(stderr, "[error] unknown register type\n"); - ret = -EINVAL; - goto end; - - case REG_STRING: - fprintf(stderr, "[error] Unary plus can only be applied to numeric or floating point registers\n"); - ret = -EINVAL; - goto end; - case REG_S64: - break; - case REG_DOUBLE: - break; - } next_pc += sizeof(struct unary_op); break; } @@ -623,20 +567,14 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct unary_op *insn = (struct unary_op *) pc; - if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", - (unsigned int) insn->reg); - ret = -EINVAL; - goto end; - } switch (reg[insn->reg].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; case REG_STRING: - fprintf(stderr, "[error] Unary minus can only be applied to numeric or floating point registers\n"); + ERR("Unary minus can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; case REG_S64: @@ -653,20 +591,14 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct unary_op *insn = (struct unary_op *) pc; - if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", - (unsigned int) insn->reg); - ret = -EINVAL; - goto end; - } switch (reg[insn->reg].type) { default: - fprintf(stderr, "[error] unknown register type\n"); + ERR("unknown register type\n"); ret = -EINVAL; goto end; case REG_STRING: - fprintf(stderr, "[error] Unary not can only be applied to numeric or floating point registers\n"); + ERR("Unary not can only be applied to numeric or floating point registers\n"); ret = -EINVAL; goto end; case REG_S64: @@ -676,11 +608,6 @@ int lttng_filter_interpret_bytecode(void *filter_data, reg[insn->reg].d = !reg[insn->reg].d; break; } - if (unlikely(reg[insn->reg].type != REG_S64)) { - fprintf(stderr, "[error] Unary not can only be applied to numeric register\n"); - ret = -EINVAL; - goto end; - } reg[insn->reg].v = !reg[insn->reg].v; next_pc += sizeof(struct unary_op); break; @@ -690,23 +617,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct logical_op *insn = (struct logical_op *) pc; - if (unlikely(reg[REG_R0].type == REG_STRING)) { - fprintf(stderr, "[error] Logical operator 'and' can only be applied to numeric and floating point registers\n"); - ret = -EINVAL; - goto end; - } - /* If REG_R0 is 0, skip and evaluate to 0 */ if ((reg[REG_R0].type == REG_S64 && reg[REG_R0].v == 0) || (reg[REG_R0].type == REG_DOUBLE && reg[REG_R0].d == 0.0)) { dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); next_pc = start_pc + insn->skip_offset; - if (unlikely(next_pc <= pc)) { - fprintf(stderr, "[error] Loops are not allowed in bytecode\n"); - ret = -EINVAL; - goto end; - } } else { next_pc += sizeof(struct logical_op); } @@ -716,12 +632,6 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct logical_op *insn = (struct logical_op *) pc; - if (unlikely(reg[REG_R0].type == REG_STRING)) { - fprintf(stderr, "[error] Logical operator 'or' can only be applied to numeric and floating point registers\n"); - ret = -EINVAL; - goto end; - } - /* If REG_R0 is nonzero, skip and evaluate to 1 */ if ((reg[REG_R0].type == REG_S64 && reg[REG_R0].v != 0) @@ -730,11 +640,6 @@ int lttng_filter_interpret_bytecode(void *filter_data, dbg_printf("Jumping to bytecode offset %u\n", (unsigned int) insn->skip_offset); next_pc = start_pc + insn->skip_offset; - if (unlikely(next_pc <= pc)) { - fprintf(stderr, "[error] Loops are not allowed in bytecode\n"); - ret = -EINVAL; - goto end; - } } else { next_pc += sizeof(struct logical_op); } @@ -747,18 +652,12 @@ int lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; struct field_ref *ref = (struct field_ref *) insn->data; - if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", - (unsigned int) insn->reg); - ret = -EINVAL; - goto end; - } dbg_printf("load field ref offset %u type %u\n", ref->offset, ref->type); switch (ref->type) { case FIELD_REF_UNKNOWN: default: - fprintf(stderr, "[error] unknown field ref type\n"); + ERR("unknown field ref type\n"); ret = -EINVAL; goto end; @@ -803,16 +702,308 @@ int lttng_filter_interpret_bytecode(void *filter_data, { struct load_op *insn = (struct load_op *) pc; + dbg_printf("load string %s\n", insn->data); + reg[insn->reg].str = insn->data; + reg[insn->reg].type = REG_STRING; + reg[insn->reg].seq_len = UINT_MAX; + reg[insn->reg].literal = 1; + next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; + break; + } + + case FILTER_OP_LOAD_S64: + { + struct load_op *insn = (struct load_op *) pc; + + memcpy(®[insn->reg].v, insn->data, + sizeof(struct literal_numeric)); + dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v); + reg[insn->reg].type = REG_S64; + next_pc += sizeof(struct load_op) + + sizeof(struct literal_numeric); + break; + } + + case FILTER_OP_LOAD_DOUBLE: + { + struct load_op *insn = (struct load_op *) pc; + + memcpy(®[insn->reg].d, insn->data, + sizeof(struct literal_double)); + dbg_printf("load s64 %g\n", reg[insn->reg].d); + reg[insn->reg].type = REG_DOUBLE; + next_pc += sizeof(struct load_op) + + sizeof(struct literal_double); + break; + } + } + } +end: + /* return 0 (discard) on error */ + if (ret) + return 0; + return retval; +} + +static +int bin_op_compare_check(struct vreg reg[NR_REG], const char *str) +{ + switch (reg[REG_R0].type) { + default: + goto error_unknown; + + case REG_STRING: + switch (reg[REG_R1].type) { + default: + goto error_unknown; + + case REG_STRING: + break; + case REG_S64: + case REG_DOUBLE: + goto error_mismatch; + } + break; + case REG_S64: + case REG_DOUBLE: + switch (reg[REG_R1].type) { + default: + goto error_unknown; + + case REG_STRING: + goto error_mismatch; + + case REG_S64: + case REG_DOUBLE: + break; + } + break; + } + return 0; + +error_unknown: + + return -EINVAL; +error_mismatch: + ERR("type mismatch for '%s' binary operator\n", str); + return -EINVAL; +} + +static +int lttng_filter_validate_bytecode(struct bytecode_runtime *bytecode) +{ + void *pc, *next_pc, *start_pc; + int ret = -EINVAL; + struct vreg reg[NR_REG]; + int i; + + for (i = 0; i < NR_REG; i++) { + reg[i].type = REG_S64; + reg[i].literal = 0; + } + + start_pc = &bytecode->data[0]; + for (pc = next_pc = start_pc; pc - start_pc < bytecode->len; + pc = next_pc) { + if (unlikely(pc >= start_pc + bytecode->len)) { + ERR("filter bytecode overflow\n"); + ret = -EINVAL; + goto end; + } + dbg_printf("Validating op %s (%u)\n", + print_op((unsigned int) *(filter_opcode_t *) pc), + (unsigned int) *(filter_opcode_t *) pc); + switch (*(filter_opcode_t *) pc) { + case FILTER_OP_UNKNOWN: + default: + ERR("unknown bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + ret = -EINVAL; + goto end; + + case FILTER_OP_RETURN: + ret = 0; + goto end; + + /* binary */ + case FILTER_OP_MUL: + case FILTER_OP_DIV: + case FILTER_OP_MOD: + case FILTER_OP_PLUS: + case FILTER_OP_MINUS: + case FILTER_OP_RSHIFT: + case FILTER_OP_LSHIFT: + case FILTER_OP_BIN_AND: + case FILTER_OP_BIN_OR: + case FILTER_OP_BIN_XOR: + ERR("unsupported bytecode op %u\n", + (unsigned int) *(filter_opcode_t *) pc); + ret = -EINVAL; + goto end; + + case FILTER_OP_EQ: + { + ret = bin_op_compare_check(reg, "=="); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_NE: + { + ret = bin_op_compare_check(reg, "!="); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_GT: + { + ret = bin_op_compare_check(reg, ">"); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_LT: + { + ret = bin_op_compare_check(reg, "<"); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_GE: + { + ret = bin_op_compare_check(reg, ">="); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + case FILTER_OP_LE: + { + ret = bin_op_compare_check(reg, "<="); + if (ret) + goto end; + reg[REG_R0].type = REG_S64; + next_pc += sizeof(struct binary_op); + break; + } + + /* unary */ + case FILTER_OP_UNARY_PLUS: + case FILTER_OP_UNARY_MINUS: + case FILTER_OP_UNARY_NOT: + { + struct unary_op *insn = (struct unary_op *) pc; + if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", + ERR("invalid register %u\n", + (unsigned int) insn->reg); + ret = -EINVAL; + goto end; + } + switch (reg[insn->reg].type) { + default: + ERR("unknown register type\n"); + ret = -EINVAL; + goto end; + + case REG_STRING: + ERR("Unary op can only be applied to numeric or floating point registers\n"); + ret = -EINVAL; + goto end; + case REG_S64: + break; + case REG_DOUBLE: + break; + } + next_pc += sizeof(struct unary_op); + break; + } + /* logical */ + case FILTER_OP_AND: + case FILTER_OP_OR: + { + struct logical_op *insn = (struct logical_op *) pc; + + if (unlikely(reg[REG_R0].type == REG_STRING)) { + ERR("Logical operator 'and' can only be applied to numeric and floating point registers\n"); + ret = -EINVAL; + goto end; + } + + dbg_printf("Validate jumping to bytecode offset %u\n", + (unsigned int) insn->skip_offset); + if (unlikely(start_pc + insn->skip_offset <= pc)) { + ERR("Loops are not allowed in bytecode\n"); + ret = -EINVAL; + goto end; + } + next_pc += sizeof(struct logical_op); + break; + } + + /* load */ + case FILTER_OP_LOAD_FIELD_REF: + { + struct load_op *insn = (struct load_op *) pc; + struct field_ref *ref = (struct field_ref *) insn->data; + + if (unlikely(insn->reg >= REG_ERROR)) { + ERR("invalid register %u\n", + (unsigned int) insn->reg); + ret = -EINVAL; + goto end; + } + dbg_printf("Validate load field ref offset %u type %u\n", + ref->offset, ref->type); + switch (ref->type) { + case FIELD_REF_UNKNOWN: + default: + ERR("unknown field ref type\n"); + ret = -EINVAL; + goto end; + + case FIELD_REF_STRING: + reg[insn->reg].type = REG_STRING; + reg[insn->reg].literal = 0; + break; + case FIELD_REF_SEQUENCE: + reg[insn->reg].type = REG_STRING; + reg[insn->reg].literal = 0; + break; + case FIELD_REF_S64: + reg[insn->reg].type = REG_S64; + reg[insn->reg].literal = 0; + break; + case FIELD_REF_DOUBLE: + reg[insn->reg].type = REG_DOUBLE; + reg[insn->reg].literal = 0; + break; + } + + next_pc += sizeof(struct load_op) + sizeof(struct field_ref); + break; + } + + case FILTER_OP_LOAD_STRING: + { + struct load_op *insn = (struct load_op *) pc; + + if (unlikely(insn->reg >= REG_ERROR)) { + ERR("invalid register %u\n", (unsigned int) insn->reg); ret = -EINVAL; goto end; } - dbg_printf("load string %s\n", insn->data); - reg[insn->reg].str = insn->data; reg[insn->reg].type = REG_STRING; - reg[insn->reg].seq_len = UINT_MAX; reg[insn->reg].literal = 1; next_pc += sizeof(struct load_op) + strlen(insn->data) + 1; break; @@ -823,14 +1014,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", + ERR("invalid register %u\n", (unsigned int) insn->reg); ret = -EINVAL; goto end; } - memcpy(®[insn->reg].v, insn->data, - sizeof(struct literal_numeric)); - dbg_printf("load s64 %" PRIi64 "\n", reg[insn->reg].v); reg[insn->reg].type = REG_S64; next_pc += sizeof(struct load_op) + sizeof(struct literal_numeric); @@ -842,14 +1030,11 @@ int lttng_filter_interpret_bytecode(void *filter_data, struct load_op *insn = (struct load_op *) pc; if (unlikely(insn->reg >= REG_ERROR)) { - fprintf(stderr, "[error] invalid register %u\n", + ERR("invalid register %u\n", (unsigned int) insn->reg); ret = -EINVAL; goto end; } - memcpy(®[insn->reg].d, insn->data, - sizeof(struct literal_double)); - dbg_printf("load s64 %g\n", reg[insn->reg].d); reg[insn->reg].type = REG_DOUBLE; next_pc += sizeof(struct load_op) + sizeof(struct literal_double); @@ -858,10 +1043,7 @@ int lttng_filter_interpret_bytecode(void *filter_data, } } end: - /* return 0 (discard) on error */ - if (ret) - return 0; - return retval; + return ret; } static @@ -1001,6 +1183,11 @@ int _lttng_filter_event_link_bytecode(struct ltt_event *event, } next_offset = offset + sizeof(uint16_t) + strlen(field_name) + 1; } + /* Validate bytecode */ + ret = lttng_filter_validate_bytecode(runtime); + if (ret) { + goto link_error; + } event->filter_data = runtime; event->filter = lttng_filter_interpret_bytecode; return 0;