Как обрабатывать чтение / запись нарушения доступа [дубликат]

Обозначение скобок позволяет вам получить доступ к свойствам по имени, хранящимся в переменной:

var obj = { "abc" : "hello" };
var x = "abc";
var y = obj[x];
console.log(y); //output - hello

obj.x не будет работать в этом случае.

75
задан starblue 15 February 2009 в 19:05
поделиться

25 ответов

В общем, это невозможно сделать. Вот один особенно неприятный случай:

struct Point2d {
    int x;
    int y;
};

struct Point3d {
    int x;
    int y;
    int z;
};

void dump(Point3 *p)
{
    printf("[%d %d %d]\n", p->x, p->y, p->z);
}

Point2d points[2] = { {0, 1}, {2, 3} };
Point3d *p3 = reinterpret_cast<Point3d *>(&points[0]);
dump(p3);

На многих платформах это будет распечатываться:

[0 1 2]

Вы вынуждаете систему времени выполнения неправильно интерпретировать бит памяти, но в этом случае он не будет разбиваться, потому что бит все имеет смысл. Это часть дизайна языка (посмотрите на полиморфизм C-стиля с struct inaddr, inaddr_in, inaddr_in6), поэтому вы не можете надежно защитить его на любой платформе.

68
ответ дан Peter Mortensen 24 August 2018 в 23:19
поделиться
  • 1
    Вероятно, это правильный ответ, но я думаю, что простая функция, которая проверяет общие ячейки памяти hexspeak, будет полезна для общей отладки ... Прямо сейчас у меня есть указатель, который иногда указывает на 0xfeeefeee, и если бы у меня была простая функция, использовать для перцовых утверждений вокруг Это сделало бы намного легче найти виновника ... РЕДАКТИРОВАТЬ: Хотя было бы непросто написать один сам, я думаю .. – quant 24 June 2013 в 00:17
  • 2
    @quant проблема заключается в том, что некоторые C и C ++-коды могли бы выполнять арифметику указателя на недопустимом адресе без проверки (на основе определения мусора, мусора) и, таким образом, передаются в "арифметически модифицированном" указатель с одного из тех известных недопустимых адресов. Обычные случаи ищут метод из несуществующей vtable на основе недопустимого адреса объекта или одного неправильного типа или просто считывают поля из указателя на структуру, которая не указывает на один. – rwong 23 December 2014 в 22:49
  • 3
    Это в основном означает, что вы можете использовать только индексы массивов из внешнего мира. API, который должен защищаться от вызывающего, просто не может иметь указателей в интерфейсе. Тем не менее, было бы неплохо иметь макросы для использования в утверждениях о правильности указателей (которые вы обязаны иметь внутренне). Если указатель должен указывать внутри массива, начальная точка и длина которого известны, это можно явно проверить. Лучше умереть от нарушения утверждения (задокументированная ошибка), чем deref (недокументированная ошибка). – Rob 23 January 2015 в 22:18

В Win32 / 64 есть способ сделать это. Попытайтесь прочитать указатель и поймать полученный SEH exeception, который будет брошен на неудачу. Если он не бросает, то это действительный указатель.

Проблема с этим методом заключается в том, что он просто возвращает, можете ли вы читать данные из указателя. Это не гарантирует гарантии безопасности типа или любого другого числа инвариантов. В общем, этот метод хорош для другого, кроме как сказать «да, я могу прочитать это конкретное место в памяти за время, прошедшее сейчас».

Короче говоря, не делайте этого;)

Raymond Chen имеет сообщение в блоге на эту тему: http://blogs.msdn.com/oldnewthing/archive /2007/06/25/3507294.aspx

26
ответ дан Adam Rosenfield 24 August 2018 в 23:19
поделиться
  • 1
    Это правильный ответ. – Foredecker 15 February 2009 в 17:08
  • 2
    Все еще не скажу, правильно ли вы указываете ... – Tim Ring 15 February 2009 в 17:11
  • 3
    @Tim, в C ++ нет возможности сделать это. – JaredPar 15 February 2009 в 17:14
  • 4
    Это только «правильный ответ». если вы определяете «действительный указатель», поскольку "не вызывает нарушение доступа / segfault". Я бы предпочел определить его как «указывает на значимые данные, выделенные для цели, которую вы собираетесь использовать». Я бы сказал, что это лучшее определение действительности указателя ...;) – jalf 15 February 2009 в 17:22
  • 5
    @ Кристофер, очень верно. Я должен был сказать: «Я могу прочитать это конкретное место в памяти за время, которое теперь прошло». – JaredPar 15 February 2009 в 17:42

