2010-03-22 22 views
7

Estoy intentando rastrear un bloqueo muy extraño. Lo que es tan extraño al respecto es una solución que alguien descubrió y que no puedo explicar.cómo puede un ejecutivo cambiar el comportamiento del programa ejecutado

La solución es este pequeño programa que me referiré como 'corredor':

#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 
#include <errno.h> 

int main(int argc, char *argv[]) 
{ 
    if (argc == 1) 
    { 
     fprintf(stderr, "Usage: %s prog [args ...]\n", argv[0]); 
     return 1; 
    } 

    execvp(argv[1], argv + 1); 

    fprintf(stderr, "execv failed: %s\n", strerror(errno)); 

    // If exec returns because the program is not found or we 
    // don't have the appropriate permission 
    return 255; 
} 

Como se puede ver, todo esto hace es utilizar el programa para reemplazar execvp sí con un programa diferente.

El programa se bloquea cuando se invoca directamente desde la línea de comandos:

/path/to/prog args # this crashes 

pero funciona bien cuando se invoca indirectamente a través de mi corredor de cuña:

/path/to/runner /path/to/prog args # works successfully 

Para la vida de mí, Puedo descubrir cómo tener un ejecutivo adicional puede cambiar el comportamiento del programa que se está ejecutando (como puede ver, el programa no cambia el entorno).

Algunos antecedentes sobre el accidente. El bloqueo en sí está sucediendo en el tiempo de ejecución de C++. En concreto, cuando el programa hace un throw, la versión estrellarse cree incorrectamente que no hay capturas juego (aunque hay) y llama terminate. Cuando invoco el programa a través de runner, la excepción se captura correctamente.

Mi pregunta es alguna idea de por qué el exec adicional cambia el comportamiento del programa ejecutado?

+0

No sé: Pero ¿Cambia la execvp el directorio de trabajo? ¿Qué argumentos estás pasando? –

+0

@MartinYork - AFAIK, 'execvp' nunca cambia el directorio de trabajo (que requiere una llamada a' chdir' y el corredor no hace eso). Los argumentos específicos son irrelevantes; el comportamiento descrito es independiente de los argumentos específicos pasados ​​al programa. –

+1

¿Hace lo mismo si usa 'execv()' en lugar de 'execvp()'? – caf

Respuesta

3

Es posible que los archivos .so cargados por el corredor estén haciendo que el runee funcione correctamente. Intente leer cada uno de los binarios y ver si hay bibliotecas cargando diferentes versiones/ubicaciones.

+1

El problema es si 'ld-linux.so.2' asigna un objeto compartido específico al espacio de direcciones antes del binario principal o después (el error real está en otra parte pero debido a circunstancias, el error solo se manifiesta cuando el SO está mapeado una dirección más baja que el binario principal). –

0

Como un tiro en la oscuridad: el doble ejecutivo puede cambiar el orden de las variables de entorno en la memoria RAM.

Medio Ambiente es una estructura de memoria con los punteros; el kernel copia esa estructura en el espacio de direcciones del nuevo proceso. El orden real de los elementos en la RAM puede cambiar durante esa copia (las variables de entorno no se ordenan semánticamente, pero las direcciones en la RAM tienen un orden). Con dos exec(), el orden puede modificarse dos veces.

Que un cambio en el orden de las cadenas en RAM desentierra un error es algo extraño, pero cosas más extrañas han sucedido.

+0

Gracias por la sugerencia pero eso no parece ser así. Dejé el bloque de entorno sin procesar y tienen el mismo orden en ambos. –

0

Me pregunto si está pasando algo diferente en argv [0] a lo que es el shell. Obviamente no puedo ver lo que estás escribiendo, pero es posible que estés configurando argv [0] en el primer argumento real del programa, mientras que el intérprete lo establece en su nombre (por ejemplo, ruta completa o corta))

+0

@MarkR: gracias por su sugerencia. Modifiqué el corredor para que 'argv [0]' no incluyera la ruta. Lamentablemente, sigo viendo el mismo comportamiento. –

1

Tal vez el programa llamado tiene una pérdida de memoria. Intente ejecutarlo con valgrind o alguna otra herramienta de comprobación de memoria. Después de tener un error de memoria, todo lo demás es un comportamiento indefinido (y entonces todo puede suceder).

+0

Aparte de lo normal aún alcanzable en los bloques de salida, Valgrind no detecta ningún error en la versión que finaliza (o la versión que no termina para el caso). –

0

Supongo que hay dos cosas que se pueden comparar entre las versiones "operativa" y "fallar": descripciones de archivos abiertos y manejadores de señales, ya que se las puede pasar el ejecutivo.

No puedo ver cómo son el problema/ser diferente, pero podría valer la pena eliminarlos.

Cuestiones relacionadas