Страницы

Поиск по вопросам

среда, 3 октября 2018 г.

Как узнать, можно ли разыменовать указатель?

У меня возникла некоторая проблема: у меня в одной части программы используется объдинение из указателя char* и просто char. Хотелось бы вывести оба этих элемента (по-разному их интерпретируя, разумеется). Но, если в объединении хранится символ, указатель разыменовывать нельзя — иначе упадём. Как заранее выяснить, не приведёт ли разыменовывание к сегфолту?
Кончено, можно было бы завести рядышком специальное поле, в котором хранить информацию о том, что лежит в объединии. Но для этого нужно переписать большую часть кода, что вряд ли подходит, и, наверняка, есть менее глобальное решение.


Ответ

Вот есть один способ, правда, он непереносим и будет работать лишь на Linux. Нужно посмотреть на таблицу памяти, выделеной процессу. Если область памяти, на которую указывает указатель, помечена как доступная для чтения, значит, оный указатель можно разыменовать, и вывести содержимое той памяти. Если же нужно записать что-то в эту память, следует смотреть на второй флаг.
Конечно, такой вариант скорее подходит лишь для целей отладки. Но, возможно, и на других системах можно как-нибудь выяснить корректность указателя.
Идея кода была взята из исходников утилиты pmap. Подробнее о формате файла /proc/self/maps можно почитать в справочном руководстве proc(5)
bool can_i_read(void* p) { uintptr_t begin, end; char readable, writable, executable, mapped; FILE* fp = fopen("/proc/self/maps", "r"); if (!fp) { return false; } while (fscanf(fp, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c", &begin, &end, &readable, &writable, &executable, &mapped) == 6) { if (begin <= (uintptr_t)p && (uintptr_t)p < end) { fclose(fp); // если нужно проверить доступность на запись, // следует смотреть флаг writable return readable == 'r'; } // не зациклимся — перед концом всегда будет перевод строки while (fgetc(fp) != '
') ; } fclose(fp); return false; }
Работоспособность проверена на Ubuntu 14.04.4 / Linux 4.1.15

Комментариев нет:

Отправить комментарий