Посмотрите на этот и этот вопрос. Также взгляните на интеллектуальные указатели.

7
ответ дан Community 24 August 2018 в 23:19
поделиться

Не очень хорошая политика принимать произвольные указатели в качестве входных параметров в публичном API. Лучше иметь типы «простых данных», например, целое число, строку или структуру (я имею в виду классическую структуру с простыми данными внутри, конечно, официально что-либо может быть структурой).

Почему? Хорошо, потому что, как говорят другие, нет стандартного способа узнать, был ли вам задан действительный указатель или указатель на нежелательный.

Но иногда у вас нет выбора - ваш API должен принять указатель.

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

Можете ли вы дважды проверить? Хорошо, что я сделал в таком случае, чтобы определить инвариант для типа, на который указывает указатель, и вызвать его, когда вы его получите (в режиме отладки). По крайней мере, если инвариант выходит из строя (или падает), вы знаете, что вам присвоено плохое значение.

// API that does not allow NULL
void PublicApiFunction1(Person* in_person)
{
  assert(in_person != NULL);
  assert(in_person->Invariant());

  // Actual code...
}

// API that allows NULL
void PublicApiFunction2(Person* in_person)
{
  assert(in_person == NULL || in_person->Invariant());

  // Actual code (must keep in mind that in_person may be NULL)
}
2
ответ дан Daniel Daranas 24 August 2018 в 23:19
поделиться
  • 1
    re: & quot; передать простой тип данных ... как строку & quot; Но в C ++ строки чаще всего передаются как указатели на символы, (char *) или (const char *), поэтому вы возвращаетесь к указателям прохода. И ваш пример пропускает in_person как ссылку, а не как указатель, поэтому сравнение (in_person! = NULL) подразумевает, что есть некоторые сравнения объектов / указателей, определенные в классе Person. – Jesse Chisholm 24 April 2014 в 15:43
  • 2
    @JesseChisholm По строке я имел в виду строку, т. Е. Std :: string. Я не рекомендую использовать char * как способ хранения строк или их передачи. Не делай этого. – Daniel Daranas 24 April 2014 в 15:50
  • 3
    @JesseChisholm Почему-то я ошибся, когда я ответил на этот вопрос пять лет назад. Ясно, что нет смысла проверять, является ли Person & amp; нулевой. Это даже не компилируется. Я имел в виду использовать указатели, а не ссылки. Я исправил это сейчас. – Daniel Daranas 24 April 2014 в 15:51

Вы знаете, новый драйвер (по крайней мере, на Linux), который способен на это, вероятно, не будет так сложно писать.

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

0
ответ дан dicroce 24 August 2018 в 23:19
поделиться

Во-первых, я не вижу смысла пытаться защитить себя от вызывающего, намеренно пытаясь вызвать крушение. Они могут легко сделать это, пытаясь получить доступ через недействительный указатель. Есть много других способов - они могут просто перезаписать вашу память или стек. Если вам нужно защититься от такого рода вещей, вам нужно работать в отдельном процессе с использованием сокетов или другого IPC для связи.

Мы пишем довольно много программного обеспечения, которое позволяет партнерам / клиентам / пользователям для расширения функциональности. Неизбежно любая ошибка сообщается нам в первую очередь, поэтому полезно иметь возможность легко показать, что проблема заключается в подключаемом коде. Кроме того, есть проблемы с безопасностью, и некоторые пользователи более доверяют другим.

