¿Es ((void *) -1) una dirección válida?

6 minutos de lectura

avatar de usuario
alca

Verbatim de linux’ man shmat:

VALOR DEVUELTO

[…] en caso de error (void *) -1 se devuelve, y error se establece para indicar la causa del error.

(POSIX dice lo mismo usando un redacción ligeramente diferente.)

¿Existe alguna regla obligatoria o definición (¿estándar?) que (void *) -1 puede que no sea una dirección válida?

0xffffffff es técnicamente una dirección válida en un entorno de 32 bits, pero en la mayoría de los sistemas operativos (ciertamente Linux/Windows) estará en la parte reservada del núcleo del espacio de direcciones. Eso significa que en los procesos de modo de usuario es seguro usarlo como un código de error ya que ninguna función de asignación de modo de usuario devolvería esto como una dirección utilizable.

  • Además, prácticamente todos los administradores de memoria asignan punteros en algunas direcciones alineadas, (void *)-1 no observa ninguna posible alineación.

    – Dmitro Sirenko

    9 de noviembre de 2012 a las 11:17

  • @EarlGray bueno, eso es cierto, pero aún es posible que un programa acceda a algún desplazamiento desde la dirección alineada, por lo que si esto estuviera en un rango válido, sería un problema.

    – Benj

    9 de noviembre de 2012 a las 11:19

avatar de usuario
Un tipo programador

Para simplificar, considere una máquina con 16 bits de espacio de direcciones. Esta máquina puede direccionar la memoria de 0 a 65535. En este caso (void*) -1 sería lo mismo que 0xffff, que es 65535. Si bien técnicamente esta dirección es válida, hay pocos sistemas que tendrían algo allí a lo que permitirían acceder.

La otra cosa a considerar es que casi todas las llamadas al sistema POSIX devuelven -1 en error


Como señaló Benj, en realidad es posible mapear la dirección NULL. Esto se puede usar, por ejemplo, cuando desea ver si hay una asignación con un determinado shmiden cuyo caso el shmaddr el argumento se establece en NULL y la funcion regresa NULL para indicar que la memoria compartida existe.

  • La pregunta es: ¿por qué no NULL? Casi todas las llamadas al sistema POSIX devuelven NULL si el puntero devuelto no es válido.

    – Dmitro Sirenko

    9 de noviembre de 2012 a las 11:27

  • @EarlGray dependiendo de la distribución de Linux, en realidad es posible mapear NULL con mmap. También es posible hacerlo con VirtualAlloc en Windows (hay que pasar un 1 como dirección deseada y dejar que se redondee hacia abajo). Entonces, NULL puede ser una dirección válida, mientras que 0xffffffff no.

    – Benj

    9 de noviembre de 2012 a las 11:42


  • @EarlGray Es posible, como señaló Benj, y actualicé mi respuesta con una situación en la que volverá NULL.

    – Un tipo programador

    9 de noviembre de 2012 a las 11:48

  • Hay innumerables sistemas que tienen datos válidos y accesibles en la dirección 0xFFFF, la mayoría de los sistemas de microcontroladores colocan su vector de reinicio en esa misma dirección. Esos sistemas a menudo carecerán de mapeo de memoria virtual, por lo que si intenta leer esa dirección, no obtendrá un error, pero obtendrá valores basura. Sin embargo, la mayoría de las veces, el vector de reinicio se programa en flash, por lo que no podrá escribir nada en esa dirección, no sucedería nada si lo hiciera.

    – Lundin

    9 de noviembre de 2012 a las 12:53


  • @Lundin La documentación que OP ha publicado es específica del sistema operativo, la pregunta es por qué shmat comportarse de esta manera en el sistema operativo para el que se escribieron los documentos. no importa eso 0xFFFF podría ser válido en otros sistemas.

    – Benj

    9 de noviembre de 2012 a las 13:50

Para responder a la pregunta directamente, no, no existe una regla, definición, norma o especificación obligatoria que diga (void *) -1 puede que no sea una dirección válida.

(Por supuesto, no hay reglas, definiciones, estándares o especificaciones sobre direcciones de memoria obligatorias. Veo gente caminando por la calle todos los días sin cumplir con el estándar C, por ejemplo, pero nunca he visto a nadie arrestado por eso. Pero, incluso si omitimos la parte obligatoria, usando (void *) -1 como dirección generalmente no está prohibido por las especificaciones comunes).

Sin embargo, no es necesario para (void *) -1 no ser una dirección válida para que shmat funcione. Solo es necesario que un exitoso llamar a shmat nunca regresa (void *) -1 y eso (void *) -1 ser compatible con el compilador con el fin de probar el valor de retorno de shmat. Si se cumplen estas dos condiciones, un programa siempre puede distinguir una llamada shmat exitosa de una llamada shmat fallida.

En cuanto a la segunda condición, la norma C no garantiza que (void *) -1 se puede usar, por lo que POSIX, al especificar que se trata de un retorno de error de shmat, requiere implícitamente la implementación de C (u otro lenguaje) para admitirlo. Entonces, esta es una extensión del lenguaje requerido por POSIX, y generalmente es algo simple de admitir para los compiladores.

Con respecto a la primera condición, considere cuándo podríamos querer que shmat regrese (void *) -1 para una llamada exitosa. shmat se puede llamar con una dirección solicitada por el usuario o sin ella, en cuyo caso la implementación elige una dirección. En cualquier arquitectura de computadora normal, hay múltiples razones para usar direcciones que son múltiplos de varios valores. Para shmat, el más obvio es el mapeo de memoria. En arquitecturas con memoria virtual, la memoria se asigna en unidades de páginas y shmat, cuando asigna memoria para el segmento, se asigna al inicio de una página. Cualquier tamaño de página par no tiene múltiplos que sean (void *) -1ya que este último es impar, por lo que shmat nunca elige asignar un segmento a (void *) -1. Incluso si shmat no usara el tamaño de página, normalmente usaría alguna otra alineación, como 4, 8 o 16 bytes, porque proporcionar memoria alineada significa que las estructuras almacenadas al comienzo de esa memoria se alinearán, lo que da como resultado una memoria más rápida. acceso en muchos procesadores.

Eso deja el caso donde el usuario solicita (void *) -1 como dirección. Esto sería inusual y podría funcionar solo si el segmento de memoria fuera un solo byte o si el modelo de memoria permitiera ajustarse (o si el compilador presentara un modelo de memoria muy extraño en el que (void *) -1 no eran el último byte en el espacio de direcciones). No puedo decir con certeza si algún sistema POSIX admite esto o no. Sin embargo, está claro que esto es esencialmente inútil, y nadie tiene otra razón para hacerlo que no sea la curiosidad. Por lo tanto, es seguro y razonable descartar este caso de shmat, simplemente diciendo que no se admite, no lo haga.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad