~lttng/babeltrace/trunk

« back to all changes in this revision

Viewing changes to src/lib/graph/iterator.c

  • Committer: Philippe Proulx
  • Author(s): Simon Marchi
  • Date: 2023-11-22 16:55:42 UTC
  • Revision ID: git-v1:9340eff9237ee05d044f7953495300506e152315
lib: validate iterator message packets

Validate that messages coming out of iterators have sensible packet
values.  This applies to event and packet end messages: their packet
must match the packet of the previous packet beginning message.

Add a hash table to hold per-stream state, inside the
bt_message_iterator structure.  Since this state will only be used for
dev assertions, for the moment, only create it if BT_DEV_MODE is
defined.

Discard the per-stream state when the iterator seeks (after which the
iterator is expected to produce a new message sequence, starting from
scratch).

If the iterator uses auto-seek to implement "seek ns from origin", we
need to discard the per-stream state twice: once after seeking the
beginning, and once after consuming messages until the desired point.

When a wrong packet is detected, print an error logging message with
some details, before the failed assertion message:

    Babeltrace 2 library postcondition not satisfied.
    ------------------------------------------------------------------------
    Condition ID: `post:message-iterator-class-next-method:message-packet-is-expected`.
    Function: bt_message_iterator_class_next_method().
    ------------------------------------------------------------------------
    Error is:
    Message's packet is not expected: stream-addr=0x60d000001d80, stream-id=0, iterator-addr=0x611000004c80, iterator-upstream-comp-name="source.gpx.GpxSource", iterator-upstream-comp-log-level=WARNING, iterator-upstream-comp-class-type=SOURCE, iterator-upstream-comp-class-name="GpxSource", iterator-upstream-comp-class-partial-descr="", message-addr=0x607000004540, message-type=EVENT, received-packet-addr=0x607000004310, expected-packet-addr=(nil)
    Aborting...

The particular structure of the code is explained by the following
patch, which adds verification that the message sequence is as expected.
Both assertions (packet is expected, and message sequence is as
expected) need to know about the current packet (this state is
maintained by message_packet_is_valid), so must be in the same "for all
messages" loop.  Alternatively, they could both track the current packet
independently, but that would be redundant.

But this form also allows putting more info about the problematic
message in the abort notice, which I think is nice.

Change-Id: I176417d9ae7b04a9c16ff975e008e208b173e3d2
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Reviewed-on: https://review.lttng.org/c/babeltrace/+/10448
Tested-by: jenkins <jenkins@lttng.org>
Reviewed-by: Philippe Proulx <eeppeliteloop@gmail.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
66
66
                (_iter)->state == BT_MESSAGE_ITERATOR_STATE_LAST_SEEKING_RETURNED_ERROR, \
67
67
                "Message iterator is in the wrong state: %!+i", (_iter))
68
68
 
 
69
#ifdef BT_DEV_MODE
 
70
struct per_stream_state
 
71
{
 
72
        bt_packet *cur_packet;
 
73
};
 
74
#endif
 
75
 
 
76
static void
 
77
clear_per_stream_state (struct bt_message_iterator *iterator)
 
78
{
 
79
#ifdef BT_DEV_MODE
 
80
        g_hash_table_remove_all(iterator->per_stream_state);
 
81
#else
 
82
        BT_USE_EXPR(iterator);
 
83
#endif
 
84
}
 
85
 
69
86
static inline
70
87
void set_msg_iterator_state(struct bt_message_iterator *iterator,
71
88
                enum bt_message_iterator_state state)
135
152
                iterator->msgs = NULL;
136
153
        }
137
154
 
 
155
#ifdef BT_DEV_MODE
 
156
        g_hash_table_destroy(iterator->per_stream_state);
 
157
#endif
 
158
 
138
159
        g_free(iterator);
139
160
}
140
161
 
341
362
 
342
363
        g_ptr_array_set_size(iterator->msgs, MSG_BATCH_SIZE);
343
364
        iterator->last_ns_from_origin = INT64_MIN;
 
