unum-cloud / usearch

Fast Open-Source Search & Clustering engine × for Vectors & 🔜 Strings × in C++, C, Python, JavaScript, Rust, Java, Objective-C, Swift, C#, GoLang, and Wolfram 🔍
https://unum-cloud.github.io/usearch/
Apache License 2.0
2.15k stars 130 forks source link

Bug: add remove index vector data bad_alloc #292

Closed weedge closed 11 months ago

weedge commented 11 months ago

Describe the bug

image

libc++abi: terminating due to uncaught exception of type std::bad_alloc: std::bad_alloc

Steps to reproduce

Repeat test: https://github.com/unum-cloud/usearch/pull/291

Expected behavior

add success

USearch version

v2.7.2

Operating System

macos

Hardware architecture

x86

Which interface are you using?

Other bindings

Contact Details

No response

Is there an existing issue for this?

Code of Conduct

ashvardanian commented 11 months ago

Hey, @weedge! You've caught a corner case that I've just mitigated. It's coming from the underlying multi-hash-table implementation and is hard to debug from the Rust layer and much easier on the C++ level. For that, I've implemented a temporary test case in test.cpp:

void test_special() {
    index_config_t config;
    metric_punned_t metric(4, metric_kind_t::cos_k, scalar_kind_t::f32_k);
    index_dense_t index = index_dense_t::make(metric, config);

    expect(index.reserve(10));
    expect(index.capacity() == 10);

    float first[4] = {0.2, 0.1, 0.2, 0.1};
    float second[4] = {0.3, 0.2, 0.4, 0.0};

    default_key_t id1 = 483367403120493160;
    default_key_t id2 = 483367403120558696;
    default_key_t id3 = 483367403120624232;
    default_key_t id4 = 4; // Adjusted to match Rust test

    expect(!!index.add(id1, first));
    float found_slice[4] = {0.0f};
    expect(index.get(id1, found_slice) == 1);
    expect(!!index.remove(id1));

    expect(!!index.add(id2, second));
    expect(index.get(id2, found_slice) == 1);
    expect(!!index.remove(id2));

    expect(!!index.add(id3, second));
    expect(index.get(id3, found_slice) == 1);
    expect(!!index.remove(id3));

    expect(!!index.add(id4, second));
    expect(index.get(id4, found_slice) == 1);
    expect(!!index.remove(id4));

    expect(index.size() == 0);
}

I also set the breakpoints for the address sanitizer: __asan::ReportGenericError and __sanitizer::Die. I will remove that particular case from tests to keep them minimalistic and easy to navigate, but feel free to reuse this snippet whenever you spot bugs!

And thanks again for your contributions 🤗

ashvardanian commented 11 months ago

:tada: This issue has been resolved in version 2.7.8 :tada:

The release is available on GitHub release

Your semantic-release bot :package::rocket: