OpenAtomFoundation / pika

Pika is a Redis-Compatible database developed by Qihoo's infrastructure team.
BSD 3-Clause "New" or "Revised" License
5.76k stars 1.19k forks source link

dbsize mem error: heap-buffer-overflow #2747

Closed chenbt-hz closed 2 weeks ago

chenbt-hz commented 2 weeks ago

Is this a regression?

Yes

Description

在mac环境中,执行dbsize会导致进程崩溃,而且ut大概率无法通过会触发IO 异常:

错误日志如下:

=================================================================
==23360==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60e000030040 at pc 0x00010e87af2f bp 0x700011106c10 sp 0x700011106c08
WRITE of size 8 at 0x60e000030040 thread T109
    #0 0x10e87af2e in storage::Redis::ScanStreamsKeyNum(storage::KeyInfo*) redis_streams.cc:358
    #1 0x10e720823 in storage::Redis::ScanKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) redis.cc:390
    #2 0x10e94f0de in storage::Storage::GetKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) storage.cc:1838
    #3 0x10e20845e in DB::GetKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) pika_db.cc:122
    #4 0x10e207a53 in DB::RunKeyScan() pika_db.cc:102
    #5 0x10e2075cf in DB::DoKeyScan(void*) pika_db.cc:171
    #6 0x10e9bfe29 in net::BGThread::ThreadMain() bg_thread.cc:103
    #7 0x10ea9a3bb in net::Thread::RunThread(void*) net_thread.cc:22
    #8 0x7ff815b17201 in _pthread_start+0x62 (libsystem_pthread.dylib:x86_64+0x6201)
    #9 0x7ff815b12baa in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1baa)

0x60e000030040 is located 0 bytes after 160-byte region [0x60e00002ffa0,0x60e000030040)
allocated by thread T109 here:
    #0 0x113c3060d in wrap__Znwm+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xec60d)
    #1 0x10f71b3d4 in void* std::__1::__libcpp_operator_new[abi:v160006]<unsigned long>(unsigned long) new:285
    #2 0x10f71b3b8 in std::__1::__libcpp_allocate[abi:v160006](unsigned long, unsigned long) new:311
    #3 0x10df4efac in std::__1::allocator<storage::KeyInfo>::allocate[abi:v160006](unsigned long) allocator.h:115
    #4 0x10df4ec9a in std::__1::__allocation_result<std::__1::allocator_traits<std::__1::allocator<storage::KeyInfo>>::pointer> std::__1::__allocate_at_least[abi:v160006]<std::__1::allocator<storage::KeyInfo>>(std::__1::allocator<storage::KeyInfo>&, unsigned long) allocate_at_least.h:55
    #5 0x10e789203 in std::__1::__split_buffer<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator<storage::KeyInfo>&) __split_buffer:323
    #6 0x10e78848c in std::__1::__split_buffer<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>&>::__split_buffer(unsigned long, unsigned long, std::__1::allocator<storage::KeyInfo>&) __split_buffer:319
    #7 0x10e787f9f in std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>::__append(unsigned long) vector:1046
    #8 0x10e720a7f in std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>::resize(unsigned long) vector:1910
    #9 0x10e720464 in storage::Redis::ScanKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) redis.cc:368
    #10 0x10e94f0de in storage::Storage::GetKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) storage.cc:1838
    #11 0x10e20845e in DB::GetKeyNum(std::__1::vector<storage::KeyInfo, std::__1::allocator<storage::KeyInfo>>*) pika_db.cc:122
    #12 0x10e207a53 in DB::RunKeyScan() pika_db.cc:102
    #13 0x10e2075cf in DB::DoKeyScan(void*) pika_db.cc:171
    #14 0x10e9bfe29 in net::BGThread::ThreadMain() bg_thread.cc:103
    #15 0x10ea9a3bb in net::Thread::RunThread(void*) net_thread.cc:22
    #16 0x7ff815b17201 in _pthread_start+0x62 (libsystem_pthread.dylib:x86_64+0x6201)
    #17 0x7ff815b12baa in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1baa)

Thread T109 created by T75 here:
    #0 0x113c13c8a in wrap_pthread_create+0x5a (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xcfc8a)
    #1 0x10ea9a68a in net::Thread::StartThread() net_thread.cc:34
    #2 0x10e4695e7 in PikaServer::KeyScanTaskSchedule(void (*)(void*), void*) pika_server.cc:817
    #3 0x10e207385 in DB::KeyScan() pika_db.cc:88
    #4 0x10e45e974 in PikaServer::DoSameThingSpecificDB(std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&, TaskArg const&) pika_server.cc:387
    #5 0x10deee68a in InfoCmd::InfoKeyspace(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>&) pika_admin.cc:1236
    #6 0x10dee439e in InfoCmd::Do() pika_admin.cc:903
    #7 0x10dee260e in InfoCmd::Execute() pika_admin.cc:757
    #8 0x10e03314b in PikaClientConn::DoCmd(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> const&) pika_client_conn.cc:192
    #9 0x10e03b91e in PikaClientConn::ExecRedisCmd(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>> const&, std::__1::shared_ptr<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>&) pika_client_conn.cc:497
    #10 0x10e03a869 in PikaClientConn::BatchExecRedisCmd(std::__1::vector<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>, std::__1::allocator<std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>>>>> const&) pika_client_conn.cc:315
    #11 0x10e03a474 in PikaClientConn::DoBackgroundTask(void*) pika_client_conn.cc:307
    #12 0x10eae42ef in net::ThreadPool::runInThread() thread_pool.cc:161
    #13 0x10eae3a4c in net::ThreadPool::Worker::WorkerMain(void*) thread_pool.cc:17
    #14 0x7ff815b17201 in _pthread_start+0x62 (libsystem_pthread.dylib:x86_64+0x6201)
    #15 0x7ff815b12baa in thread_start+0xe (libsystem_pthread.dylib:x86_64+0x1baa)

