Skip to content

[BUG] wtr::HashMap::operator[] Reference Invalidation during Rehash #24

@Winteradio

Description

@Winteradio

Open · Winteradio opened this issue on March 4, 2026

⚠️ Issue Description

wtr::HashMap에서 operator[]를 사용하여 자기 자신에 대한 대입 연산(m_map[A] = m_map[B])을 수행할 때,
특정 조건에서 메모리 오염(Memory Corruption) 또는 **크래시(Crash)**가 발생할 수 있는 잠재적 위험이 확인되었습니다.

이는 std::unordered_map에서는 발생하지 않는 wtr::HashMap만의 구조적 특징으로 인한 사이드 이펙트입니다.

🔍 Problematic Scenario

다음과 같이 하나의 Map 인스턴스에 대해 읽기와 쓰기를 동시에 수행하는 구문에서 문제가 발생합니다.

// ePNG 키가 존재하지 않아 삽입이 필요한 상황이라고 가정
// eJPG 키는 이미 존재하며 특정 파서 객체를 가리키고 있음
m_parserMap[eExtension::ePNG] = m_parserMap[eExtension::eJPG];

🛠️ Cause Analysis

이슈의 근본 원인은 Open Addressing 기반 컨테이너의 데이터 지역성(Data Locality) 확보 전략과 Rehash 메커니즘의 충돌에 있습니다.

1. Pointer Stability (포인터 안정성) 결여

  • std::unordered_map (Node-based): 노드 기반 체이닝 방식을 사용하므로 새로운 요소가 삽입되어도 기존 요소들의 메모리 주소는 고정됩니다.
    따라서 m_map[B]가 반환한 레퍼런스는 항상 안전합니다.
  • wtr::HashMap (Array-based): 성능 최적화를 위해 연속된 메모리 배열을 사용합니다.
    삽입 시 부하율(Load Factor)을 초과하면 Rehash가 발생하여 전체 데이터를 새로운 메모리 공간으로 복사(이사)합니다.

2. Execution Order & Use-After-Free

m_map[A] = m_map[B] 구문 실행 시 시점 차이로 인해 지뢰가 발생합니다.

  1. 우항 평가: m_map[B]가 호출되어 내부 데이터의 레퍼런스(Value&)를 반환합니다. (현재 주소: 0x100)
  2. 좌항 평가: m_map[A]가 호출되어 삽입을 시도합니다. 이때 공간이 부족하여 Rehash가 실행됩니다.
  3. 메모리 무효화: 모든 데이터가 0x500 주소로 이동하고 기존 0x100 주소는 해제됩니다.
  4. 대입 실패: 이미 해제된 0x100 주소의 데이터를 참조하여 대입을 시도하므로 Dangling Reference 이슈가 발생합니다.

📊 Comparison Summary

Feature std::unordered_map wtr::HashMap
Structure Node-based (Chaining) Array-based (Open Addressing)
Pointer Stability Safe (Addresses never change) Dangerous (Addresses change on Rehash)
Self-Assignment map[A] = map[B] (Safe) map[A] = map[B] (Crash Risk)
Performance Slower (Cache Misses) Faster (Cache Locality)

💡 Note

이 이슈는 wtr::HashMap이 성능을 위해 선택한 Contiguous Memory 구조의 필연적인 특성입니다.
std::vector의 요소를 레퍼런스로 들고 있다가 push_back으로 인해 메모리 재할당이 일어나는 상황과 동일한 메커니즘의 주의가 필요합니다.


Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions