У меня возникла некоторая проблема: у меня в одной части программы используется объдинение из указателя 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
Комментариев нет:
Отправить комментарий