布隆过滤器实现疑问:如何用OpenSSL EVP计算哈希并更新存储?
布隆过滤器哈希函数修复方案
核心问题分析
- 静态哈希函数无法访问成员缓冲区:原
hash函数被声明为static,无法写入类成员MD5_hash_result_buffer,导致计算出的哈希值完全没被保存,后续insert读取的是无效数据。 - 内存泄漏:
hash函数中用OPENSSL_malloc分配的内存未释放,长期运行会耗尽内存。 - 索引越界风险:直接将哈希片段作为
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
相关产品推荐
相关产品推荐

