Fix: event field value: assertion fails on empty string
[lttng-tools.git] / src / common / event-field-value.c
1 /*
2 * event-field-value.c
3 *
4 * Linux Trace Toolkit Control Library
5 *
6 * Copyright (C) 2020 Philippe Proulx <pproulx@efficios.com>
7 *
8 * SPDX-License-Identifier: LGPL-2.1-only
9 *
10 */
11
12 #define _LGPL_SOURCE
13 #include <assert.h>
14 #include <stddef.h>
15 #include <stdbool.h>
16
17 #include <common/error.h>
18 #include <common/macros.h>
19 #include <lttng/event-field-value-internal.h>
20
21 static
22 struct lttng_event_field_value *create_empty_field_val(
23 enum lttng_event_field_value_type type, size_t size)
24 {
25 struct lttng_event_field_value *field_val;
26
27 field_val = zmalloc(size);
28 if (!field_val) {
29 goto end;
30 }
31
32 field_val->type = type;
33
34 end:
35 return field_val;
36 }
37
38 LTTNG_HIDDEN
39 struct lttng_event_field_value *lttng_event_field_value_uint_create(
40 uint64_t val)
41 {
42 struct lttng_event_field_value_uint *field_val;
43
44 field_val = container_of(create_empty_field_val(
45 LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT,
46 sizeof(*field_val)),
47 struct lttng_event_field_value_uint, parent);
48 if (!field_val) {
49 goto error;
50 }
51
52 field_val->val = val;
53 goto end;
54
55 error:
56 lttng_event_field_value_destroy(&field_val->parent);
57
58 end:
59 return &field_val->parent;
60 }
61
62 LTTNG_HIDDEN
63 struct lttng_event_field_value *lttng_event_field_value_int_create(
64 int64_t val)
65 {
66 struct lttng_event_field_value_int *field_val;
67
68 field_val = container_of(create_empty_field_val(
69 LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT,
70 sizeof(*field_val)),
71 struct lttng_event_field_value_int, parent);
72 if (!field_val) {
73 goto error;
74 }
75
76 field_val->val = val;
77 goto end;
78
79 error:
80 lttng_event_field_value_destroy(&field_val->parent);
81
82 end:
83 return &field_val->parent;
84 }
85
86 static
87 struct lttng_event_field_value_enum *create_enum_field_val(
88 enum lttng_event_field_value_type type, size_t size)
89 {
90 struct lttng_event_field_value_enum *field_val;
91
92 field_val = container_of(create_empty_field_val(type, size),
93 struct lttng_event_field_value_enum, parent);
94 if (!field_val) {
95 goto error;
96 }
97
98 lttng_dynamic_pointer_array_init(&field_val->labels, free);
99 goto end;
100
101 error:
102 lttng_event_field_value_destroy(&field_val->parent);
103
104 end:
105 return field_val;
106 }
107
108 LTTNG_HIDDEN
109 struct lttng_event_field_value *lttng_event_field_value_enum_uint_create(
110 uint64_t val)
111 {
112 struct lttng_event_field_value_enum_uint *field_val;
113
114 field_val = container_of(create_enum_field_val(
115 LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM,
116 sizeof(*field_val)),
117 struct lttng_event_field_value_enum_uint, parent);
118 if (!field_val) {
119 goto error;
120 }
121
122 field_val->val = val;
123 goto end;
124
125 error:
126 lttng_event_field_value_destroy(&field_val->parent.parent);
127
128 end:
129 return &field_val->parent.parent;
130 }
131
132 LTTNG_HIDDEN
133 struct lttng_event_field_value *lttng_event_field_value_enum_int_create(
134 int64_t val)
135 {
136 struct lttng_event_field_value_enum_int *field_val;
137
138 field_val = container_of(create_enum_field_val(
139 LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM,
140 sizeof(*field_val)),
141 struct lttng_event_field_value_enum_int, parent);
142 if (!field_val) {
143 goto error;
144 }
145
146 field_val->val = val;
147 goto end;
148
149 error:
150 lttng_event_field_value_destroy(&field_val->parent.parent);
151
152 end:
153 return &field_val->parent.parent;
154 }
155
156 LTTNG_HIDDEN
157 struct lttng_event_field_value *lttng_event_field_value_real_create(double val)
158 {
159 struct lttng_event_field_value_real *field_val = container_of(
160 create_empty_field_val(
161 LTTNG_EVENT_FIELD_VALUE_TYPE_REAL,
162 sizeof(*field_val)),
163 struct lttng_event_field_value_real, parent);
164
165 if (!field_val) {
166 goto error;
167 }
168
169 field_val->val = val;
170 goto end;
171
172 error:
173 lttng_event_field_value_destroy(&field_val->parent);
174
175 end:
176 return &field_val->parent;
177 }
178
179 LTTNG_HIDDEN
180 struct lttng_event_field_value *lttng_event_field_value_string_create_with_size(
181 const char *val, size_t size)
182 {
183 struct lttng_event_field_value_string *field_val = container_of(
184 create_empty_field_val(
185 LTTNG_EVENT_FIELD_VALUE_TYPE_STRING,
186 sizeof(*field_val)),
187 struct lttng_event_field_value_string, parent);
188
189 if (!field_val) {
190 goto error;
191 }
192
193 if (size) {
194 assert(val);
195 field_val->val = strndup(val, size);
196 } else {
197 /*
198 * User code do not expect a NULL string pointer. Populate with
199 * an empty string when length is 0.
200 */
201 field_val->val = strdup("");
202 }
203 if (!field_val->val) {
204 goto error;
205 }
206
207 goto end;
208
209 error:
210 lttng_event_field_value_destroy(&field_val->parent);
211
212 end:
213 return &field_val->parent;
214 }
215
216 LTTNG_HIDDEN
217 struct lttng_event_field_value *lttng_event_field_value_string_create(
218 const char *val)
219 {
220 assert(val);
221 return lttng_event_field_value_string_create_with_size(val,
222 strlen(val));
223 }
224
225 static
226 void destroy_field_val(void *field_val)
227 {
228 lttng_event_field_value_destroy(field_val);
229 }
230
231 LTTNG_HIDDEN
232 struct lttng_event_field_value *lttng_event_field_value_array_create(void)
233 {
234 struct lttng_event_field_value_array *field_val = container_of(
235 create_empty_field_val(
236 LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY,
237 sizeof(*field_val)),
238 struct lttng_event_field_value_array, parent);
239
240 if (!field_val) {
241 goto error;
242 }
243
244 lttng_dynamic_pointer_array_init(&field_val->elems, destroy_field_val);
245 goto end;
246
247 error:
248 lttng_event_field_value_destroy(&field_val->parent);
249
250 end:
251 return &field_val->parent;
252 }
253
254 LTTNG_HIDDEN
255 void lttng_event_field_value_destroy(struct lttng_event_field_value *field_val)
256 {
257 if (!field_val) {
258 goto end;
259 }
260
261 switch (field_val->type) {
262 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
263 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
264 {
265 struct lttng_event_field_value_enum *enum_field_val =
266 container_of(field_val,
267 struct lttng_event_field_value_enum, parent);
268
269 lttng_dynamic_pointer_array_reset(&enum_field_val->labels);
270 break;
271 }
272 case LTTNG_EVENT_FIELD_VALUE_TYPE_STRING:
273 {
274 struct lttng_event_field_value_string *str_field_val =
275 container_of(field_val,
276 struct lttng_event_field_value_string, parent);
277
278 free(str_field_val->val);
279 break;
280 }
281 case LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY:
282 {
283 struct lttng_event_field_value_array *array_field_expr =
284 container_of(field_val,
285 struct lttng_event_field_value_array,
286 parent);
287
288 lttng_dynamic_pointer_array_reset(&array_field_expr->elems);
289 break;
290 }
291 default:
292 break;
293 }
294
295 free(field_val);
296
297 end:
298 return;
299 }
300
301 LTTNG_HIDDEN
302 int lttng_event_field_value_enum_append_label_with_size(
303 struct lttng_event_field_value *field_val,
304 const char *label, size_t size)
305 {
306 int ret;
307 char *new_label;
308
309 assert(field_val);
310 assert(label);
311 new_label = strndup(label, size);
312 if (!new_label) {
313 ret = -1;
314 goto end;
315 }
316
317 ret = lttng_dynamic_pointer_array_add_pointer(
318 &container_of(field_val,
319 struct lttng_event_field_value_enum, parent)->labels,
320 new_label);
321 if (ret == 0) {
322 new_label = NULL;
323 }
324
325 end:
326 free(new_label);
327 return ret;
328 }
329
330 LTTNG_HIDDEN
331 int lttng_event_field_value_enum_append_label(
332 struct lttng_event_field_value *field_val,
333 const char *label)
334 {
335 assert(label);
336 return lttng_event_field_value_enum_append_label_with_size(field_val,
337 label, strlen(label));
338 }
339
340 LTTNG_HIDDEN
341 int lttng_event_field_value_array_append(
342 struct lttng_event_field_value *array_field_val,
343 struct lttng_event_field_value *field_val)
344 {
345 assert(array_field_val);
346 assert(field_val);
347 return lttng_dynamic_pointer_array_add_pointer(
348 &container_of(array_field_val,
349 struct lttng_event_field_value_array, parent)->elems,
350 field_val);
351 }
352
353 LTTNG_HIDDEN
354 int lttng_event_field_value_array_append_unavailable(
355 struct lttng_event_field_value *array_field_val)
356 {
357 assert(array_field_val);
358 return lttng_dynamic_pointer_array_add_pointer(
359 &container_of(array_field_val,
360 struct lttng_event_field_value_array, parent)->elems,
361 NULL);
362 }
363
364 enum lttng_event_field_value_type lttng_event_field_value_get_type(
365 const struct lttng_event_field_value *field_val)
366 {
367 enum lttng_event_field_value_type type;
368
369 if (!field_val) {
370 type = LTTNG_EVENT_FIELD_VALUE_TYPE_INVALID;
371 goto end;
372 }
373
374 type = field_val->type;
375
376 end:
377 return type;
378 }
379
380 enum lttng_event_field_value_status
381 lttng_event_field_value_unsigned_int_get_value(
382 const struct lttng_event_field_value *field_val, uint64_t *val)
383 {
384 enum lttng_event_field_value_status status;
385
386 if (!field_val || !val) {
387 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
388 goto end;
389 }
390
391 switch (field_val->type) {
392 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_INT:
393 *val = container_of(field_val,
394 const struct lttng_event_field_value_uint,
395 parent)->val;
396 break;
397 case LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM:
398 {
399 const struct lttng_event_field_value_enum *field_val_enum = container_of(
400 field_val,
401 const struct lttng_event_field_value_enum,
402 parent);
403 const struct lttng_event_field_value_enum_uint
404 *field_val_enum_uint = container_of(
405 field_val_enum,
406 const struct lttng_event_field_value_enum_uint,
407 parent);
408 *val = field_val_enum_uint->val;
409 break;
410 }
411 default:
412 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
413 goto end;
414 }
415
416 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
417
418 end:
419 return status;
420 }
421
422 enum lttng_event_field_value_status
423 lttng_event_field_value_signed_int_get_value(
424 const struct lttng_event_field_value *field_val, int64_t *val)
425 {
426 enum lttng_event_field_value_status status;
427
428 if (!field_val || !val) {
429 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
430 goto end;
431 }
432
433 switch (field_val->type) {
434 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_INT:
435 *val = container_of(field_val,
436 const struct lttng_event_field_value_int,
437 parent)->val;
438 break;
439 case LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM:
440 {
441 const struct lttng_event_field_value_enum *field_val_enum = container_of(
442 field_val,
443 const struct lttng_event_field_value_enum,
444 parent);
445 const struct lttng_event_field_value_enum_int
446 *field_val_enum_uint = container_of(
447 field_val_enum,
448 const struct lttng_event_field_value_enum_int,
449 parent);
450 *val = field_val_enum_uint->val;
451 break;
452 }
453 default:
454 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
455 goto end;
456 }
457
458 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
459
460 end:
461 return status;
462 }
463
464 enum lttng_event_field_value_status
465 lttng_event_field_value_real_get_value(
466 const struct lttng_event_field_value *field_val, double *val)
467 {
468 enum lttng_event_field_value_status status;
469
470 if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_REAL ||
471 !val) {
472 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
473 goto end;
474 }
475
476 *val = container_of(field_val,
477 const struct lttng_event_field_value_real, parent)->val;
478 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
479
480 end:
481 return status;
482 }
483
484 static
485 bool is_enum_field_val(const struct lttng_event_field_value *field_val)
486 {
487 return field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_UNSIGNED_ENUM ||
488 field_val->type == LTTNG_EVENT_FIELD_VALUE_TYPE_SIGNED_ENUM;
489 }
490
491 enum lttng_event_field_value_status
492 lttng_event_field_value_enum_get_label_count(
493 const struct lttng_event_field_value *field_val,
494 unsigned int *count)
495 {
496 enum lttng_event_field_value_status status;
497
498 if (!field_val || !is_enum_field_val(field_val) || !count) {
499 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
500 goto end;
501 }
502
503 *count = (unsigned int) lttng_dynamic_pointer_array_get_count(
504 &container_of(field_val,
505 const struct lttng_event_field_value_enum,
506 parent)->labels);
507 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
508
509 end:
510 return status;
511 }
512
513 const char *lttng_event_field_value_enum_get_label_at_index(
514 const struct lttng_event_field_value *field_val,
515 unsigned int index)
516 {
517 const char *ret;
518 const struct lttng_event_field_value_enum *enum_field_val;
519
520 if (!field_val || !is_enum_field_val(field_val)) {
521 ret = NULL;
522 goto end;
523 }
524
525 enum_field_val = container_of(field_val,
526 const struct lttng_event_field_value_enum, parent);
527
528 if (index >= lttng_dynamic_pointer_array_get_count(&enum_field_val->labels)) {
529 ret = NULL;
530 goto end;
531 }
532
533 ret = lttng_dynamic_pointer_array_get_pointer(&enum_field_val->labels,
534 index);
535
536 end:
537 return ret;
538 }
539
540 enum lttng_event_field_value_status lttng_event_field_value_string_get_value(
541 const struct lttng_event_field_value *field_val,
542 const char **value)
543 {
544 enum lttng_event_field_value_status status;
545
546 if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_STRING) {
547 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
548 goto end;
549 }
550
551 *value = container_of(field_val,
552 const struct lttng_event_field_value_string, parent)->val;
553 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
554
555 end:
556 return status;
557 }
558
559 enum lttng_event_field_value_status lttng_event_field_value_array_get_length(
560 const struct lttng_event_field_value *field_val,
561 unsigned int *length)
562 {
563 enum lttng_event_field_value_status status;
564
565 if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY ||
566 !length) {
567 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
568 goto end;
569 }
570
571 *length = (unsigned int) lttng_dynamic_pointer_array_get_count(
572 &container_of(field_val,
573 const struct lttng_event_field_value_array,
574 parent)->elems);
575 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
576
577 end:
578 return status;
579 }
580
581 enum lttng_event_field_value_status
582 lttng_event_field_value_array_get_element_at_index(
583 const struct lttng_event_field_value *field_val,
584 unsigned int index,
585 const struct lttng_event_field_value **elem_field_val)
586 {
587 enum lttng_event_field_value_status status;
588 const struct lttng_event_field_value_array *array_field_val;
589
590 if (!field_val || field_val->type != LTTNG_EVENT_FIELD_VALUE_TYPE_ARRAY ||
591 !elem_field_val) {
592 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
593 goto end;
594 }
595
596 array_field_val = container_of(field_val,
597 const struct lttng_event_field_value_array, parent);
598
599 if (index >= lttng_dynamic_pointer_array_get_count(&array_field_val->elems)) {
600 status = LTTNG_EVENT_FIELD_VALUE_STATUS_INVALID;
601 goto end;
602 }
603
604 *elem_field_val = lttng_dynamic_pointer_array_get_pointer(
605 &array_field_val->elems, index);
606 if (*elem_field_val) {
607 status = LTTNG_EVENT_FIELD_VALUE_STATUS_OK;
608 } else {
609 status = LTTNG_EVENT_FIELD_VALUE_STATUS_UNAVAILABLE;
610 }
611
612 end:
613 return status;
614 }
This page took 0.04186 seconds and 4 git commands to generate.