Thread T75 created by T0 here:
    #0 0x113c13c8a in wrap_pthread_create+0x5a (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xcfc8a)
    #1 0x10eae463b in net::ThreadPool::Worker::start() thread_pool.cc:23
    #2 0x10eae5361 in net::ThreadPool::start_thread_pool() thread_pool.cc:58
    #3 0x10e074496 in PikaClientProcessor::Start() pika_client_processor.cc:23
    #4 0x10e457c84 in PikaServer::Start() pika_server.cc:163
    #5 0x10dea963a in main pika.cc:236
    #6 0x7ff81578c385 in start+0x795 (dyld:x86_64+0xfffffffffff5c385)

SUMMARY: AddressSanitizer: heap-buffer-overflow redis_streams.cc:358 in storage::Redis::ScanStreamsKeyNum(storage::KeyInfo*)
Shadow bytes around the buggy address:
  0x60e00002fd80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e00002fe00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e00002fe80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e00002ff00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e00002ff80: fa fa fa fa 00 00 00 00 00 00 00 00 00 00 00 00
=>0x60e000030000: 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa fa
  0x60e000030080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e000030100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e000030180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e000030200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x60e000030280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==23360==ABORTING
zsh: abort      ./build/pika -c tests/conf/pika.conf

Please provide a link to a minimal reproduction of the bug

No response

Screenshots or videos

No response

Please provide the version you discovered this bug in (check about page for version information)

No response

Anything else?

AI日志分析:

错误类型: heap-buffer-overflow 表示在堆上分配的缓冲区被写入了超出其大小的数据。

错误位置: 错误发生在 redis_streams.cc 文件的第 358 行,函数 storage::Redis::ScanStreamsKeyNum 中。

触发点: 写入操作的地址是 0x60e000030040,这个地址正好位于之前分配的 160 字节区域的末尾,即 [0x60e00002ffa0, 0x60e000030040)。

分配信息: 这个区域是由线程 T109 分配的,分配的调用栈显示,分配是通过 std::1::vector<storage::KeyInfo, std::1::allocator>::resize 函数进行的,这是 C++ STL 标准库中的 vector 类型的一个成员函数,用于改变 vector 的大小。

错误上下文: 日志显示,这个写入操作是在执行 info keyspace 命令时发生的,这通常是一个用于获取 Redis 数据库状态信息的命令。

调用栈: 调用栈显示了从命令执行到发生错误的函数调用路径,包括 PikaClientConn::DoCmd、InfoCmd::InfoKeyspace 等函数。

错误处理: 日志的最后部分显示 ABORTING,表示程序因为检测到这个错误而终止执行。

针对这个问题,你需要检查 storage::Redis::ScanStreamsKeyNum 函数在第 358 行的代码,找出为什么会出现写入超出缓冲区大小的数据。可能的原因包括:

错误的数组索引或循环条件,导致写入超出了数组的界限。 错误的内存分配或释放逻辑,可能导致了内存越界。 修复这个问题通常需要确保所有对缓冲区的写入操作都不超过其分配的大小,并且循环和条件语句正确地限制了访问范围。在修复后,重新编译并运行程序,以确保问题不再出现。

AI修改建议

key_infos->resize(6); // 确保vector至少有6个元素

wangshao1 commented 2 weeks ago

是redis.cc scankeynum里resize大小不对吗?

Issues-translate-bot commented 2 weeks ago

Bot detected the issue body's language is not English, translate it automatically.


Is the resize size in redis.cc scankeynum wrong?

chenbt-hz commented 2 weeks ago

是redis.cc scankeynum里resize大小不对吗?

是吧。你看是改成resize(6)还是删除ScanStreamsKeyNum(&((*key_infos)[5]))?

Status Redis::ScanKeyNum(std::vector<KeyInfo>* key_infos) {
  key_infos->resize(5);
  rocksdb::Status s;
  s = ScanStringsKeyNum(&((*key_infos)[0]));
  if (!s.ok()) {
    return s;
  }
  s = ScanHashesKeyNum(&((*key_infos)[1]));
  if (!s.ok()) {
    return s;
  }
  s = ScanListsKeyNum(&((*key_infos)[2]));
  if (!s.ok()) {
    return s;
  }
  s = ScanZsetsKeyNum(&((*key_infos)[3]));
  if (!s.ok()) {
    return s;
  }
  s = ScanSetsKeyNum(&((*key_infos)[4]));
  if (!s.ok()) {
    return s;
  }
  s = ScanStreamsKeyNum(&((*key_infos)[5]));
  if (!s.ok()) {
    return s;
  }

  return Status::OK();
}
wangshao1 commented 2 weeks ago

嗯,我提了pr,你帮忙看下。我本地测试没有问题了。

Issues-translate-bot commented 2 weeks ago

Bot detected the issue body's language is not English, translate it automatically.


Well, I submitted a PR, please help me take a look at it. My local test has no problem.