Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

3.5.1+: mi_free_size uses mi_free_small for small sizes with MI_PAGE_META_IS_ALIGNED, corrupting the heap when a larger block is freed with a small size

Đã đóng
#1,423 6 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 5 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
65/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
c
Lĩnh vực
backend

Hướng nghiên cứu

Start in src/free.c at the mi_free_size branch changed between v3.5.0 and v3.5.1, then build and run the supplied C++ reproducer with the stated release configurations. Compare the page-alignment and page-map paths, and verify that the completed change prevents heap corruption while preserving appropriate handling of an undersized delete.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Summary

Since v3.5.1, mi_free_size (used by sized operator delete(void*, size_t)) takes the mi_free_small path for any size <= MI_SMALL_SIZE_MAX when MI_PAGE_META_IS_ALIGNED is set. mi_free_small finds the page by aligning the pointer down instead of using the page map, so if the block actually lives in a larger page, the "page" header is garbage and the heap is corrupted (SEGV in _mi_page_free_collect / mi_page_update_sample_countdown via mi_free_try_collect_mt, or corrupted thread-free list (possibly due to a cross-thread double free)).

Up to v3.5.0 the same code worked in practice (the #if was MI_PAGE_META_SMALL_IS_ALIGNED only, so the regular page-map lookup was used).

I realize the caller is technically at fault: the block was allocated with malloc(2000+) but released with a sized delete whose size is tiny (std::unique_ptr<T> default deleter on a variable-size record with a flexible array member, sizeof(T)==4). This is UB per the C++ standard, and we are fixing our code. I'm reporting because (a) this was a silent behavior change in a patch release, and a hard-to-diagnose crash in release builds, and (b) debug and secure builds of 3.5.3 do not report it (no mi_free_size ... less than the allocated block size message and no crash in our real application), so it is very hard to find. Perhaps release builds could keep the page-map lookup for mi_free_size, or the docs could mention the requirement.

Reproducer

#include <cstdlib>
#include <cstring>
#include <memory>
#include <thread>
#include <vector>
#include <cstdio>

struct Extra { unsigned a; unsigned char data[]; };

int main() {
  for (int round = 0; round < 200; ++round) {
    std::vector<std::unique_ptr<Extra>> v;
    for (int i = 0; i < 2000; ++i) {
      size_t sz = 2000 + (i % 7) * 3000;   // > MI_SMALL_SIZE_MAX
      auto* p = static_cast<Extra*>(malloc(sz));
      memset(p, 0, sz);
      v.emplace_back(p);                   // default_delete -> operator delete(p, sizeof(Extra)==4)
    }
    std::thread t([&] { v.clear(); });     // cross-thread free
    t.join();
    std::vector<void*> junk;               // churn the same pages
    for (int i = 0; i < 5000; ++i) junk.push_back(malloc(3000));
    for (auto* j : junk) free(j);
  }
  puts("done");
}

Build (shared mimalloc, release, default CMake options, -DMI_USE_CXX=ON):

g++ -O2 -fsized-deallocation repro.cpp -o repro /path/to/libmimalloc.so.3 -pthread

Results (Rocky Linux 9.8, glibc 2.34, GCC 15.2, x86_64, Release builds from the GitHub tags)

mimalloc result
v3.4.5 done
v3.5.0 done
v3.5.1 SIGSEGV
v3.5.3 SIGSEGV
v3.5.4 SIGSEGV

In our real application (a gRPC server, free from a different thread) the same change shows: 3.4.5 and 3.5.0 pass, 3.5.1/3.5.2/3.5.3/3.5.4 crash (several full runs each), while v3.5.3 built with MI_DEBUG_FULL=ON or MI_SECURE=ON ran clean. MI_PROFILE=OFF does not help.

Diffing v3.5.0..v3.5.1, src/free.c changes mi_free_size from #if MI_PAGE_META_SMALL_IS_ALIGNED to #if MI_PAGE_META_SMALL_IS_ALIGNED || MI_PAGE_META_IS_ALIGNED for the size <= MI_SMALL_SIZE_MAX branch calling mi_free_small(p), which I believe is the trigger.

Ngôn ngữ chính
C
Star
13.4k
Fork
1.2k
Merge trung bình
4 ngày 8 giờ
Pull request đã merge (30 ngày)
8

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của microsoft/mimalloc

Tất cả issue của microsoft/mimalloc

Issue tương tự

Thêm issue về C

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.