Мы используем несколько разных методов в зависимости от требований производительности и пропускной способности и надежности. Из наиболее предпочтительных:

  • отдельных процессов с использованием сокетов (часто передающих данные как текст).
  • отдельные процессы с использованием разделяемой памяти (если большие объемы данных должны проходить).
  • то же самое обрабатывает отдельные потоки через очередь сообщений (если частые короткие сообщения).
  • тот же процесс отдельных потоков все передал данные, выделенные из пула памяти.
  • тот же процесс через прямой вызов процедуры - все переданные данные, выделенные из пула памяти.

Мы стараемся никогда не прибегать к тому, что вы пытаетесь сделать, когда имеете дело с сторонним программным обеспечением - особенно когда нам предоставляются плагины / библиотеки как двоичные, а не исходные.

Использование пула памяти довольно просто в большинстве случаев и не должно быть неэффективным. Если вы выбрали данные в первую очередь, тогда тривиально проверить указатели на значения, которые вы выделили. Вы также можете сохранить выделенную длину и добавить «магические» значения до и после данных, чтобы проверить допустимый тип данных и переполнение данных.

6
ответ дан Dipstick 24 August 2018 в 23:19
поделиться

Добавление к принятому ответу:

Предположим, что ваш указатель может содержать только три значения - 0, 1 и -1, где 1 означает действительный указатель, -1 недопустимый и 0 другой недействительный. Какова вероятность того, что ваш указатель будет NULL, все значения одинаково вероятны? 1/3. Теперь возьмите действительный аргумент, поэтому для каждого недопустимого случая у вас есть соотношение 50:50, чтобы поймать все ошибки. Выглядит хорошо? Масштабируйте это для 4-байтового указателя. Возможны 2 ^ 32 или 4294967294 возможных значения. Из них только одно значение верно, одно значение NULL, и вы по-прежнему остаетесь с 4294967292 другими недопустимыми случаями. Пересчитайте: у вас есть тест на 1 из (4294967292+ 1) неверных случаев. Вероятность 2.xe-10 или 0 для большинства практических целей. Такова тщетность проверки NULL.

0
ответ дан dirkgently 24 August 2018 в 23:19
поделиться

AFAIK нет способа. Вы должны попытаться избежать этой ситуации, всегда устанавливая указатели на NULL после освобождения памяти.

15
ответ дан Ferdinand Beyer 24 August 2018 в 23:19
поделиться
  • 1
    Установка указателя на null дает вам ничего, кроме, может быть, ложного чувства безопасности. – user 15 February 2009 в 16:51
  • 2
    Это неправда. Особенно в C ++ вы можете определить, удалять ли объекты-члены, проверяя значение null. Также обратите внимание, что в C ++ допустимо удаление нулевых указателей, поэтому безусловное удаление объектов в деструкторах является популярным. – Ferdinand Beyer 15 February 2009 в 16:58
  • 3
    int * p = new int (0); int * p2 = p; delete p; p = NULL; удалить p2; // сбой – user 15 February 2009 в 17:01
  • 4
    zabzonk, и ?? он сказал, что вы можете удалить нулевой указатель. p2 не является нулевым указателем, но является недопустимым указателем. вы должны установить его до нуля. – Johannes Schaub - litb 15 February 2009 в 17:03
  • 5
    Если у вас есть псевдонимы в указанной памяти, только один из них будет установлен в NULL, другие псевдонимы будут болтаться. – jdehaan 11 February 2011 в 06:51

Относительно ответа в этом потоке:

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () для Windows.

Мой совет - держаться подальше от них, кто-то уже разместил это: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Еще одно сообщение по той же теме и тем же автором (я думаю): http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx («IsBadXxxPtr действительно нужно называть CrashProgramRandomly»).

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

7
ответ дан Fredrik 24 August 2018 в 23:19
поделиться
  • 1
    Вероятно, другим способом является использование _CrtIsValidHeapPointer . Эта функция возвращает TRUE, если указатель действителен, и генерирует исключение при освобождении указателя. Как указано, эта функция доступна только в отладочном CRT. – Crend King 23 November 2011 в 17:01

