EnglishРусский Map

Pointer provenance

title
Pointer provenance
type
concept
summary
Идея о том, что указатель несёт не только адрес, но и привязку к исходному выделению памяти, с которой обязаны считаться компиляторы
tags
c, cpp, memory-model, compilers
created
2026-04-18
updated
2026-04-18
lang
ru
translation_of
pointer-provenance
source_updated
2026-04-18
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Два указателя могут иметь одинаковый битовый шаблон, но при этом не быть взаимозаменяемыми. Provenance (происхождение) - это дополнительные метаданные ("из какого выделения памяти получен этот указатель?"), которые делают их различимыми в модели памяти языка. Именно это делает недопустимыми некоторые оптимизации компилятора, которые кажутся очевидно корректными на уровне битов, но ломают семантику программы на уровне языка.

Пример nerd-snipe

Если p1 и p2 имеют одинаковый тип, вправе ли компилятор переписать if (p1 == p2) { f(p1); } в if (p1 == p2) { f(p2); }?

На битовом уровне - да, мы ведь только что проверили их равенство. Но с учётом provenance - нет: p1 и p2 могут быть численно равны, но происходить из разных выделений памяти. Передача p2 вместо p1 в f означала бы, что f работает через другой provenance, и любые проверки границ (bounds checks), escape-анализ или рассуждения об алиасинге (aliasing) внутри f относились бы не к тому выделению памяти.

В C и C++ модель памяти настолько неоднозначна, что этот вопрос породил многолетние споры в комитетах по стандартизации. Статья о pointer provenance Ральфа Юнга (Ralf Jung) служит здесь общепринятым первоисточником.

Зачем это компиляторам

Современные компиляторы опираются на правила provenance для обоснования оптимизаций:

  • Анализ псевдонимов (alias analysis). Указатели из разных выделений памяти не могут ссылаться на один и тот же объект (alias); компилятор может переупорядочивать операции чтения (load) и записи (store) вокруг них.
  • Escape-анализ. Указатель, который никогда не выходит за пределы своего выделения памяти, можно сохранить в регистрах.
  • Удаление мёртвых записей (dead store elimination). Записи в память, доступную только через один provenance, можно удалить, как только этот provenance перестаёт существовать.

Каждая из этих оптимизаций строится на уверенности компилятора в том, что одинаковые битовые шаблоны с разным provenance не смешиваются друг с другом.

Почему fil-c делает концепцию наглядной

Большинство реализаций языков отслеживают provenance абстрактно - как свойство абстрактной машины, о которой рассуждает компилятор, стирая его во время выполнения. fil-c делает provenance наблюдаемым в рантайме: каждый указатель спарен с AllocationRecord*, который и является provenance. Два указателя с одинаковыми адресами, но разными записями будут вести себя по-разному, поскольку несут разные границы (bounds) и разную достижимость для GC. Поэтому на вопрос о переписывании кода компилятором Fil-C даёт однозначный ответ: эти два указателя не взаимозаменяемы, так как различаются связанные с ними записи.

Это делает Fil-C удобной ментальной моделью для понимания того, что означает "provenance" в реальной системе, в отличие от того, чем он является в абстрактной машине комитета по стандартизации.

Связанные страницы

  • simplified-model-of-fil-c - где подробно описана связка provenance и capability
  • fil-c - сам проект
  • no-silver-bullet - provenance относится к сущностной сложности (essential complexity) модели памяти C/C++; никакие трюки оптимизации не устраняют её