You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

布隆过滤器实现疑问:如何用OpenSSL EVP计算哈希并更新存储?

布隆过滤器哈希函数修复方案

核心问题分析

  1. 静态哈希函数无法访问成员缓冲区:原hash函数被声明为static,无法写入类成员MD5_hash_result_buffer,导致计算出的哈希值完全没被保存,后续insert读取的是无效数据。
  2. 内存泄漏:hash函数中用OPENSSL_malloc分配的内存未释放,长期运行会耗尽内存。
  3. 索引越界风险:直接将哈希片段作为bitset索引,未对bloomfilter_store_size取模,当哈希值大于HASH_SIZE时会触发未定义行为。

修改后的完整代码

#include <openssl/evp.h>
#include <bitset>
#include <memory>

#include "config.h"

class Bloomfilter {
public:
    explicit Bloomfilter(size_t hash_func_count = 4)
            : hash_function_count(hash_func_count),
              object_count_(0),
              MD5_hash_result_buffer(
                  std::make_unique<unsigned char[]>(MD5_result_size_bytes)
              ) {}

    void insert(const std::string &object) {
        hash(object);
        const auto *object_hashes =
            reinterpret_cast<const uint16_t *>(MD5_hash_result_buffer.get());

        for (size_t i = 0; i < hash_function_count; i++) {
            // 对bitset大小取模,避免索引越界
            const size_t index_to_set = object_hashes[i] % bloomfilter_store_size;
            bloomfilter_store_[index_to_set] = true;
        }
        ++object_count_;
    }

    void insert(unsigned int object) {
        std::string object_str = std::to_string(object);
        insert(object_str);
    }

    template <typename InputIterator>
    inline void insert(const InputIterator begin, const InputIterator end)
    {
        InputIterator itr = begin;
        while (end != itr)
        {
            insert(*(itr++));
        }
    }  

private:
    static constexpr size_t MD5_result_size_bytes = 16;
    static constexpr size_t bloomfilter_store_size = HASH_SIZE;
    static constexpr size_t bytes_per_hash_function = 2;

    // 改为非static成员函数,才能访问类的成员变量
    void hash(const std::string &val) {
        const auto *md5_input_val =
            reinterpret_cast<const unsigned char *>(val.data());
        const size_t md5_input_length = val.length();
        
        // 初始化EVP上下文
        EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
        if (!mdctx) {
            // 可根据需求添加错误处理逻辑
            return;
        }

        // 初始化MD5哈希算法
        if (EVP_DigestInit_ex(mdctx, EVP_md5(), nullptr) != 1) {
            EVP_MD_CTX_free(mdctx);
            return;
        }

        // 更新哈希输入数据
        if (EVP_DigestUpdate(mdctx, md5_input_val, md5_input_length) != 1) {
            EVP_MD_CTX_free(mdctx);
            return;
        }

        // 将哈希结果写入类成员缓冲区,无需额外malloc
        unsigned int md5_digest_len;
        if (EVP_DigestFinal_ex(mdctx, MD5_hash_result_buffer.get(), &md5_digest_len) != 1) {
            EVP_MD_CTX_free(mdctx);
            return;
        }

        // 释放上下文
        EVP_MD_CTX_free(mdctx);
    }

    const size_t hash_function_count;
    std::bitset<bloomfilter_store_size> bloomfilter_store_;
    size_t object_count_;
    const std::unique_ptr<unsigned char[]> MD5_hash_result_buffer;
};

关键改动说明

  • 移除hash函数的static修饰:让函数能访问类的MD5_hash_result_buffer成员,将计算出的哈希值直接写入该缓冲区。
  • 删除OPENSSL_malloc调用:直接使用预先分配好的成员缓冲区存储哈希结果,避免内存泄漏。
  • 添加索引取模操作:在设置bitset位时,对bloomfilter_store_size取模,保证索引始终在合法范围内,避免越界访问。
  • 增加基础错误检查:对EVP接口的返回值进行判断,避免因哈希初始化/更新/最终化失败导致的无效数据。

内容的提问来源于stack exchange,提问作者dearn44

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 08:27:09