Вот три простых способа для программы C под Linux получить интроспективную информацию о состоянии памяти, в которой она работает, и почему в некоторых контекстах заданы соответствующие сложные ответы.

  1. После вызова метода getpagesize () и округления указателя на границу страницы вы можете вызвать mincore (), чтобы узнать, действительна ли страница и если она входит в состав рабочего процесса. Обратите внимание, что для этого требуются некоторые ресурсы ядра, поэтому вы должны проверить его и определить, действительно ли вызов этой функции подходит для вашего api. Если ваш api будет обрабатывать прерывания или читать из последовательных портов в память, целесообразно называть это, чтобы избежать непредсказуемого поведения.
  2. После вызова stat (), чтобы определить, есть ли / proc / доступный самокаталог, вы можете открывать и читать через / proc / self / maps, чтобы найти информацию о регионе, в котором находится указатель. Изучите man-страницу для proc, псевдо-файловой системы информации процесса. Очевидно, что это относительно дорого, но вы можете уйти с кешированием результата анализа в массив, который вы можете эффективно искать, используя двоичный поиск. Также рассмотрите / proc / self / smaps. Если ваш api предназначен для высокопроизводительных вычислений, тогда программа захочет узнать о / proc / self / numa, которая задокументирована в man-странице для numa, неравномерной архитектуры памяти.
  3. Get_mempolicy (MPOL_F_ADDR) подходит для высокопроизводительных вычислений api, где есть несколько потоков выполнения, и вы управляете своей работой сродством к неравномерной памяти, поскольку она относится к ядрам процессора и ресурсам сокетов. Разумеется, такой api также скажет вам, является ли указатель действительным.

В Microsoft Windows существует функция QueryWorkingSetEx, которая задокументирована в API состояния процесса (также в API NUMA). В качестве следствия сложного программирования NUMA API эта функция также позволит вам выполнять простые «указатели на проверку работоспособности (C / C ++)», поэтому маловероятно, что они будут устаревать не менее 15 лет.

23
ответ дан George Carrette 24 August 2018 в 23:19
поделиться
  • 1
    Первый ответ, который не пытается быть моральным по самому вопросу и на самом деле отлично отвечает на него. Люди иногда не понимают, что действительно нужен такой подход отладки, чтобы найти ошибки, например. Сторонних библиотек или устаревшего кода, потому что даже valgrind находит только дикие указатели при фактическом доступе к ним, а не к примеру. если вы хотите регулярно проверять указатели на достоверность в таблице кеша, которые были перезаписаны из другого места вашего кода ... – lumpidu 17 June 2015 в 13:52
  • 2
    Это должен быть принятый ответ. Я сделал это просто на платформе, отличной от linux. По сути, он раскрывает информацию процесса самому процессу. С учетом этого аспекта он выглядит лучше, чем linux, чем Windows, предоставляя более значимую информацию через API состояния процесса. – minghua 30 November 2015 в 21:39

Как говорили другие, вы не можете надежно обнаружить недопустимый указатель. Рассмотрим некоторые формы, которые может принять недопустимый указатель:

У вас может быть нулевой указатель. Это то, о чем вы могли бы легко проверить и что-то сделать.

У вас может быть указатель где-то за пределами допустимой памяти. То, что составляет действительную память, зависит от того, как среда выполнения вашей системы устанавливает адресное пространство. В системах Unix обычно это виртуальное адресное пространство, начинающееся с 0 и идущее на некоторое количество мегабайт. На встроенных системах это может быть довольно мало. В любом случае он может начинаться не с 0. Если ваше приложение работает в режиме супервизора или эквивалент, ваш указатель может ссылаться на реальный адрес, который может быть или не быть резервным с реальной памятью.

У вас может быть указатель где-то внутри вашу действительную память, даже внутри вашего сегмента данных, bss, стек или кучу, но не указывая на действительный объект. Вариант этого - указатель, который указывал на действительный объект, прежде чем что-то случилось с объектом. Плохие вещи в этом контексте включают освобождение памяти, повреждение памяти или повреждение указателя.

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

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

Лучшее, что вы можете сделать, это разрешить крах и выпустить хорошую диагностическую информацию.

