ненулевое значение зарезервированного указателя

Как я могу создать зарезервированное значение указателя?

Контекст таков: я думал о том, как реализовать структуру данных для динамического языка сценариев (я не планирую реализовывать это — просто удивляюсь, как это будет сделано).

Строки могут содержать произвольные байты, включая NUL. Таким образом, необходимо хранить значение отдельно. Для этого требуется указатель (для указания на массив) и номер. Первый трюк заключается в том, что если указатель равен NULL, он не может быть допустимой строкой, поэтому число может использоваться для фактического целого числа.

Если можно создать второе зарезервированное значение указателя, это можно использовать, чтобы подразумевать, что другое поле теперь используется в качестве значения с плавающей запятой. Можно ли это сделать?

Одна мысль состоит в том, чтобы mmap () адрес не имел разрешений, что также можно сделать, чтобы заменить использование указателя NULL.

2

Решение

В любой современной системе вы можете просто использовать значения указателя 1, 24095 для таких целей. Другой частый выбор (uintptr_t)-1, который технически уступает, но используется чаще, чем 1 тем не менее.

Почему эти ценности «безопасны»?
Современные системы защищают от доступа к указателю NULL, делая невозможным сопоставление чего-либо с нулевым виртуальным адресом. Практически любая разыменование указателя NULL попадет в эту несуществующую область, и аппаратное обеспечение сообщит системе ОС о том, что произошло что-то плохое, что заставит ОС вызвать сбой процесса.
Поскольку страницы виртуальной памяти выровнены по страницам (по крайней мере, 4 КБ на текущем оборудовании), и ничто не сопоставлено с нулевым адресом, ничто не может быть сопоставлено со всем диапазоном 0, ..., 4095защищая все эти адреса одинаково, и вы можете использовать их в качестве значений специального назначения.

Сколько места в виртуальной памяти зарезервировано для этой цели — системный параметр, в Linux это контролируется /proc/sys/vm/mmap_min_addrи пользователь root может изменить его на ноль, что отключило бы эту защиту (что было бы не очень разумной идеей). По умолчанию в Ubuntu 64 КБ (т. Е. 16 страниц).

Это также причина, почему (uintptr_1)-1 менее безопасен, чем 1; даже если любая загрузка более одного байта попадет на нулевую страницу, адрес (uintptr_1)-1 сам по себе не обязательно защищен таким образом. Следовательно, выполнение строковых операций на (char*)-1 не обязательно Segfault.

Редактировать:
Мое оригинальное объяснение со специальным отображением, кажется, было немного устаревшим, возможно, именно так все и было на старой платформе Mac / PPC. Несмотря на то, что эффект практически одинаков, я изменил детали ответа, чтобы отразить современный Linux. Во всяком случае, важный момент не как достигается защита нулевой страницы, важно то, что любая нормальная, современная система будет иметь немного защита нулевой страницы, которая охватывает по крайней мере упомянутый диапазон адресов. Некоторые подробности можно найти в этом ответе SO: https://stackoverflow.com/a/12645890/2445184

6

Другие решения

В стандарте C (и стандарте C ++) подход, который на 100% действителен и работает, прост: объявите переменную, используйте ее адрес в качестве магического значения.

char *ptr;
char magic;
if (ptr == &magic) { ... }

Это гарантирует, что magic никогда не будет перекрываться с другим объектом.

Значения магического указателя, такие как (char *) 1 тоже есть свои преимущества, но их легко ошибиться (даже если вы игнорируете теоретические реализации, где (char *) 1 может быть действительным объектом, если вы используете (int *) 1 в качестве значения магического указателя, а оптимизатор предполагает int * значения выровнены надлежащим образом, это может убрать проверки, которые являются недопустимыми только в 100% действительном коде, а не в вашем коде), которые я бы рекомендовал стандартным подходом, и при желании временно переключиться на значения магического указателя, только если вы обнаружите, что они помогают вам отладки.

5

mmapЕсли адрес уже назначен, произойдет сбой. Вероятно, было бы лучше использовать адрес некоторой статической переменной или функции. Или получить уникальный адрес через malloc(1),

1
По вопросам рекламы [email protected]