HdrHistogram/HdrHistogram_c

linear iteration goes into infinite loop on recording new values

Closed this issue · 1 comments

During the course of iteration if a new value gets inserted in a bucket that the iterator has already passed then the iteration never ends (hdr_iter_next continues to return true).

I made a quick change to one of the test cases to reproduce the issue.
I am not sure if this is proper usage of the api, but an infinite loop seems to be a very bad outcome.

static char* test_linear_iter_buckets_correctly()
{
    struct hdr_histogram *h;
    hdr_init(1, 255, 2, &h);

    hdr_record_value(h, 193);
    hdr_record_value(h, 255);
    hdr_record_value(h, 0);
    hdr_record_value(h, 1);
    hdr_record_value(h, 64);
    hdr_record_value(h, 128);

    struct hdr_iter iter;
    hdr_iter_linear_init(&iter, h, 64);

    int step_count = 0;
    int64_t total_count = 0;
    while (hdr_iter_next(&iter))
    {
        total_count += iter.specifics.linear.count_added_in_this_iteration_step;
        // start - changes to reproduce issue
        if (step_count == 0)
        {
            hdr_record_value(h, 2);
        }
        // end - changes to reproduce issue
        step_count++;
    }

    mu_assert("Number of steps", compare_int64(4, step_count));
    mu_assert("Total count", compare_int64(6, total_count));

    return 0;
}

In our application the issue was caused due to unsynchronized access from multiple threads. One thread was computing the hdr_value_at_percentile which another threaded called hdr_record_value (guessing this). The hdr_value_at_percentile call went into an infinite loop.

0x0081bf8e: has_next + 0x1e (7fff27779da0, 7f113380f040, 7fff27779de8, 1007fff27779ef0)
0x0081bf35: _basic_iter_next + 0x15 (81bf20, 7fff27779de8)
0x0081ba05: hdr_iter_next + 0x25 (7fff27779df0, 3635503b6, 4058c00000000000, 19, 26c17d008, 3635503b6) + 80
0x0081bb84: hdr_value_at_percentile + 0x114 (3fe, 4bb, 5a0, 709, c57, 196bff) + ffffff12161d1650

I've fixed this now, thank you. I'll need to check ABI compatibility before I push out a new release, but the head of the git repo has the fix and is stable if you need it immediately.