365
 
 
366
#ifdef BT_DEV_MODE
 
367
        /* The per-stream state is only used for dev assertions right now. */
 
368
        iterator->per_stream_state = g_hash_table_new_full(
 
369
                g_direct_hash,
 
370
                g_direct_equal,
 
371
                NULL,
 
372
                g_free);
 
373
#endif
 
374
 
344
375
        iterator->auto_seek.msgs = g_queue_new();
345
376
        if (!iterator->auto_seek.msgs) {
346
377
                BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate a GQueue.");
788
819
        return result;
789
820
}
790
821
 
 
822
#ifdef BT_DEV_MODE
 
823
static
 
824
const bt_stream *get_stream_from_msg(const struct bt_message *msg)
 
825
{
 
826
        struct bt_stream *stream;
 
827
 
 
828
        switch (msg->type) {
 
829
        case BT_MESSAGE_TYPE_STREAM_BEGINNING:
 
830
        case BT_MESSAGE_TYPE_STREAM_END:
 
831
        {
 
832
                struct bt_message_stream *msg_stream =
 
833
                        (struct bt_message_stream *) msg;
 
834
                stream = msg_stream->stream;
 
835
                break;
 
836
        }
 
837
        case BT_MESSAGE_TYPE_EVENT:
 
838
        {
 
839
                struct bt_message_event *msg_event =
 
840
                        (struct bt_message_event *) msg;
 
841
                stream = msg_event->event->stream;
 
842
                break;
 
843
        }
 
844
        case BT_MESSAGE_TYPE_PACKET_BEGINNING:
 
845
        case BT_MESSAGE_TYPE_PACKET_END:
 
846
        {
 
847
                struct bt_message_packet *msg_packet =
 
848
                        (struct bt_message_packet *) msg;
 
849
                stream = msg_packet->packet->stream;
 
850
                break;
 
851
        }
 
852
        case BT_MESSAGE_TYPE_DISCARDED_EVENTS:
 
853
        case BT_MESSAGE_TYPE_DISCARDED_PACKETS:
 
854
        {
 
855
                struct bt_message_discarded_items *msg_discarded =
 
856
                        (struct bt_message_discarded_items *) msg;
 
857
                stream = msg_discarded->stream;
 
858
                break;
 
859
        }
 
860
        case BT_MESSAGE_TYPE_MESSAGE_ITERATOR_INACTIVITY:
 
861
                stream = NULL;
 
862
                break;
 
863
        default:
 
864
                bt_common_abort();
 
865
        }
 
866
 
 
867
        return stream;
 
868
}
 
869
 
 
870
static
 
871
struct per_stream_state *get_per_stream_state(
 
872
                struct bt_message_iterator *iterator,
 
873
                const struct bt_stream *stream)
 
874
{
 
875
        struct per_stream_state *state = g_hash_table_lookup(
 
876
                iterator->per_stream_state, stream);
 
877
 
 
878
        if (!state) {
 
879
                state = g_new0(struct per_stream_state, 1);
 
880
                g_hash_table_insert(iterator->per_stream_state,
 
881
                        (gpointer) stream, state);
 
882
        }
 
883
 
 
884
        return state;
 
885
}
 
886
#endif
 
887
 
 
888
#define NEXT_METHOD_NAME        "bt_message_iterator_class_next_method"
 
889
 
 
890
#ifdef BT_DEV_MODE
 
891
static
 
892
void assert_post_dev_expected_packet(struct bt_message_iterator *iterator,
 
893
                const struct bt_message *msg)
 
