[libpas] Support compact reservations >=128MiB
Component: libpas / bmalloc allocator | 5b0cfbc
libpas는 bmalloc, TZone, isoheap의 기반이 되는 allocator입니다. 내부 pointer 상당수를 고정된 virtual reservation 하나의 base 기준 3바이트 "compact" offset으로 저장합니다. 최소 alignment가 8B이므로, 24비트를 3만큼 shift해도 표현 범위는 128MiB에 그칩니다. 그래서 compact 주소로 참조되는 객체(view, directory, heap, size class, tree node)는 모두 이 영역 안에서 할당되어야 합니다. 이때 영역 내부의 할당은 위쪽으로만 증가하는 bump pointer 하나로 처리되어 왔습니다.
한편 pointer type마다 alignment와 decode shift가 고정되어 있습니다. decode된 compact pointer는 유효한 metadata 주소로 그대로 신뢰되기 때문에, layout과 alignment invariant는 보안과 직결됩니다. heap enumerator 역시 reservation의 bump 범위를 알아야 정상적으로 동작합니다. 이 enumerator는 out-of-process 도구와 crash reporter가 heap을 읽을 수 있도록 지원하는 구성요소입니다.
이 commit은 compact reservation을 128MiB에서 256MiB로 확장하고, 두 개의 bump allocation front로 나눴습니다. 먼저 bottom front는 위쪽으로 증가하며, alignment가 16B 미만인 객체를 최대 128MiB까지 담당합니다. 반대로 top front는 아래쪽으로 증가하며, 16B-aligned 객체만 전체 256MiB 범위 안에서 담당합니다.
이를 위해 PAS_DEFINE_OVERALIGNED_COMPACT_PTR type이 새로 추가되었습니다. pointer 크기는 3B 그대로지만 shift를 3이 아닌 4로 적용하므로 256MiB까지 주소 지정이 가능합니다. 이 type은 directory, heap, cartesian tree node, size directory pointer type에 적용되었습니다. 그 밖에 enumerator, immortal heap, crash-report 코드가 함께 수정되었고, reservation과 enumeration에 대한 테스트가 새로 추가되었습니다. 사용되지 않던 ptr header 두 개도 제거되었습니다.
Compact reservation layout (offsets from reservation base)
256MiB ┬───────────────────────────────┐
│ top front (bumps DOWN) │
│ only >=16B-aligned objects │
│ addressed via overaligned │
│ compact ptr (idx << 4) │
├───────────────────────────────┤ <- pas_compact_heap_reservation_top_bump
│ (free gap shared by fronts) │
128MiB ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ limit of bottom front
│ │
├───────────────────────────────┤ <- pas_compact_heap_reservation_bump
│ bottom front (bumps UP) │
│ any alignment <16B allowed │
│ standard compact ptr (idx<<3)│
0MiB ┴───────────────────────────────┘
Both pointer kinds decode relative to the reservation BASE,
even for objects living in the top front.
Significance
50GiB가 넘는 대용량 메모리 process에서는 128MiB compact reservation이 고갈되어 crash하는 사례가 나타나기 시작했습니다. 이번 변경으로 segregated view나 thread별 TLC 같은 hot metadata를 키우지 않고도 이 failure mode가 제거되었습니다. 다만 그 결과 reservation 내부에서 libpas metadata와 객체가 놓이는 위치도 달라졌습니다.
Audit directions
이 commit은 compact pointer의 주소 지정 모델을 바꿨습니다. 동시에 allocator에서 가장 신뢰도가 높은 metadata 경로에 아래쪽으로 증가하는 두 번째 allocation front를 추가했습니다.
- Front 간 산술 연산.
try_allocate_bottom/try_allocate_top과pas_compact_heap_reservation_try_allocate에서 두 bump 값을 서로 어떻게 비교하는지 살펴볼 필요가 있습니다. 128MiB bottom 한계와의 비교도 함께 확인해야 합니다. 특히 alignment 계산 과정의 overflow나 underflow 여부가 점검 대상입니다. - Pointer type과 front의 일치 여부. overaligned가 아닌 compact pointer type이 top front 할당을 받을 수 있는 경로가 있는지 확인해야 합니다. 이 경우 24비트 index가 조용히 잘리거나 잘못 decode될 수 있기 때문입니다. 반대로 변환된 type(bitfit directory, heap, cartesian tree node, segregated size directory)이 항상 16B-aligned로만 할당되는지도 확인이 필요합니다. immortal heap이나 manual-alignment 할당처럼 누락된 호출 지점이 하나라도 있으면, 잘못 decode된 metadata pointer가 생성될 수 있습니다. alignment 요청이 어느 front로 라우팅되는지는
pas_immortal_heap의bump_is_ok와pas_immortal_heap_allocate_with_manual_alignment에서 확인할 수 있습니다. - 두 범위에 대한 enumeration.
pas_enumerator와pas_enumerate_initially_unaccounted_pages가 두 개의 bump 범위를 어떻게 처리하는지 살펴볼 필요가 있습니다. 특히 out-of-process reader가 신뢰할 수 없거나 손상된 대상 process를 파싱하는 상황이 점검 대상입니다. top 또는 bottom bump 값이 조작되어 있으면 범위를 벗어난 copy나 read로 이어질 가능성이 있습니다. 의도된 invariant는pas_report_crash_pgm_report.h와 새로 추가된 테스트에 드러나 있습니다. - 동시성. 여러 thread가 동시에 할당하는 상황에서 두 bump pointer 주변의 locking이나 atomicity가 올바르게 보장되는지 점검해야 합니다.