Как проверить, доступна ли память?

Я пытаюсь отладить проблему сбоя, когда memcpy пытается получить доступ к несуществующей ячейке памяти и терпит неудачу. Ниже приводится сокращенная версия кода проблемы:

void func_foo(int **a) {
   int *b, c;
   if (*a) {
       b = *a;
   }
   memcpy(&c, b, sizeof(int));//this crashes because address "b" is not accessible.
}

Мой вопрос: есть ли способ проверить, доступна ли память перед попыткой memcpy, или есть другой механизм защиты для предотвращения сбоя здесь? Не вызовет ли проверка **a также сбой в этом случае?


person Deepanjan Mazumdar    schedule 03.06.2013    source источник
comment
memcpy (& c, b, sizeof (int *));   -  person mf_    schedule 03.06.2013
comment
@mf_ Нет, это неправильно.   -  person    schedule 03.06.2013
comment
@ H2CO3 он пытается скопировать адрес памяти в c, но c не является указателем   -  person mf_    schedule 03.06.2013
comment
@mf_ Нет, это тоже неправильно. Он пытается скопировать int из b в c.   -  person    schedule 03.06.2013
comment
@ H2CO3, тогда ответ основан на проверке ** a на наличие мусора?   -  person mf_    schedule 03.06.2013
comment
@mf_ Какой ответ? Мой? Нет. Я ответил только на то, что спросил OP - он хочет знать, указывает ли b (a. K. A. *a) на действительную ячейку памяти.   -  person    schedule 03.06.2013
comment
позвольте нам продолжить обсуждение в чате   -  person mf_    schedule 03.06.2013
comment
Специфическая для окна, но та же тема: stackoverflow.com/questions/993324/   -  person Mike    schedule 03.06.2013
comment
Если *a равно NULL, этот код использует b без его инициализации. Это представитель вашего настоящего кода? Если это так, ваш реальный код не работает; b всегда следует инициализировать перед его использованием в memcpy, иначе memcpy не следует выполнять. Если нет, значит, вы не показали нам код представителя.   -  person Eric Postpischil    schedule 03.06.2013


Ответы (2)


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

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

Would not checking **a cause a crash as well in this case?

Правильно, все, что вы здесь делаете, это присваивает переданное значение локальному, а затем пытается получить к нему доступ. Если local плохой, это потому, что переданное значение плохое. Мусор на входе, мусор на выходе.


Чтобы обратиться к предоставленному вами коду:

   if (*a) {
       b = *a;
   }
   memcpy(&c, b, sizeof(int));//you really shouldn't be executing this at all unless
                              // you're setting b, so it should be within the if check 
                              // and only executed after b=*a
person Mike    schedule 03.06.2013
comment
Проголосовали за игнорирование слона в комнате: код в вопросе использует b без его инициализации. Это могло быть причиной первоначальной проблемы. - person Eric Postpischil; 04.06.2013
comment
@Eric - несколько моментов: 1) поскольку OP заявил, что это не настоящий код, это больше похоже на слона в коридоре, мы не знаем, есть ли в реальном коде те же проблемы. 2) даже если код был в пределах проверки для параметра b, нет гарантии, что это не вызовет проблемы. Как вы сказали, если *a равно NULL b не будет установлен, но если a* является мусором, тогда будет установлено b, и мы все равно, скорее всего, выйдем из строя в memcpy 3) пунктах 1 и 2, вы правы, что код мог бы быть чище, поэтому я обратился к этому. - person Mike; 04.06.2013

Если кто-то передает вам указатель мусора в * a, нет способа проверить (в любом случае, независимо от платформы), доступен ли он.

Но если кто-то передает == NULL или * a == NULL, вы можете хотя бы проверить это (Эрик упомянул это сначала в своем комментарии к другому ответу):

void func_foo(int **a) 
{
   int *b= NULL, c;

   if (a!=NULL) {
       b = *a;
   }

   if (b!=NULL) {
       printf("about to access memory at address 0x%p\n", b);
       memcpy(&c, b, sizeof(int));//this crashes because address "b" is not accessible.
       // btw same as c= *b  or  c= **a; 
   }
   else {
       printf("someone passed us a null pointer either in a or *a\n");
   }
}

Ради удовольствия, упрощенная версия будет выглядеть так:

void func_foo(int **a) 
{
   int c;

   if (a!=NULL && *a!=NULL) {
       c = **a;
   }
   else {
       printf("someone passed us a null pointer either in a or *a\n");
   }
}
person Nicholaz    schedule 03.06.2013