1
ответ дан John Grieggs 24 August 2018 в 23:19
поделиться
  • 1
    re: & quot; вывести некоторую хорошую диагностическую информацию ", есть тр. Поскольку вы не можете проверить правильность указателя, информация, которую вы должны суетиться, минимальна. "Исключение произошло здесь, & quot; может быть, все, что вы получаете. Весь стек вызовов хорош, но требует лучшей структуры, чем предоставляет большинство библиотек времени выполнения C ++. – Jesse Chisholm 24 April 2014 в 15:34

эти ссылки могут быть полезны

_CrtIsValidPointer Проверяет, что указанный диапазон памяти действителен для чтения и записи (только для отладочной версии). http://msdn.microsoft.com/en-us/library/0w1ekd5e.aspx

_CrtCheckMemory Подтверждает целостность блоков памяти, выделенных в куче отладки (только отладочная версия ). http://msdn.microsoft.com/en-us/library/e73x0s4b.aspx

0
ответ дан Khachatur 24 August 2018 в 23:19
поделиться

Эта статья MEM10-C. Определить и использовать функцию проверки указателя говорит, что можно сделать проверку в некоторой степени, особенно в ОС Linux.

0
ответ дан Marek Szanyi 24 August 2018 в 23:19
поделиться

Предотвращение сбоя, вызванного отправкой вызывающего абонента недопустимым указателем, является хорошим способом сделать тихие ошибки, которые трудно найти.

Разве не лучше, если программист, использующий ваш API, получить четкое сообщение о том, что его код подделка, сбив его, а не скрывая?

30
ответ дан Nailer 24 August 2018 в 23:19
поделиться
  • 1
    +1 Неудачная ранняя загрузка и всегда лучший вариант! – Mark Kegel 16 February 2009 в 02:33
  • 2
    В некоторых случаях, однако, проверка плохого указателя сразу же, когда API называется , это , как вы терпите неудачу раньше. Например, что, если API хранит указатель в структуре данных, где он будет отложен позже? Тогда передача API плохим указателем приведет к сбою в некоторой случайной более поздней точке. В этом случае было бы лучше потерпеть неудачу раньше, при вызове API, где первоначально было введено неправильное значение. – peterflynn 11 September 2015 в 02:22

В Unix вы должны использовать ядро ​​syscall, которое проверяет указатель и возвращает EFAULT, например:

#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdbool.h>

bool isPointerBad( void * p )
{
   int fh = open( p, 0, 0 );
   int e = errno;

   if ( -1 == fh && e == EFAULT )
   {
      printf( "bad pointer: %p\n", p );
      return true;
   }
   else if ( fh != -1 )
   {
      close( fh );
   }

   printf( "good pointer: %p\n", p );
   return false;
}

int main()
{
   int good = 4;
   isPointerBad( (void *)3 );
   isPointerBad( &good );
   isPointerBad( "/tmp/blah" );

   return 0;
}

return:

bad pointer: 0x3
good pointer: 0x7fff375fd49c
good pointer: 0x400793

Возможно, есть лучше использовать syscall, чем open () [возможно, доступ], так как есть вероятность, что это может привести к фактической кодовой программе создания файла и последующему закрытию.

0
ответ дан Peeter Joot 24 August 2018 в 23:19
поделиться

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () для Windows. Они занимают время пропорционально длине блока, поэтому для проверки работоспособности я просто проверяю начальный адрес.

0
ответ дан pngaz 24 August 2018 в 23:19
поделиться

