assert-pre-internal.h: add BT_ASSERT_PRE_VALID_INDEX()
[babeltrace.git] / lib / ctf-ir / validation.c
1 /*
2 * validation.c
3 *
4 * Babeltrace - CTF IR: Validation of trace, stream class, and event class
5 *
6 * Copyright 2016-2018 Philippe Proulx <pproulx@efficios.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
27 #define BT_LOG_TAG "VALIDATION"
28 #include <babeltrace/lib-logging-internal.h>
29
30 #include <babeltrace/assert-pre-internal.h>
31 #include <babeltrace/ctf-ir/validation-internal.h>
32 #include <babeltrace/ctf-ir/resolve-internal.h>
33 #include <babeltrace/ctf-ir/trace-internal.h>
34 #include <babeltrace/ctf-ir/stream-class-internal.h>
35 #include <babeltrace/ctf-ir/field-types-internal.h>
36 #include <babeltrace/ctf-ir/event-class-internal.h>
37 #include <babeltrace/ctf-ir/field-types-internal.h>
38 #include <babeltrace/values.h>
39 #include <babeltrace/babeltrace-internal.h>
40 #include <babeltrace/ref.h>
41
42 /*
43 * This function resolves and validates the field types of an event
44 * class. Only `event_context_type` and `event_payload_type` are
45 * resolved and validated; the other field types are used as eventual
46 * resolving targets.
47 *
48 * All parameters are owned by the caller.
49 */
50 static
51 int validate_event_class_types(struct bt_value *environment,
52 struct bt_field_type *packet_header_type,
53 struct bt_field_type *packet_context_type,
54 struct bt_field_type *event_header_type,
55 struct bt_field_type *stream_event_ctx_type,
56 struct bt_field_type *event_context_type,
57 struct bt_field_type *event_payload_type)
58 {
59 int ret = 0;
60
61 BT_LOGV("Validating event class field types: "
62 "packet-header-ft-addr=%p, "
63 "packet-context-ft-addr=%p, "
64 "event-header-ft-addr=%p, "
65 "stream-event-context-ft-addr=%p, "
66 "event-context-ft-addr=%p, "
67 "event-payload-ft-addr=%p",
68 packet_header_type, packet_context_type, event_header_type,
69 stream_event_ctx_type, event_context_type, event_payload_type);
70
71 /* Resolve sequence type lengths and variant type tags first */
72 ret = bt_resolve_types(environment, packet_header_type,
73 packet_context_type, event_header_type, stream_event_ctx_type,
74 event_context_type, event_payload_type,
75 BT_RESOLVE_FLAG_EVENT_CONTEXT |
76 BT_RESOLVE_FLAG_EVENT_PAYLOAD);
77 if (ret) {
78 BT_LOGW("Cannot resolve event class field types: ret=%d",
79 ret);
80 goto end;
81 }
82
83 /* Validate field types individually */
84 if (event_context_type) {
85 ret = bt_field_type_validate(event_context_type);
86 if (ret) {
87 BT_LOGW("Invalid event class's context field type: "
88 "ret=%d", ret);
89 goto end;
90 }
91 }
92
93 if (event_payload_type) {
94 ret = bt_field_type_validate(event_payload_type);
95 if (ret) {
96 BT_LOGW("Invalid event class's payload field type: "
97 "ret=%d", ret);
98 goto end;
99 }
100 }
101
102 end:
103 return ret;
104 }
105
106 /*
107 * This function resolves and validates the field types of a stream
108 * class. Only `packet_context_type`, `event_header_type`, and
109 * `stream_event_ctx_type` are resolved and validated; the other field
110 * type is used as an eventual resolving target.
111 *
112 * All parameters are owned by the caller.
113 */
114 static
115 int validate_stream_class_types(struct bt_value *environment,
116 struct bt_field_type *packet_header_type,
117 struct bt_field_type *packet_context_type,
118 struct bt_field_type *event_header_type,
119 struct bt_field_type *stream_event_ctx_type)
120 {
121 int ret = 0;
122
123 BT_LOGV("Validating stream class field types: "
124 "packet-header-ft-addr=%p, "
125 "packet-context-ft-addr=%p, "
126 "event-header-ft-addr=%p, "
127 "stream-event-context-ft-addr=%p",
128 packet_header_type, packet_context_type, event_header_type,
129 stream_event_ctx_type);
130
131 /* Resolve sequence type lengths and variant type tags first */
132 ret = bt_resolve_types(environment, packet_header_type,
133 packet_context_type, event_header_type, stream_event_ctx_type,
134 NULL, NULL,
135 BT_RESOLVE_FLAG_PACKET_CONTEXT |
136 BT_RESOLVE_FLAG_EVENT_HEADER |
137 BT_RESOLVE_FLAG_STREAM_EVENT_CTX);
138 if (ret) {
139 BT_LOGW("Cannot resolve stream class field types: ret=%d",
140 ret);
141 goto end;
142 }
143
144 /* Validate field types individually */
145 if (packet_context_type) {
146 ret = bt_field_type_validate(packet_context_type);
147 if (ret) {
148 BT_LOGW("Invalid stream class's packet context field type: "
149 "ret=%d", ret);
150 goto end;
151 }
152 }
153
154 if (event_header_type) {
155 ret = bt_field_type_validate(event_header_type);
156 if (ret) {
157 BT_LOGW("Invalid stream class's event header field type: "
158 "ret=%d", ret);
159 goto end;
160 }
161 }
162
163 if (stream_event_ctx_type) {
164 ret = bt_field_type_validate(
165 stream_event_ctx_type);
166 if (ret) {
167 BT_LOGW("Invalid stream class's event context field type: "
168 "ret=%d", ret);
169 goto end;
170 }
171 }
172
173 end:
174 return ret;
175 }
176
177 /*
178 * This function resolves and validates the field types of a trace.
179 *
180 * All parameters are owned by the caller.
181 */
182 static
183 int validate_trace_types(struct bt_value *environment,
184 struct bt_field_type *packet_header_type)
185 {
186 int ret = 0;
187
188 BT_LOGV("Validating event class field types: "
189 "packet-header-ft-addr=%p", packet_header_type);
190
191 /* Resolve sequence type lengths and variant type tags first */
192 ret = bt_resolve_types(environment, packet_header_type,
193 NULL, NULL, NULL, NULL, NULL,
194 BT_RESOLVE_FLAG_PACKET_HEADER);
195 if (ret) {
196 BT_LOGW("Cannot resolve trace field types: ret=%d",
197 ret);
198 goto end;
199 }
200
201 /* Validate field types individually */
202 if (packet_header_type) {
203 ret = bt_field_type_validate(packet_header_type);
204 if (ret) {
205 BT_LOGW("Invalid trace's packet header field type: "
206 "ret=%d", ret);
207 goto end;
208 }
209 }
210
211 end:
212 return ret;
213 }
214
215 /*
216 * Checks whether or not `field_type` contains a variant or a sequence
217 * field type, recursively. Returns 1 if it's the case.
218 *
219 * `field_type` is owned by the caller.
220 */
221 static
222 int field_type_contains_sequence_or_variant_ft(struct bt_field_type *type)
223 {
224 int ret = 0;
225 enum bt_field_type_id type_id = bt_field_type_get_type_id(type);
226
227 switch (type_id) {
228 case BT_FIELD_TYPE_ID_SEQUENCE:
229 case BT_FIELD_TYPE_ID_VARIANT:
230 ret = 1;
231 goto end;
232 case BT_FIELD_TYPE_ID_ARRAY:
233 case BT_FIELD_TYPE_ID_STRUCT:
234 {
235 int i;
236 int field_count = bt_field_type_get_field_count(type);
237
238 if (field_count < 0) {
239 ret = -1;
240 goto end;
241 }
242
243 for (i = 0; i < field_count; ++i) {
244 struct bt_field_type *child_type =
245 bt_field_type_borrow_field_at_index(
246 type, i);
247
248 ret = field_type_contains_sequence_or_variant_ft(
249 child_type);
250 if (ret != 0) {
251 goto end;
252 }
253 }
254 break;
255 }
256 default:
257 break;
258 }
259
260 end:
261 return ret;
262 }
263
264 BT_HIDDEN
265 int bt_validate_class_types(struct bt_value *environment,
266 struct bt_field_type *packet_header_type,
267 struct bt_field_type *packet_context_type,
268 struct bt_field_type *event_header_type,
269 struct bt_field_type *stream_event_ctx_type,
270 struct bt_field_type *event_context_type,
271 struct bt_field_type *event_payload_type,
272 int trace_valid, int stream_class_valid, int event_class_valid,
273 struct bt_validation_output *output,
274 enum bt_validation_flag validate_flags,
275 bt_validation_flag_copy_field_type_func copy_field_type_func)
276 {
277 int ret = 0;
278 int contains_seq_var;
279 int valid_ret;
280
281 BT_LOGV("Validating field types: "
282 "packet-header-ft-addr=%p, "
283 "packet-context-ft-addr=%p, "
284 "event-header-ft-addr=%p, "
285 "stream-event-context-ft-addr=%p, "
286 "event-context-ft-addr=%p, "
287 "event-payload-ft-addr=%p, "
288 "trace-is-valid=%d, stream-class-is-valid=%d, "
289 "event-class-is-valid=%d, validation-flags=%x",
290 packet_header_type, packet_context_type, event_header_type,
291 stream_event_ctx_type, event_context_type, event_payload_type,
292 trace_valid, stream_class_valid, event_class_valid,
293 (unsigned int) validate_flags);
294
295 /* Clean output values */
296 memset(output, 0, sizeof(*output));
297
298 /* Set initial valid flags according to valid parameters */
299 if (trace_valid) {
300 output->valid_flags |= BT_VALIDATION_FLAG_TRACE;
301 }
302
303 if (stream_class_valid) {
304 output->valid_flags |= BT_VALIDATION_FLAG_STREAM;
305 }
306
307 if (event_class_valid) {
308 output->valid_flags |= BT_VALIDATION_FLAG_EVENT;
309 }
310
311 /* Own the type parameters */
312 bt_get(packet_header_type);
313 bt_get(packet_context_type);
314 bt_get(event_header_type);
315 bt_get(stream_event_ctx_type);
316 bt_get(event_context_type);
317 bt_get(event_payload_type);
318
319 /* Validate trace */
320 if ((validate_flags & BT_VALIDATION_FLAG_TRACE) && !trace_valid) {
321 struct bt_field_type *packet_header_type_copy = NULL;
322
323 /* Create field type copies */
324 if (packet_header_type) {
325 contains_seq_var =
326 field_type_contains_sequence_or_variant_ft(
327 packet_header_type);
328 if (contains_seq_var < 0) {
329 ret = contains_seq_var;
330 goto error;
331 } else if (!contains_seq_var) {
332 /* No copy is needed */
333 packet_header_type_copy = packet_header_type;
334 bt_get(packet_header_type_copy);
335 goto skip_packet_header_type_copy;
336 }
337
338 BT_LOGV_STR("Copying packet header field type because it contains at least one sequence or variant field type.");
339 packet_header_type_copy =
340 copy_field_type_func(packet_header_type);
341 if (!packet_header_type_copy) {
342 ret = -1;
343 BT_LOGE_STR("Cannot copy packet header field type.");
344 goto error;
345 }
346
347 /*
348 * Freeze this copy: if it's returned to the
349 * caller, it cannot be modified any way since
350 * it will be resolved.
351 */
352 bt_field_type_freeze(packet_header_type_copy);
353 }
354
355 skip_packet_header_type_copy:
356 /* Put original reference and move copy */
357 BT_MOVE(packet_header_type, packet_header_type_copy);
358
359 /* Validate trace field types */
360 valid_ret = validate_trace_types(environment,
361 packet_header_type);
362 if (valid_ret == 0) {
363 /* Trace is valid */
364 output->valid_flags |= BT_VALIDATION_FLAG_TRACE;
365 }
366 }
367
368 /* Validate stream class */
369 if ((validate_flags & BT_VALIDATION_FLAG_STREAM) &&
370 !stream_class_valid) {
371 struct bt_field_type *packet_context_type_copy = NULL;
372 struct bt_field_type *event_header_type_copy = NULL;
373 struct bt_field_type *stream_event_ctx_type_copy = NULL;
374
375 if (packet_context_type) {
376 contains_seq_var =
377 field_type_contains_sequence_or_variant_ft(
378 packet_context_type);
379 if (contains_seq_var < 0) {
380 ret = contains_seq_var;
381 goto error;
382 } else if (!contains_seq_var) {
383 /* No copy is needed */
384 packet_context_type_copy = packet_context_type;
385 bt_get(packet_context_type_copy);
386 goto skip_packet_context_type_copy;
387 }
388
389 BT_LOGV_STR("Copying packet context field type because it contains at least one sequence or variant field type.");
390 packet_context_type_copy =
391 copy_field_type_func(packet_context_type);
392 if (!packet_context_type_copy) {
393 BT_LOGE_STR("Cannot copy packet context field type.");
394 goto sc_validation_error;
395 }
396
397 /*
398 * Freeze this copy: if it's returned to the
399 * caller, it cannot be modified any way since
400 * it will be resolved.
401 */
402 bt_field_type_freeze(packet_context_type_copy);
403 }
404
405 skip_packet_context_type_copy:
406 if (event_header_type) {
407 contains_seq_var =
408 field_type_contains_sequence_or_variant_ft(
409 event_header_type);
410 if (contains_seq_var < 0) {
411 ret = contains_seq_var;
412 goto error;
413 } else if (!contains_seq_var) {
414 /* No copy is needed */
415 event_header_type_copy = event_header_type;
416 bt_get(event_header_type_copy);
417 goto skip_event_header_type_copy;
418 }
419
420 BT_LOGV_STR("Copying event header field type because it contains at least one sequence or variant field type.");
421 event_header_type_copy =
422 copy_field_type_func(event_header_type);
423 if (!event_header_type_copy) {
424 BT_LOGE_STR("Cannot copy event header field type.");
425 goto sc_validation_error;
426 }
427
428 /*
429 * Freeze this copy: if it's returned to the
430 * caller, it cannot be modified any way since
431 * it will be resolved.
432 */
433 bt_field_type_freeze(event_header_type_copy);
434 }
435
436 skip_event_header_type_copy:
437 if (stream_event_ctx_type) {
438 contains_seq_var =
439 field_type_contains_sequence_or_variant_ft(
440 stream_event_ctx_type);
441 if (contains_seq_var < 0) {
442 ret = contains_seq_var;
443 goto error;
444 } else if (!contains_seq_var) {
445 /* No copy is needed */
446 stream_event_ctx_type_copy =
447 stream_event_ctx_type;
448 bt_get(stream_event_ctx_type_copy);
449 goto skip_stream_event_ctx_type_copy;
450 }
451
452 BT_LOGV_STR("Copying stream event context field type because it contains at least one sequence or variant field type.");
453 stream_event_ctx_type_copy =
454 copy_field_type_func(stream_event_ctx_type);
455 if (!stream_event_ctx_type_copy) {
456 BT_LOGE_STR("Cannot copy stream event context field type.");
457 goto sc_validation_error;
458 }
459
460 /*
461 * Freeze this copy: if it's returned to the
462 * caller, it cannot be modified any way since
463 * it will be resolved.
464 */
465 bt_field_type_freeze(stream_event_ctx_type_copy);
466 }
467
468 skip_stream_event_ctx_type_copy:
469 /* Put original references and move copies */
470 BT_MOVE(packet_context_type, packet_context_type_copy);
471 BT_MOVE(event_header_type, event_header_type_copy);
472 BT_MOVE(stream_event_ctx_type, stream_event_ctx_type_copy);
473
474 /* Validate stream class field types */
475 valid_ret = validate_stream_class_types(environment,
476 packet_header_type, packet_context_type,
477 event_header_type, stream_event_ctx_type);
478 if (valid_ret == 0) {
479 /* Stream class is valid */
480 output->valid_flags |= BT_VALIDATION_FLAG_STREAM;
481 }
482
483 goto sc_validation_done;
484
485 sc_validation_error:
486 BT_PUT(packet_context_type_copy);
487 BT_PUT(event_header_type_copy);
488 BT_PUT(stream_event_ctx_type_copy);
489 ret = -1;
490 goto error;
491 }
492
493 sc_validation_done:
494 /* Validate event class */
495 if ((validate_flags & BT_VALIDATION_FLAG_EVENT) &&
496 !event_class_valid) {
497 struct bt_field_type *event_context_type_copy = NULL;
498 struct bt_field_type *event_payload_type_copy = NULL;
499
500 if (event_context_type) {
501 contains_seq_var =
502 field_type_contains_sequence_or_variant_ft(
503 event_context_type);
504 if (contains_seq_var < 0) {
505 ret = contains_seq_var;
506 goto error;
507 } else if (!contains_seq_var) {
508 /* No copy is needed */
509 event_context_type_copy = event_context_type;
510 bt_get(event_context_type_copy);
511 goto skip_event_context_type_copy;
512 }
513
514 BT_LOGV_STR("Copying event context field type because it contains at least one sequence or variant field type.");
515 event_context_type_copy =
516 copy_field_type_func(event_context_type);
517 if (!event_context_type_copy) {
518 BT_LOGE_STR("Cannot copy event context field type.");
519 goto ec_validation_error;
520 }
521
522 /*
523 * Freeze this copy: if it's returned to the
524 * caller, it cannot be modified any way since
525 * it will be resolved.
526 */
527 bt_field_type_freeze(event_context_type_copy);
528 }
529
530 skip_event_context_type_copy:
531 if (event_payload_type) {
532 contains_seq_var =
533 field_type_contains_sequence_or_variant_ft(
534 event_payload_type);
535 if (contains_seq_var < 0) {
536 ret = contains_seq_var;
537 goto error;
538 } else if (!contains_seq_var) {
539 /* No copy is needed */
540 event_payload_type_copy = event_payload_type;
541 bt_get(event_payload_type_copy);
542 goto skip_event_payload_type_copy;
543 }
544
545 BT_LOGV_STR("Copying event payload field type because it contains at least one sequence or variant field type.");
546 event_payload_type_copy =
547 copy_field_type_func(event_payload_type);
548 if (!event_payload_type_copy) {
549 BT_LOGE_STR("Cannot copy event payload field type.");
550 goto ec_validation_error;
551 }
552
553 /*
554 * Freeze this copy: if it's returned to the
555 * caller, it cannot be modified any way since
556 * it will be resolved.
557 */
558 bt_field_type_freeze(event_payload_type_copy);
559 }
560
561 skip_event_payload_type_copy:
562 /* Put original references and move copies */
563 BT_MOVE(event_context_type, event_context_type_copy);
564 BT_MOVE(event_payload_type, event_payload_type_copy);
565
566 /* Validate event class field types */
567 valid_ret = validate_event_class_types(environment,
568 packet_header_type, packet_context_type,
569 event_header_type, stream_event_ctx_type,
570 event_context_type, event_payload_type);
571 if (valid_ret == 0) {
572 /* Event class is valid */
573 output->valid_flags |= BT_VALIDATION_FLAG_EVENT;
574 }
575
576 goto ec_validation_done;
577
578 ec_validation_error:
579 BT_PUT(event_context_type_copy);
580 BT_PUT(event_payload_type_copy);
581 ret = -1;
582 goto error;
583 }
584
585 ec_validation_done:
586 /*
587 * Validation is complete. Move the field types that were used
588 * to validate (and that were possibly altered by the validation
589 * process) to the output values.
590 */
591 BT_MOVE(output->packet_header_type, packet_header_type);
592 BT_MOVE(output->packet_context_type, packet_context_type);
593 BT_MOVE(output->event_header_type, event_header_type);
594 BT_MOVE(output->stream_event_ctx_type, stream_event_ctx_type);
595 BT_MOVE(output->event_context_type, event_context_type);
596 BT_MOVE(output->event_payload_type, event_payload_type);
597 return ret;
598
599 error:
600 BT_PUT(packet_header_type);
601 BT_PUT(packet_context_type);
602 BT_PUT(event_header_type);
603 BT_PUT(stream_event_ctx_type);
604 BT_PUT(event_context_type);
605 BT_PUT(event_payload_type);
606 return ret;
607 }
608
609 BT_HIDDEN
610 void bt_validation_replace_types(struct bt_trace *trace,
611 struct bt_stream_class *stream_class,
612 struct bt_event_class *event_class,
613 struct bt_validation_output *output,
614 enum bt_validation_flag replace_flags)
615 {
616 if ((replace_flags & BT_VALIDATION_FLAG_TRACE) && trace) {
617 bt_field_type_freeze(trace->packet_header_field_type);
618 BT_MOVE(trace->packet_header_field_type,
619 output->packet_header_type);
620 }
621
622 if ((replace_flags & BT_VALIDATION_FLAG_STREAM) && stream_class) {
623 bt_field_type_freeze(stream_class->packet_context_field_type);
624 bt_field_type_freeze(stream_class->event_header_field_type);
625 bt_field_type_freeze(stream_class->event_context_field_type);
626 BT_MOVE(stream_class->packet_context_field_type,
627 output->packet_context_type);
628 BT_MOVE(stream_class->event_header_field_type,
629 output->event_header_type);
630 BT_MOVE(stream_class->event_context_field_type,
631 output->stream_event_ctx_type);
632 }
633
634 if ((replace_flags & BT_VALIDATION_FLAG_EVENT) && event_class) {
635 bt_field_type_freeze(event_class->context_field_type);
636 bt_field_type_freeze(event_class->payload_field_type);
637 BT_MOVE(event_class->context_field_type, output->event_context_type);
638 BT_MOVE(event_class->payload_field_type, output->event_payload_type);
639 }
640 }
641
642 BT_HIDDEN
643 void bt_validation_output_put_types(
644 struct bt_validation_output *output)
645 {
646 BT_PUT(output->packet_header_type);
647 BT_PUT(output->packet_context_type);
648 BT_PUT(output->event_header_type);
649 BT_PUT(output->stream_event_ctx_type);
650 BT_PUT(output->event_context_type);
651 BT_PUT(output->event_payload_type);
652 }
This page took 0.042685 seconds and 4 git commands to generate.