2 * lttng-filter-validator.c
4 * LTTng UST filter bytecode validator.
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #include "lttng-filter.h"
28 #include <urcu/rculfhash.h>
29 #include "lttng-hash-helper.h"
31 /* merge point table node */
33 struct cds_lfht_node node
;
35 /* Context at merge point */
36 struct vreg reg
[NR_REG
];
37 unsigned long target_pc
;
40 static unsigned long lttng_hash_seed
;
41 static unsigned int lttng_hash_seed_ready
;
44 int lttng_hash_match(struct cds_lfht_node
*node
, const void *key
)
46 struct lfht_mp_node
*mp_node
=
47 caa_container_of(node
, struct lfht_mp_node
, node
);
48 unsigned long key_pc
= (unsigned long) key
;
50 if (mp_node
->target_pc
== key_pc
)
57 int merge_point_add(struct cds_lfht
*ht
, unsigned long target_pc
,
58 const struct vreg reg
[NR_REG
])
60 struct lfht_mp_node
*node
;
61 unsigned long hash
= lttng_hash_mix((const void *) target_pc
,
65 dbg_printf("Filter: adding merge point at offset %lu, hash %lu\n",
67 node
= zmalloc(sizeof(struct lfht_mp_node
));
70 node
->target_pc
= target_pc
;
71 memcpy(node
->reg
, reg
, sizeof(node
->reg
));
72 cds_lfht_add(ht
, hash
, &node
->node
);
77 * Number of merge points for hash table size. Hash table initialized to
78 * that size, and we do not resize, because we do not want to trigger
79 * RCU worker thread execution: fall-back on linear traversal if number
80 * of merge points exceeds this value.
82 #define DEFAULT_NR_MERGE_POINTS 128
83 #define MIN_NR_BUCKETS 128
84 #define MAX_NR_BUCKETS 128
87 int bin_op_compare_check(const struct vreg reg
[NR_REG
], const char *str
)
89 switch (reg
[REG_R0
].type
) {
94 switch (reg
[REG_R1
].type
) {
107 switch (reg
[REG_R1
].type
) {
126 ERR("type mismatch for '%s' binary operator\n", str
);
131 * Validate bytecode range overflow within the validation pass.
132 * Called for each instruction encountered.
135 int bytecode_validate_overflow(struct bytecode_runtime
*bytecode
,
136 void *start_pc
, void *pc
)
140 switch (*(filter_opcode_t
*) pc
) {
141 case FILTER_OP_UNKNOWN
:
144 ERR("unknown bytecode op %u\n",
145 (unsigned int) *(filter_opcode_t
*) pc
);
150 case FILTER_OP_RETURN
:
152 if (unlikely(pc
+ sizeof(struct return_op
)
153 > start_pc
+ bytecode
->len
)) {
164 case FILTER_OP_MINUS
:
165 case FILTER_OP_RSHIFT
:
166 case FILTER_OP_LSHIFT
:
167 case FILTER_OP_BIN_AND
:
168 case FILTER_OP_BIN_OR
:
169 case FILTER_OP_BIN_XOR
:
171 ERR("unsupported bytecode op %u\n",
172 (unsigned int) *(filter_opcode_t
*) pc
);
183 case FILTER_OP_EQ_STRING
:
184 case FILTER_OP_NE_STRING
:
185 case FILTER_OP_GT_STRING
:
186 case FILTER_OP_LT_STRING
:
187 case FILTER_OP_GE_STRING
:
188 case FILTER_OP_LE_STRING
:
189 case FILTER_OP_EQ_S64
:
190 case FILTER_OP_NE_S64
:
191 case FILTER_OP_GT_S64
:
192 case FILTER_OP_LT_S64
:
193 case FILTER_OP_GE_S64
:
194 case FILTER_OP_LE_S64
:
195 case FILTER_OP_EQ_DOUBLE
:
196 case FILTER_OP_NE_DOUBLE
:
197 case FILTER_OP_GT_DOUBLE
:
198 case FILTER_OP_LT_DOUBLE
:
199 case FILTER_OP_GE_DOUBLE
:
200 case FILTER_OP_LE_DOUBLE
:
202 if (unlikely(pc
+ sizeof(struct binary_op
)
203 > start_pc
+ bytecode
->len
)) {
210 case FILTER_OP_UNARY_PLUS
:
211 case FILTER_OP_UNARY_MINUS
:
212 case FILTER_OP_UNARY_NOT
:
213 case FILTER_OP_UNARY_PLUS_S64
:
214 case FILTER_OP_UNARY_MINUS_S64
:
215 case FILTER_OP_UNARY_NOT_S64
:
216 case FILTER_OP_UNARY_PLUS_DOUBLE
:
217 case FILTER_OP_UNARY_MINUS_DOUBLE
:
218 case FILTER_OP_UNARY_NOT_DOUBLE
:
220 if (unlikely(pc
+ sizeof(struct unary_op
)
221 > start_pc
+ bytecode
->len
)) {
231 if (unlikely(pc
+ sizeof(struct logical_op
)
232 > start_pc
+ bytecode
->len
)) {
239 case FILTER_OP_LOAD_FIELD_REF
:
241 ERR("Unknown field ref type\n");
245 case FILTER_OP_LOAD_FIELD_REF_STRING
:
246 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
247 case FILTER_OP_LOAD_FIELD_REF_S64
:
248 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
250 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct field_ref
)
251 > start_pc
+ bytecode
->len
)) {
257 case FILTER_OP_LOAD_STRING
:
259 struct load_op
*insn
= (struct load_op
*) pc
;
260 uint32_t str_len
, maxlen
;
262 if (unlikely(pc
+ sizeof(struct load_op
)
263 > start_pc
+ bytecode
->len
)) {
268 maxlen
= start_pc
+ bytecode
->len
- pc
- sizeof(struct load_op
);
269 str_len
= strnlen(insn
->data
, maxlen
);
270 if (unlikely(str_len
>= maxlen
)) {
271 /* Final '\0' not found within range */
277 case FILTER_OP_LOAD_S64
:
279 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_numeric
)
280 > start_pc
+ bytecode
->len
)) {
286 case FILTER_OP_LOAD_DOUBLE
:
288 if (unlikely(pc
+ sizeof(struct load_op
) + sizeof(struct literal_double
)
289 > start_pc
+ bytecode
->len
)) {
295 case FILTER_OP_CAST_TO_S64
:
296 case FILTER_OP_CAST_DOUBLE_TO_S64
:
297 case FILTER_OP_CAST_NOP
:
299 if (unlikely(pc
+ sizeof(struct cast_op
)
300 > start_pc
+ bytecode
->len
)) {
311 unsigned long delete_all_nodes(struct cds_lfht
*ht
)
313 struct cds_lfht_iter iter
;
314 struct lfht_mp_node
*node
;
315 unsigned long nr_nodes
= 0;
317 cds_lfht_for_each_entry(ht
, &iter
, node
, node
) {
320 ret
= cds_lfht_del(ht
, cds_lfht_iter_get_node(&iter
));
322 /* note: this hash table is never used concurrently */
335 int validate_instruction_context(struct bytecode_runtime
*bytecode
,
336 const struct vreg reg
[NR_REG
],
342 switch (*(filter_opcode_t
*) pc
) {
343 case FILTER_OP_UNKNOWN
:
346 ERR("unknown bytecode op %u\n",
347 (unsigned int) *(filter_opcode_t
*) pc
);
352 case FILTER_OP_RETURN
:
362 case FILTER_OP_MINUS
:
363 case FILTER_OP_RSHIFT
:
364 case FILTER_OP_LSHIFT
:
365 case FILTER_OP_BIN_AND
:
366 case FILTER_OP_BIN_OR
:
367 case FILTER_OP_BIN_XOR
:
369 ERR("unsupported bytecode op %u\n",
370 (unsigned int) *(filter_opcode_t
*) pc
);
377 ret
= bin_op_compare_check(reg
, "==");
384 ret
= bin_op_compare_check(reg
, "!=");
391 ret
= bin_op_compare_check(reg
, ">");
398 ret
= bin_op_compare_check(reg
, "<");
405 ret
= bin_op_compare_check(reg
, ">=");
412 ret
= bin_op_compare_check(reg
, "<=");
418 case FILTER_OP_EQ_STRING
:
419 case FILTER_OP_NE_STRING
:
420 case FILTER_OP_GT_STRING
:
421 case FILTER_OP_LT_STRING
:
422 case FILTER_OP_GE_STRING
:
423 case FILTER_OP_LE_STRING
:
425 if (reg
[REG_R0
].type
!= REG_STRING
426 || reg
[REG_R1
].type
!= REG_STRING
) {
427 ERR("Unexpected register type for string comparator\n");
434 case FILTER_OP_EQ_S64
:
435 case FILTER_OP_NE_S64
:
436 case FILTER_OP_GT_S64
:
437 case FILTER_OP_LT_S64
:
438 case FILTER_OP_GE_S64
:
439 case FILTER_OP_LE_S64
:
441 if (reg
[REG_R0
].type
!= REG_S64
442 || reg
[REG_R1
].type
!= REG_S64
) {
443 ERR("Unexpected register type for s64 comparator\n");
450 case FILTER_OP_EQ_DOUBLE
:
451 case FILTER_OP_NE_DOUBLE
:
452 case FILTER_OP_GT_DOUBLE
:
453 case FILTER_OP_LT_DOUBLE
:
454 case FILTER_OP_GE_DOUBLE
:
455 case FILTER_OP_LE_DOUBLE
:
457 if ((reg
[REG_R0
].type
!= REG_DOUBLE
&& reg
[REG_R0
].type
!= REG_S64
)
458 || (reg
[REG_R1
].type
!= REG_DOUBLE
&& reg
[REG_R1
].type
!= REG_S64
)) {
459 ERR("Unexpected register type for double comparator\n");
463 if (reg
[REG_R0
].type
!= REG_DOUBLE
&& reg
[REG_R1
].type
!= REG_DOUBLE
) {
464 ERR("Double operator should have at least one double register\n");
472 case FILTER_OP_UNARY_PLUS
:
473 case FILTER_OP_UNARY_MINUS
:
474 case FILTER_OP_UNARY_NOT
:
476 struct unary_op
*insn
= (struct unary_op
*) pc
;
478 if (unlikely(insn
->reg
>= REG_ERROR
)) {
479 ERR("invalid register %u\n",
480 (unsigned int) insn
->reg
);
484 switch (reg
[insn
->reg
].type
) {
486 ERR("unknown register type\n");
491 ERR("Unary op can only be applied to numeric or floating point registers\n");
502 case FILTER_OP_UNARY_PLUS_S64
:
503 case FILTER_OP_UNARY_MINUS_S64
:
504 case FILTER_OP_UNARY_NOT_S64
:
506 struct unary_op
*insn
= (struct unary_op
*) pc
;
508 if (unlikely(insn
->reg
>= REG_ERROR
)) {
509 ERR("invalid register %u\n",
510 (unsigned int) insn
->reg
);
514 if (reg
[insn
->reg
].type
!= REG_S64
) {
515 ERR("Invalid register type\n");
522 case FILTER_OP_UNARY_PLUS_DOUBLE
:
523 case FILTER_OP_UNARY_MINUS_DOUBLE
:
524 case FILTER_OP_UNARY_NOT_DOUBLE
:
526 struct unary_op
*insn
= (struct unary_op
*) pc
;
528 if (unlikely(insn
->reg
>= REG_ERROR
)) {
529 ERR("invalid register %u\n",
530 (unsigned int) insn
->reg
);
534 if (reg
[insn
->reg
].type
!= REG_DOUBLE
) {
535 ERR("Invalid register type\n");
546 struct logical_op
*insn
= (struct logical_op
*) pc
;
548 if (reg
[REG_R0
].type
!= REG_S64
) {
549 ERR("Logical comparator expects S64 register\n");
554 dbg_printf("Validate jumping to bytecode offset %u\n",
555 (unsigned int) insn
->skip_offset
);
556 if (unlikely(start_pc
+ insn
->skip_offset
<= pc
)) {
557 ERR("Loops are not allowed in bytecode\n");
565 case FILTER_OP_LOAD_FIELD_REF
:
567 ERR("Unknown field ref type\n");
571 case FILTER_OP_LOAD_FIELD_REF_STRING
:
572 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
574 struct load_op
*insn
= (struct load_op
*) pc
;
575 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
577 if (unlikely(insn
->reg
>= REG_ERROR
)) {
578 ERR("invalid register %u\n",
579 (unsigned int) insn
->reg
);
583 dbg_printf("Validate load field ref offset %u type string\n",
587 case FILTER_OP_LOAD_FIELD_REF_S64
:
589 struct load_op
*insn
= (struct load_op
*) pc
;
590 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
592 if (unlikely(insn
->reg
>= REG_ERROR
)) {
593 ERR("invalid register %u\n",
594 (unsigned int) insn
->reg
);
598 dbg_printf("Validate load field ref offset %u type s64\n",
602 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
604 struct load_op
*insn
= (struct load_op
*) pc
;
605 struct field_ref
*ref
= (struct field_ref
*) insn
->data
;
607 if (unlikely(insn
->reg
>= REG_ERROR
)) {
608 ERR("invalid register %u\n",
609 (unsigned int) insn
->reg
);
613 dbg_printf("Validate load field ref offset %u type double\n",
618 case FILTER_OP_LOAD_STRING
:
620 struct load_op
*insn
= (struct load_op
*) pc
;
622 if (unlikely(insn
->reg
>= REG_ERROR
)) {
623 ERR("invalid register %u\n",
624 (unsigned int) insn
->reg
);
631 case FILTER_OP_LOAD_S64
:
633 struct load_op
*insn
= (struct load_op
*) pc
;
635 if (unlikely(insn
->reg
>= REG_ERROR
)) {
636 ERR("invalid register %u\n",
637 (unsigned int) insn
->reg
);
644 case FILTER_OP_LOAD_DOUBLE
:
646 struct load_op
*insn
= (struct load_op
*) pc
;
648 if (unlikely(insn
->reg
>= REG_ERROR
)) {
649 ERR("invalid register %u\n",
650 (unsigned int) insn
->reg
);
657 case FILTER_OP_CAST_TO_S64
:
658 case FILTER_OP_CAST_DOUBLE_TO_S64
:
660 struct cast_op
*insn
= (struct cast_op
*) pc
;
662 if (unlikely(insn
->reg
>= REG_ERROR
)) {
663 ERR("invalid register %u\n",
664 (unsigned int) insn
->reg
);
668 switch (reg
[insn
->reg
].type
) {
670 ERR("unknown register type\n");
675 ERR("Cast op can only be applied to numeric or floating point registers\n");
683 if (insn
->op
== FILTER_OP_CAST_DOUBLE_TO_S64
) {
684 if (reg
[insn
->reg
].type
!= REG_DOUBLE
) {
685 ERR("Cast expects double\n");
692 case FILTER_OP_CAST_NOP
:
708 int validate_instruction_all_contexts(struct bytecode_runtime
*bytecode
,
709 struct cds_lfht
*merge_points
,
710 const struct vreg reg
[NR_REG
],
715 unsigned long target_pc
= pc
- start_pc
;
716 struct cds_lfht_iter iter
;
717 struct cds_lfht_node
*node
;
720 /* Validate the context resulting from the previous instruction */
721 ret
= validate_instruction_context(bytecode
, reg
, start_pc
, pc
);
725 /* Validate merge points */
726 hash
= lttng_hash_mix((const void *) target_pc
, sizeof(target_pc
),
728 cds_lfht_for_each_duplicate(merge_points
, hash
, lttng_hash_match
,
729 (const void *) target_pc
, &iter
, node
) {
730 struct lfht_mp_node
*mp_node
=
731 caa_container_of(node
, struct lfht_mp_node
, node
);
733 dbg_printf("Filter: validate merge point at offset %lu\n",
735 ret
= validate_instruction_context(bytecode
, mp_node
->reg
,
739 /* Once validated, we can remove the merge point */
740 dbg_printf("Filter: remove one merge point at offset %lu\n",
742 ret
= cds_lfht_del(merge_points
, node
);
750 * >0: going to next insn.
751 * 0: success, stop iteration.
755 int exec_insn(struct bytecode_runtime
*bytecode
,
756 struct cds_lfht
*merge_points
,
757 struct vreg reg
[NR_REG
],
762 void *next_pc
= *_next_pc
;
764 switch (*(filter_opcode_t
*) pc
) {
765 case FILTER_OP_UNKNOWN
:
768 ERR("unknown bytecode op %u\n",
769 (unsigned int) *(filter_opcode_t
*) pc
);
774 case FILTER_OP_RETURN
:
785 case FILTER_OP_MINUS
:
786 case FILTER_OP_RSHIFT
:
787 case FILTER_OP_LSHIFT
:
788 case FILTER_OP_BIN_AND
:
789 case FILTER_OP_BIN_OR
:
790 case FILTER_OP_BIN_XOR
:
792 ERR("unsupported bytecode op %u\n",
793 (unsigned int) *(filter_opcode_t
*) pc
);
804 case FILTER_OP_EQ_STRING
:
805 case FILTER_OP_NE_STRING
:
806 case FILTER_OP_GT_STRING
:
807 case FILTER_OP_LT_STRING
:
808 case FILTER_OP_GE_STRING
:
809 case FILTER_OP_LE_STRING
:
810 case FILTER_OP_EQ_S64
:
811 case FILTER_OP_NE_S64
:
812 case FILTER_OP_GT_S64
:
813 case FILTER_OP_LT_S64
:
814 case FILTER_OP_GE_S64
:
815 case FILTER_OP_LE_S64
:
816 case FILTER_OP_EQ_DOUBLE
:
817 case FILTER_OP_NE_DOUBLE
:
818 case FILTER_OP_GT_DOUBLE
:
819 case FILTER_OP_LT_DOUBLE
:
820 case FILTER_OP_GE_DOUBLE
:
821 case FILTER_OP_LE_DOUBLE
:
823 reg
[REG_R0
].type
= REG_S64
;
824 next_pc
+= sizeof(struct binary_op
);
829 case FILTER_OP_UNARY_PLUS
:
830 case FILTER_OP_UNARY_MINUS
:
831 case FILTER_OP_UNARY_NOT
:
832 case FILTER_OP_UNARY_PLUS_S64
:
833 case FILTER_OP_UNARY_MINUS_S64
:
834 case FILTER_OP_UNARY_NOT_S64
:
836 reg
[REG_R0
].type
= REG_S64
;
837 next_pc
+= sizeof(struct unary_op
);
841 case FILTER_OP_UNARY_PLUS_DOUBLE
:
842 case FILTER_OP_UNARY_MINUS_DOUBLE
:
843 case FILTER_OP_UNARY_NOT_DOUBLE
:
845 reg
[REG_R0
].type
= REG_DOUBLE
;
846 next_pc
+= sizeof(struct unary_op
);
854 struct logical_op
*insn
= (struct logical_op
*) pc
;
857 /* Add merge point to table */
858 merge_ret
= merge_point_add(merge_points
, insn
->skip_offset
, reg
);
863 /* Continue to next instruction */
864 next_pc
+= sizeof(struct logical_op
);
869 case FILTER_OP_LOAD_FIELD_REF
:
871 ERR("Unknown field ref type\n");
875 case FILTER_OP_LOAD_FIELD_REF_STRING
:
876 case FILTER_OP_LOAD_FIELD_REF_SEQUENCE
:
878 struct load_op
*insn
= (struct load_op
*) pc
;
880 reg
[insn
->reg
].type
= REG_STRING
;
881 reg
[insn
->reg
].literal
= 0;
882 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
885 case FILTER_OP_LOAD_FIELD_REF_S64
:
887 struct load_op
*insn
= (struct load_op
*) pc
;
889 reg
[insn
->reg
].type
= REG_S64
;
890 reg
[insn
->reg
].literal
= 0;
891 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
894 case FILTER_OP_LOAD_FIELD_REF_DOUBLE
:
896 struct load_op
*insn
= (struct load_op
*) pc
;
898 reg
[insn
->reg
].type
= REG_DOUBLE
;
899 reg
[insn
->reg
].literal
= 0;
900 next_pc
+= sizeof(struct load_op
) + sizeof(struct field_ref
);
904 case FILTER_OP_LOAD_STRING
:
906 struct load_op
*insn
= (struct load_op
*) pc
;
908 reg
[insn
->reg
].type
= REG_STRING
;
909 reg
[insn
->reg
].literal
= 1;
910 next_pc
+= sizeof(struct load_op
) + strlen(insn
->data
) + 1;
914 case FILTER_OP_LOAD_S64
:
916 struct load_op
*insn
= (struct load_op
*) pc
;
918 reg
[insn
->reg
].type
= REG_S64
;
919 reg
[insn
->reg
].literal
= 1;
920 next_pc
+= sizeof(struct load_op
)
921 + sizeof(struct literal_numeric
);
925 case FILTER_OP_LOAD_DOUBLE
:
927 struct load_op
*insn
= (struct load_op
*) pc
;
929 reg
[insn
->reg
].type
= REG_DOUBLE
;
930 reg
[insn
->reg
].literal
= 1;
931 next_pc
+= sizeof(struct load_op
)
932 + sizeof(struct literal_double
);
936 case FILTER_OP_CAST_TO_S64
:
937 case FILTER_OP_CAST_DOUBLE_TO_S64
:
939 struct cast_op
*insn
= (struct cast_op
*) pc
;
941 reg
[insn
->reg
].type
= REG_S64
;
942 next_pc
+= sizeof(struct cast_op
);
945 case FILTER_OP_CAST_NOP
:
947 next_pc
+= sizeof(struct cast_op
);
958 * Never called concurrently (hash seed is shared).
960 int lttng_filter_validate_bytecode(struct bytecode_runtime
*bytecode
)
962 struct cds_lfht
*merge_points
;
963 void *pc
, *next_pc
, *start_pc
;
965 struct vreg reg
[NR_REG
];
968 for (i
= 0; i
< NR_REG
; i
++) {
969 reg
[i
].type
= REG_TYPE_UNKNOWN
;
973 if (!lttng_hash_seed_ready
) {
974 lttng_hash_seed
= time(NULL
);
975 lttng_hash_seed_ready
= 1;
978 * Note: merge_points hash table used by single thread, and
979 * never concurrently resized. Therefore, we can use it without
980 * holding RCU read-side lock and free nodes without using
983 merge_points
= cds_lfht_new(DEFAULT_NR_MERGE_POINTS
,
984 MIN_NR_BUCKETS
, MAX_NR_BUCKETS
,
987 ERR("Error allocating hash table for bytecode validation\n");
990 start_pc
= &bytecode
->data
[0];
991 for (pc
= next_pc
= start_pc
; pc
- start_pc
< bytecode
->len
;
993 if (bytecode_validate_overflow(bytecode
, start_pc
, pc
) != 0) {
994 ERR("filter bytecode overflow\n");
998 dbg_printf("Validating op %s (%u)\n",
999 print_op((unsigned int) *(filter_opcode_t
*) pc
),
1000 (unsigned int) *(filter_opcode_t
*) pc
);
1003 * For each instruction, validate the current context
1004 * (traversal of entire execution flow), and validate
1005 * all merge points targeting this instruction.
1007 ret
= validate_instruction_all_contexts(bytecode
, merge_points
,
1011 ret
= exec_insn(bytecode
, merge_points
, reg
, &next_pc
, pc
);
1016 if (delete_all_nodes(merge_points
)) {
1018 ERR("Unexpected merge points\n");
1022 if (cds_lfht_destroy(merge_points
, NULL
)) {
1023 ERR("Error destroying hash table\n");