У меня много сочувствия на ваш вопрос, так как я сам в почти одинаковой позиции. Я ценю то, что говорят многие ответы, и они правильны - в подпрограмме, указывающей указатель , должен быть предоставлен действительный указатель. В моем случае почти невозможно представить, что они могли испортить указатель, но если они управляли , это будет сбой программного обеспечения MY, и ME, который получит вину: - (

Мое требование не в том, что я продолжаю после ошибки сегментации - это было бы опасно - я просто хочу сообщить, что случилось с клиентом, до завершения, чтобы они могли исправить свой код, а не обвинять меня!

Вот как я нашел это (в Windows): http://www.cplusplus.com/reference/clibrary/csignal/signal/

Чтобы дать синопсис:

#include <signal.h>

using namespace std;

void terminate(int param)
/// Function executed if a segmentation fault is encountered during the cast to an instance.
{
  cerr << "\nThe function received a corrupted reference - please check the user-supplied  dll.\n";
  cerr << "Terminating program...\n";
  exit(1);
}

...
void MyFunction()
{
    void (*previous_sigsegv_function)(int);
    previous_sigsegv_function = signal(SIGSEGV, terminate);

    <-- insert risky stuff here -->

    signal(SIGSEGV, previous_sigsegv_function);
}

Теперь этот появляется , чтобы вести себя так, как я надеюсь (он печатает сообщение об ошибке, а затем завершает программу), - но если кто-то может заметить недостаток, пожалуйста, дайте мне знать!

4
ответ дан Sebastian Mach 24 August 2018 в 23:19
поделиться
  • 1
    Не используйте exit(), он обходит RAII и, следовательно, может вызвать утечку ресурсов. – Sebastian Mach 9 May 2012 в 12:30
  • 2
    Интересно - есть ли другой способ прекратить в этой ситуации аккуратно? И является ли оператор выхода единственной проблемой с этим? Я заметил, что я приобрел «-1». - это только из-за «выхода»? – Mike Sadler 9 May 2012 в 12:46
  • 3
    К сожалению, я понимаю, что это довольно необычная ситуация. Я только что увидел exit(), и мой портативный C ++ Alarm Bell начал звонить. Это должно быть хорошо в этой конкретной ситуации Linux, где ваша программа выйдет в любом случае, извините за шум. – Sebastian Mach 9 May 2012 в 13:15
  • 4
    сигнал (2) не переносится. Используйте sigaction (2). man 2 signal в Linux есть параграф, объясняющий почему. – rptb1 22 October 2015 в 13:22
  • 5
    В этой ситуации я обычно вызываю abort (3), а не exit (3), потому что более вероятно, что вы создадите какую-то отладочную обратную трассировку, которую вы можете использовать для диагностики проблемы после вскрытия. В большинстве Unixen, abort (3) сбрасывает ядро ​​(если разрешены основные дампы), и в Windows он предложит запустить отладчик, если он установлен. – rptb1 22 October 2015 в 13:24

Я видел, что в разных библиотеках используется какой-либо метод для проверки непечатной памяти и т. д. Я считаю, что они просто «переопределяют» методы распределения памяти и удаления (malloc / free), которые имеют некоторую логику, которая отслеживает указатели. Я полагаю, что это излишне для вашего случая использования, но это был бы один из способов сделать это.

0
ответ дан sebnow 24 August 2018 в 23:19
поделиться
  • 1
    К сожалению, это не помогает для объектов с выделенным стеклом. – Tom 15 February 2009 в 17:24

вам следует избегать этих методов, потому что они не работают. blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx - JaredPar

Если они не работают - следующее обновление Windows это исправит? Если они не работают на уровне концепции - функция будет, вероятно, полностью удалена из windows api.

Документация MSDN утверждает, что они запрещены, и причиной этого является, вероятно, недостаток дальнейшей разработки приложения (например, как правило, вы не должны использовать недействительные указатели молча - если вы отвечаете за разработку всего приложения курс) и производительность / время проверки указателя.

Но вы не должны утверждать, что они не работают из-за какого-то блога. В моем тестовом приложении я проверил, что они работают.

1
ответ дан TarmoPikaro 24 August 2018 в 23:19
поделиться

Установка указателя на NULL до и после использования является хорошей техникой. Это легко сделать в C ++, если вы управляете указателями внутри класса, например (строка):

class SomeClass
{
public:
    SomeClass();
    ~SomeClass();

    void SetText( const char *text);
    char *GetText() const { return MyText; }
    void Clear();

private:
    char * MyText;
};


SomeClass::SomeClass()
{
    MyText = NULL;
}


SomeClass::~SomeClass()
{
    Clear();
}

void SomeClass::Clear()
{
    if (MyText)
        free( MyText);

    MyText = NULL;
}



void SomeClass::Settext( const char *text)
{
    Clear();

    MyText = malloc( strlen(text));

    if (MyText)
        strcpy( MyText, text);
}
2
ответ дан Tim Ring 24 August 2018 в 23:19
поделиться
  • 1
    Обновленный вопрос делает мой ответ неправильным, конечно (или, по крайней мере, ответ на другой вопрос). Я согласен с ответами, которые в основном говорят: пусть они рухнут, если они злоупотребляют апи. Вы не можете остановить людей, попавших в большой палец с молотком ... – Tim Ring 16 February 2009 в 00:02

В C ++ нет никаких условий для проверки правильности указателя как общего случая. Очевидно, что NULL (0x00000000) плохой, и различные компиляторы и библиотеки любят использовать «специальные значения» здесь и там, чтобы облегчить отладку (например, если я когда-либо вижу указатель, отображаемый как 0xCECECECE в визуальной студии, я знаю Я сделал что-то не так), но правда в том, что, поскольку указатель - это просто индекс в памяти, почти невозможно сказать, просто взглянув на указатель, если это «правильный» индекс.

Существуют различные трюки, которые вы можете сделать с dynamic_cast и RTTI такими, чтобы гарантировать, что указанный объект имеет тот тип, который вы хотите, но все они требуют, чтобы вы указывали на что-то действительное в первую очередь ,

Если вы хотите, чтобы программа могла обнаруживать «недействительные» указатели, то мой совет таков: установите каждый указатель, который вы объявляете либо NULL, либо действительный адрес сразу после создания, и установите его в NULL сразу после освобождения память, на которую указывает. Если вы прилежны в этой практике, тогда проверка NULL - это все, что вам когда-либо понадобится.

2
ответ дан Toji 24 August 2018 в 23:19
поделиться
  • 1
    Константа нулевого указателя в C ++ (или C, если на то пошло), представлена ​​постоянным интегральным нулем. Множество реализаций используют все-двоичные-нули для представления, но на это не на что рассчитывать. – David Thornley 18 February 2009 в 21:13

Технически вы можете переопределить оператор new (и удалить) и собрать информацию обо всей выделенной памяти, чтобы вы могли иметь способ проверить, действительно ли память кучи. но:

  1. вам по-прежнему нужен способ проверить, назначен ли указатель на стек ()
  2. , вам нужно определить, что является «действительным» указателем:

a) выделена память на этом адресе

