Подтвердить что ты не робот

Тестирование указателей на достоверность (C/С++)

Есть ли способ определить (программно, конечно), если данный указатель "действителен"? Проверка на NULL проста, но как насчет таких вещей, как 0x00001234? При попытке разыменовать этот тип указателя возникает исключение/сбой.

Предпочтителен кросс-платформенный метод, но для платформы (для Windows и Linux) тоже подходит.

Обновление для уточнения: Проблема заключается не в устаревших/освобожденных/неинициализированных указателях; вместо этого я реализую API, который принимает указатели от вызывающего (например, указатель на строку, дескриптор файла и т.д.). Вызывающий может отправить (по назначению или по ошибке) недопустимое значение в качестве указателя. Как предотвратить сбой?

4b9b3361

Ответ 1

Обновление для уточнения: Проблема не в устаревших, освобожденных или неинициализированных указателях; вместо этого я реализую API, который принимает указатели от вызывающего (например, указатель на строку, дескриптор файла и т.д.). Вызывающий может отправить (по назначению или по ошибке) недопустимое значение в качестве указателя. Как предотвратить сбой?

Вы не можете выполнить эту проверку. Просто нет способа проверить, является ли указатель "действительным". Вы должны верить, что, когда люди используют функцию, которая принимает указатель, эти люди знают, что они делают. Если они передают вам 0x4211 в качестве значения указателя, то вам нужно доверять ему, указывая на адрес 0x4211. И если они "случайно" ударят по объекту, то даже если вы будете использовать какую-то страшную операционную систему (IsValidPtr или что-то еще), вы по-прежнему сможете ошибиться и быстро выйти из строя.

Начните использовать нулевые указатели для сигнализации такого рода вещей и сообщите пользователю своей библиотеки, что им не следует использовать указатели, если они склонны случайно передавать неверные указатели, серьезно:)

Ответ 2

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

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

Ответ 3

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

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

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

У Раймонда Чена есть запись в блоге на эту тему: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Ответ 4

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

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

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

Ответ 5

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

Ответ 6

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

Ответ 7

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

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 вместо основного процесса.

Ответ 8

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

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

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

  • отдельные процессы с использованием сокетов (часто передают данные как текст).

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

  • тот же процесс обрабатывает отдельные потоки через очередь сообщений (если частые короткие сообщения).

  • тот же процесс отдельных потоков все передал данные, выделенные из пула памяти.

  • тот же процесс через прямой вызов процедуры - все переданные данные, выделенные из пула памяти.

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

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

Ответ 9

У меня есть много сочувствия к вашему вопросу, так как я сам в почти одинаковой позиции. Я ценю то, о чем говорят многие ответы, и они правильны - подпрограмма, предоставляющая указатель, должна обеспечивать действительный указатель. В моем случае почти немыслимо, что они могли повредить указатель, но если бы они справились, это закончилось бы с МО, и 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);
}

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

Ответ 10

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

Ответ 11

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

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

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

Ответ 12

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

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);
}

Ответ 13

Не очень хорошая политика принимать произвольные указатели в качестве входных параметров в публичном 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)
}

Ответ 14

В 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;
}

возвращения:

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

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

Ответ 15

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

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), поэтому вы не можете надежно защитить его на любой платформе.

Ответ 16

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

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

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

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

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

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

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

Ответ 18

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

И даже в документации microsoft msdn IsBadPtr считается запрещенным. Ну, я предпочитаю работать, а не рушиться. Даже если работа над терминалом может работать некорректно (до тех пор, пока конечный пользователь может продолжить работу с приложением).

По googling Я не нашел полезного примера для Windows - нашел решение для 32-разрядных приложений,

http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2Fsrc%2FdrvCppLib%2Frtti.cpp&obid=58895&obtid=2&ovid=2

но мне также нужно поддерживать 64-битные приложения, поэтому это решение не сработало для меня.

Но я собрал исходные коды вин и сумел приготовить аналогичный код, который тоже работал бы на 64-битных приложениях: здесь добавлен код:

#include <typeinfo.h>   

typedef void (*v_table_ptr)();   

typedef struct _cpp_object   
{   
    v_table_ptr*    vtable;   
} cpp_object;   



#ifndef _WIN64
typedef struct _rtti_object_locator
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    const type_info *type_descriptor;
    //const rtti_object_hierarchy *type_hierarchy;
} rtti_object_locator;
#else

typedef struct
{
    unsigned int signature;
    int base_class_offset;
    unsigned int flags;
    unsigned int type_descriptor;
    unsigned int type_hierarchy;
    unsigned int object_locator;
} rtti_object_locator;  

#endif

/* Get type info from an object (internal) */  
static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr)  
{   
    cpp_object* cppobj = (cpp_object*) inptr;  
    const rtti_object_locator* obj_locator = 0;   

    if (!IsBadReadPtr(cppobj, sizeof(void*)) &&   
        !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) &&   
        !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator)))  
    {  
        obj_locator = (rtti_object_locator*) cppobj->vtable[-1];  
    }  

    return obj_locator;  
}  

И следующий код может определить, действителен ли указатель или нет, вам нужно добавить некоторую проверку NULL:

    CTest* t = new CTest();
    //t = (CTest*) 0;
    //t = (CTest*) 0x12345678;

    const rtti_object_locator* ptr = RTTI_GetObjectLocator(t);  

#ifdef _WIN64
    char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator;
    const type_info *td = (const type_info*)(base + ptr->type_descriptor);
#else
    const type_info *td = ptr->type_descriptor;
#endif
    const char* n =td->name();

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

Одной вещью, которую я все еще боюсь, является выполнение проверки указателя - в коде snipet выше уже есть 3-4 вызова API, которые могут быть перегружены для критически важных приложений.

Было бы хорошо, если бы кто-то мог измерить накладные расходы на проверку указателя, сравнивая, например, с С#/управляемыми вызовами С++.

Ответ 19

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

Ответ 20

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

Ответ 21

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

Ответ 22

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

  • вам по-прежнему нужен способ проверить, назначен ли указатель на стек()

  • вам нужно будет определить, что такое "действительный" указатель:

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

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

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

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

Ответ 23

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

Ответ 24

Добавление к завершенному ответу (-ам):

Предположим, что ваш указатель может содержать только три значения - 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.

Ответ 25

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

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

Ответ 26

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

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

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

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

Ответ 27

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

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

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

Ответ 28

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

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

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

Ответ 29

В Windows я использую этот код:

void * G_pPointer = NULL;
const char * G_szPointerName = NULL;
void CheckPointerIternal()
{
    char cTest = *((char *)G_pPointer);
}
bool CheckPointerIternalExt()
{
    bool bRet = false;

    __try
    {
        CheckPointerIternal();
        bRet = true;
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
    }

    return  bRet;
}
void CheckPointer(void * A_pPointer, const char * A_szPointerName)
{
    G_pPointer = A_pPointer;
    G_szPointerName = A_szPointerName;
    if (!CheckPointerIternalExt())
        throw std::runtime_error("Invalid pointer " + std::string(G_szPointerName) + "!");
}

Использование:

unsigned long * pTest = (unsigned long *) 0x12345;
CheckPointer(pTest, "pTest"); //throws exception