894
{
 
895
        const bt_stream *stream = get_stream_from_msg(msg);
 
896
        struct per_stream_state *state;
 
897
        const bt_packet *actual_packet = NULL;
 
898
        const bt_packet *expected_packet = NULL;
 
899
 
 
900
        if (!stream) {
 
901
                goto end;
 
902
        }
 
903
 
 
904
        state = get_per_stream_state(iterator, stream);
 
905
 
 
906
        switch (msg->type) {
 
907
        case BT_MESSAGE_TYPE_EVENT:
 
908
        {
 
909
                const struct bt_message_event *msg_event =
 
910
                        (const struct bt_message_event *) msg;
 
911
 
 
912
                actual_packet = msg_event->event->packet;
 
913
                expected_packet = state->cur_packet;
 
914
                break;
 
915
        }
 
916
        case BT_MESSAGE_TYPE_PACKET_BEGINNING:
 
917
        {
 
918
                const struct bt_message_packet *msg_packet =
 
919
                        (const struct bt_message_packet *) msg;
 
920
 
 
921
                BT_ASSERT(!state->cur_packet);
 
922
                state->cur_packet = msg_packet->packet;
 
923
                break;
 
924
        }
 
925
        case BT_MESSAGE_TYPE_PACKET_END:
 
926
        {
 
927
                const struct bt_message_packet *msg_packet =
 
928
                        (const struct bt_message_packet *) msg;
 
929
 
 
930
                actual_packet = msg_packet->packet;
 
931
                expected_packet = state->cur_packet;
 
932
                BT_ASSERT(state->cur_packet);
 
933
                state->cur_packet = NULL;
 
934
                break;
 
935
        }
 
936
        default:
 
937
                break;
 
938
        }
 
939
 
 
940
        BT_ASSERT_POST_DEV(NEXT_METHOD_NAME,
 
941
                "message-packet-is-expected",
 
942
                actual_packet == expected_packet,
 
943
                "Message's packet is not expected: %![stream-]s, %![iterator-]i, "
 
944
                "%![message-]n, %![received-packet-]a, %![expected-packet-]a",
 
945
                stream, iterator, msg, actual_packet, expected_packet);
 
946
 
 
947
end:
 
948
        return;
 
949
}
 
950
 
 
951
static
 
952
void assert_post_dev_next(
 
953
                struct bt_message_iterator *iterator,
 
954
                bt_message_iterator_class_next_method_status status,
 
955
                bt_message_array_const msgs, uint64_t msg_count)
 
956
{
 
957
        if (status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
 
958
                uint64_t i;
 
959
 
 
960
                for (i = 0; i < msg_count; i++) {
 
961
                        assert_post_dev_expected_packet(iterator, msgs[i]);
 
962
                }
 
963
        }
 
964
}
 
965
#endif
 
966
 
791
967
/*
792
968
 * Call the `next` method of the iterator.  Do some validation on the returned
793
969
 * messages.
794
970
 */
795
971
 
796
 
#define NEXT_METHOD_NAME        "bt_message_iterator_class_next_method"
797
 
 
798
972
static
799
973
enum bt_message_iterator_class_next_method_status
800
974
call_iterator_next_method(
822
996
                        "Clock snapshots are not monotonic");
823
997
        }
824
998
 
 
999
#ifdef BT_DEV_MODE
 
1000
        assert_post_dev_next(iterator, status, msgs, *user_count);
 
1001
#endif
 
1002
 
825
1003
        BT_ASSERT_POST_DEV_NO_ERROR_IF_NO_ERROR_STATUS(NEXT_METHOD_NAME,
826
1004
                status);
827
1005
 
1169
1347
                        iterator, bt_common_func_status_string(status));
1170
1348
        }
1171
1349
 
 
1350
        clear_per_stream_state(iterator);
 
1351
 
1172
1352
        set_iterator_state_after_seeking(iterator, status);
1173
1353
        return status;
1174
1354
}
1826
2006
                                iterator, bt_common_func_status_string(status));
1827
2007
                }
1828
2008
 
 
2009
                clear_per_stream_state(iterator);
 
2010
 
1829
2011
                switch (status) {
1830
2012
                case BT_FUNC_STATUS_OK:
1831
2013
                        break;
1982
2164
                }
1983
2165
        }
1984
2166
 
 
2167
        clear_per_stream_state(iterator);
 
2168
 
1985
2169
        /*
1986
2170
         * The following messages returned by the next method (including
1987
2171
         * post_auto_seek_next) must be after (or at) `ns_from_origin`.