b) память на этом адресе является начальным адресом объекта (например, адрес не находится в середине огромного массива)

c) память на этом адресе является начальным адресом объекта ожидаемого типа

. Нижняя строка: подход, о котором идет речь, не является способом C ++, вам необходимо определить некоторые правила, которые гарантируют, что функция получит действительные указатели.

0
ответ дан user 24 August 2018 в 23:19
поделиться

Следующее работает в Windows (кто-то предложил это раньше):

static void copy (void * target, const void * source, int size) {__try {CopyMemory (target, source, size); } __except (EXCEPTION_EXECUTE_HANDLER) {doSomething (- whatever--); }}

Функция должна быть статичной, автономной или статической для некоторого класса. Чтобы проверить только на чтение, скопируйте данные в локальный буфер. Чтобы протестировать запись без изменения содержимого, напишите их. Вы можете проверить только первые / последние адреса. Если указатель недействителен, управление будет передано в «doSomething», а затем вне скобок. Просто не используйте ничего, требующее деструкторов, например CString.

0
ответ дан user2089173 24 August 2018 в 23:19
поделиться

Действительно, что-то может быть сделано в определенном случае: например, если вы хотите проверить, является ли строка указателя строки действительной, использование syscall (fd, buf, szie) syscall может помочь вам сделать магию: пусть fd будет файлом дескриптор временного файла, который вы создаете для теста, и buf, указывающий на строку, которую вы tesing, если указатель недействителен. write () возвращает -1 и errno устанавливает значение EFAULT, указывающее, что buf находится за пределами вашего доступного адресного пространства.

1
ответ дан Wenlin.Wu 24 August 2018 в 23:19
поделиться

Невозможно выполнить эту проверку на C ++. Что делать, если другой код передает вам недопустимый указатель? Вы должны потерпеть крах. Почему? Посмотрите эту ссылку: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx

0
ответ дан zildjohn01 24 August 2018 в 23:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: