Pregunta Probando punteros para la validez (C / C ++)


¿Hay alguna manera de determinar (programáticamente, por supuesto) si un puntero dado es "válido"? Buscar NULL es fácil, pero ¿qué pasa con cosas como 0x00001234? Al intentar desreferenciar este tipo de puntero, se produce una excepción / bloqueo.

Se prefiere un método multiplataforma, pero específico de la plataforma (para Windows y Linux) también está bien.

Actualización para aclaración: El problema no es con los punteros rancios / liberados / no inicializados; en su lugar, estoy implementando una API que toma punteros de la persona que llama (como un puntero a una cadena, un identificador de archivo, etc.). El llamante puede enviar (a propósito o por error) un valor no válido como puntero. ¿Cómo evito un bloqueo?


75
2018-02-15 15:45


origen


Respuestas:


Actualización para aclaración: El problema no es con punteros rancios, liberados o no inicializados; en su lugar, estoy implementando una API que toma punteros de la persona que llama (como un puntero a una cadena, un identificador de archivo, etc.). El llamante puede enviar (a propósito o por error) un valor no válido como puntero. ¿Cómo evito un bloqueo?

No puedes hacer ese control. Simplemente no hay manera de que pueda verificar si un puntero es "válido". Debes confiar en que cuando las personas usan una función que toma un puntero, esas personas saben lo que están haciendo. Si le pasan 0x4211 como un valor de puntero, entonces tiene que confiar en que apunta a la dirección 0x4211. Y si golpean "accidentalmente" un objeto, incluso si usas alguna función de sistema de operación aterradora (IsValidPtr o lo que sea), seguirías cayendo en un error y no fallarías rápidamente.

Comience a usar punteros nulos para señalar este tipo de cosas y dígale al usuario de su biblioteca que no deberían usar punteros si tienden a pasar accidentalmente punteros no válidos, en serio :)


68
2018-02-15 16:11



La prevención de un bloqueo causado por el llamador que envía un puntero no válido es una buena forma de crear errores silenciosos que son difíciles de encontrar.

¿No es mejor para el programador que usa su API obtener un mensaje claro de que su código es falso al colgarlo en lugar de ocultarlo?


30
2018-02-15 16:05



En Win32 / 64 hay una manera de hacer esto. Intente leer el puntero y capte la excepción SEH resultante que se lanzará en caso de error. Si no arroja, entonces es un puntero válido.

El problema con este método es que simplemente devuelve si puede o no leer datos del puntero. No ofrece ninguna garantía sobre la seguridad del tipo o cualquier cantidad de otros invariantes. En general, este método es bueno para poco más que para decir "sí, puedo leer ese lugar en particular en la memoria en un momento que ya pasó".

En resumen, no hagas esto;)

Raymond Chen tiene una publicación en el blog sobre este tema: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx


26
2018-02-15 15:55



Aquí hay tres maneras sencillas para que un programa C bajo Linux se introspecte sobre el estado de la memoria en la que se está ejecutando, y por qué la pregunta tiene respuestas sofisticadas apropiadas en algunos contextos.

  1. Después de llamar a getpagesize () y de redondear el puntero a una página límite, puede llamar a mincore () para averiguar si una página es válida y si resulta ser parte del conjunto de trabajo del proceso. Tenga en cuenta que esto requiere algunos recursos del núcleo, por lo que debe compararlo y determinar si llamar a esta función es realmente apropiado en tu api. Si tu api va a manejar interrupciones, o leer desde puertos serie en la memoria, es apropiado llamar esto para evitar impredecibles comportamientos
  2. Después de llamar a stat () para determinar si hay un directorio / proc / self disponible, puede abrir y leer a través de / proc / self / maps para encontrar información sobre la región en la que reside un puntero. Estudie la página man para proc, el pseudo archivo de información de proceso sistema. Obviamente, esto es relativamente caro, pero es posible que capaz de salirse con la caché el resultado del análisis en una matriz puede buscar eficientemente usando una búsqueda binaria. Considera también el / proc / self / smaps. Si su API es para computación de alto rendimiento, entonces el programa querrá saber sobre / proc / self / numa que es documentado en la página man para numa, la memoria no uniforme arquitectura.
  3. La llamada get_mempolicy (MPOL_F_ADDR) es apropiada para el trabajo de API de alto rendimiento donde hay múltiples hilos de ejecución y usted está gestionando su trabajo para tener afinidad por la memoria no uniforme en lo que se refiere a los núcleos de la CPU y los recursos de socket. Tal api por supuesto, también le dirá si un puntero es válido.

En Microsoft Windows está la función QueryWorkingSetEx que está documentada en la API de estado del proceso (también en la API NUMA). Como corolario de la sofisticada programación de la API de NUMA, esta función también le permitirá realizar trabajos simples de "prueba de punteros para la validez (C / C ++)", por lo que es poco probable que quede obsoleta durante al menos 15 años.


23
2018-05-12 17:22



AFAIK no hay forma. Intente evitar esta situación estableciendo siempre los punteros en NULL después de liberar la memoria.


15
2018-02-15 15:48



Eche un vistazo a esta y esta pregunta. También eche un vistazo a punteros inteligentes.


7
2018-02-15 15:51



En cuanto a la respuesta un poco en este hilo:

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () para Windows.

Mi consejo es mantenerse alejado de ellos, alguien ya ha publicado este: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Otra publicación sobre el mismo tema y del mismo autor (creo) es esta: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ("IsBadXxxPtr realmente debería llamarse CrashProgramRandomly").

Si los usuarios de su API envían datos incorrectos, déjelos colapsar. Si el problema es que los datos pasados ​​no se usan hasta más tarde (y eso hace que sea más difícil encontrar la causa), agregue un modo de depuración donde las cadenas, etc. se registran en la entrada. Si son malos, será obvio (y probablemente se bloquee). Si está sucediendo a menudo, podría valer la pena sacar su API del proceso y dejar que bloquee el proceso de API en lugar del proceso principal.


7
2018-02-15 18:37