2012-06-09 2 views
5

Возможно, это вопрос новичков, но есть ли способ в C/C++, чтобы функция не принимала указатель на локальную переменную?Предотвращение локальных указателей

Рассмотрим этот код:

int* fun(void) 
{ 
int a; 
return &a; 
} 

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

int* g; 

void save(int* a) 
{ 
g = a; 
} 

void bad(void) 
{ 
int a; 
save(&a); 
} 

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

void save(int __this_pointer_must_not_be_local__ * a) 
{ 
g = a; 
} 

Спасибо заранее, если кто-то знает ответ.

+1

отзывов коментариев? ... профилировщики кода, такие как lint? –

+0

Обзор кода, статический анализ. То, о чем вы просите, на самом деле очень и очень сложно. –

+1

Что делать, если я хотел сделать 'void f() {int b; save (&b);/* do stuff */save (NULL);} '? Это не обязательно тот факт, что переменная является« локальной », что имеет значение: это также было бы плохо. int * p = new int(); save (p); delete p; ' –

ответ

0

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

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

+0

Но если кулачок компилятора распознает, когда функция пытается вернуть локальный указатель, и если в качестве предложения OP есть атрибут, почему компилятор не может использовать одну и ту же логику для генерации предупреждения? –

+0

@ScottHunter Поскольку компилятор не может достоверно определить его, статически анализируя код. Хранение указателя в глобальной переменной - это только один способ, которым вы можете обойти проверку: вы можете сохранить его в элементе структуры, преобразовать в массив байтов и т. Д. Добавление проверки настолько ненадежное приведет к поражению цели. – dasblinkenlight

+0

Как это отличается от проверки возврата, которая реализована? –

2

Существует по крайней мере один способ для отладки сборки с помощью отладки кучи (по умолчанию):

//d:\Program Files\Microsoft Visual Studio ?\VC\crt\src\dbgint.h 
\#define nNoMansLandSize 4 
typedef struct _CrtMemBlockHeader 
{ 
    struct _CrtMemBlockHeader * pBlockHeaderNext; 
    struct _CrtMemBlockHeader * pBlockHeaderPrev; 
    char *      szFileName; 
    int       nLine; 
    size_t      nDataSize; 
    int       nBlockUse; 
    long      lRequest; 
    unsigned char    gap[nNoMansLandSize]; 
    /* followed by: 
    * unsigned char   data[nDataSize]; 
    * unsigned char   anotherGap[nNoMansLandSize]; 
    */ 
} _CrtMemBlockHeader; 
\#define pbData(pblock) ((unsigned char *)((_CrtMemBlockHeader *)pblock + 1)) 

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

if (\*((int\*)pointer-1) == 0xFDFDFD) { // stack pointer } 
Смежные вопросы