segmentation raspberry que dumped c++ segmentation-fault expect

raspberry - ¿Por qué obtengo un error de segmentación en mi programa simple de c++ usando libexpect.so?



segmentation fault raspberry pi (2)

Estaría más preocupado por la advertencia al compilar. Aparentemente, la interfaz requiere que pase una cadena escribible, pero pasa una cadena constante. Si efectivamente le escribe, dará como resultado un error de segmentación. Por lo tanto, parece un buen candidato para su problema.

¿Qué sucede si en su lugar intentas crear un búfer grabable y pasar eso?

char name[] = "bash"; FILE* file = exp_popen(name);

Actualización: He probado su programa (con el cambio anterior y una "devolución 0" al final), y funciona bien para mí. Tal vez hay algo mal con su sistema, como una biblioteca a medio instalar? Puede verificar si también falla cuando se vincula con -static. Si lo hace, está seguro de que la biblioteca enlazada en tiempo de compilación es la misma que la biblioteca utilizada en tiempo de ejecución (porque se incluirá en el ejecutable en tiempo de compilación).

Estoy ocupado con un proyecto en el que tengo que automatizar algunos procesos en bash o ssh, así que decidí usar la biblioteca libexpect.so. Si no sabe qué es libexpect, proporciona una extensión de espera que puedo usar en un programa de c ++, y espero que sea solo un programa donde pueda ejecutar scripts automatizados para cosas como ssh. Así que puedo ejecutar un script que intente ssh en algún lugar ... cuando se encuentre la solicitud de contraseña esperando que ya podría haber esperado una contraseña para enviar.

Mi problema es que cuando ejecuto un programa, incluso uno realmente simple, obtengo un error de segmentación que reduje, con gdb, a una función en libexpect.so llamada exp_spawnv.

Sé que he vinculado la biblioteca correctamente, compila bien y, de hecho, el problema no existe cuando compilo y ejecuto en ubuntu, pero en mi instalación de arch Linux, recibo el error de segmentación que detallaré más adelante. La razón por la que lo estoy creando en el arco es porque quiero que el proyecto se pueda construir en la mayoría de las distribuciones.

Mi opinión es que en mi instalación de arco hay permisos que fallan cuando se llama a la función exp_spawnv, quizás una tubería, un tenedor o lo que sea.

Para demostrar que no estoy haciendo algo funky, aquí hay un main.cpp simple con fines ilustrativos.

#include <tcl8.5/expect.h> int main() { FILE* file = exp_popen("bash"); }

Por lo tanto, se trata del programa de espera más simple que se haya realizado. Aquí estoy yo compilando y vinculándolo.

$ g ++ -ggdb -c main.cpp

main.cpp: en la función ''int main ()'':

main.cpp: 5: 32: advertencia: conversión obsoleta de la constante de cadena a ''char *'' [-Wwrite-strings]

$ g ++ main.o -lexpect -o mainprog

Así que obtuve mi mainprog ejecutable ... solo ejecutando eso que me dará una falla de segmentación y nada más.

Si ejecuto mainprog en gdb, me dice que hay una falla seg en exp_spawnv. Esto es lo que hice en gdb con la traza inversa al final.

(gdb) ejecutar

Programa de inicio: / home / user / testlibexpect / mainprog

advertencia: no se pudieron cargar los símbolos de la biblioteca compartida para linux-vdso.so.1.

¿Necesita "establecer solib-search-path" o "set sysroot"?

Programa recibido señal SIGSEGV, falla de segmentación.

0x00007ffff7bc8836 en exp_spawnv () desde /usr/lib/libexpect.so

(gdb) backtrace

0 0x00007ffff7bc8836 en exp_spawnv () desde /usr/lib/libexpect.so

1 0x00007ffff7bc8cb4 en exp_spawnl () de /usr/lib/libexpect.so

2 0x00007ffff7bc8d01 en exp_popen () de /usr/lib/libexpect.so

3 0x000000000040069e en main () en main.cpp: 5

Dos cosas me preocupan

  1. Al mirar la página de manual de libexpect, sé que exp_spawnv abre un nuevo proceso y podré comunicarme a través del ARCHIVO *. ¿Entonces supongo que se recibe la señal SIGSEGV porque algo malo ha sucedido con el tenedor?

  2. Esa línea (advertencia: ¿No se pueden cargar los símbolos de la biblioteca compartida para linux-vdso.so.1.) En el backtrace parece sospechosa?

Entonces, en resumen, mi pregunta es: ¿qué debo buscar para solucionar este problema? He intentado construir la biblioteca de esperar de la fuente y al adquirirla con el gestor de paquetes de arch pacman ... el problema persiste, así que no creo que la compilación de la biblioteca esté dañada si sabes a qué me refiero.

EDITAR: el punto 2 de mis preocupaciones no es un problema de acuerdo con la investigación que he hecho, solo cosmético.

El desmontaje del eclipse está a continuación:

00007ffff7bc87c6: mov 0x20c68b(%rip),%rax # 0x7ffff7dd4e58 00007ffff7bc87cd: mov (%rax),%rax 00007ffff7bc87d0: test %rax,%rax 00007ffff7bc87d3: je 0x7ffff7bc87d7 <exp_spawnv+935> 00007ffff7bc87d5: callq *%rax 00007ffff7bc87d7: mov %r12,%rsi 00007ffff7bc87da: mov %rbp,%rdi 00007ffff7bc87dd: callq 0x7ffff7bb2330 <execvp@plt> 00007ffff7bc87e2: callq 0x7ffff7bb1720 <__errno_location@plt> 00007ffff7bc87e7: mov 0x24(%rsp),%edi 00007ffff7bc87eb: mov %rax,%rsi 00007ffff7bc87ee: mov $0x4,%edx 00007ffff7bc87f3: xor %eax,%eax 00007ffff7bc87f5: callq 0x7ffff7bb1910 <write@plt> 00007ffff7bc87fa: mov $0xffffffff,%edi 00007ffff7bc87ff: callq 0x7ffff7bb23d0 <exit@plt> 00007ffff7bc8804: nopl 0x0(%rax) 00007ffff7bc8808: xor %eax,%eax 00007ffff7bc880a: movl $0x0,0x20dd3c(%rip) # 0x7ffff7dd6550 00007ffff7bc8814: callq 0x7ffff7bb1700 <exp_init_pty@plt> 00007ffff7bc8819: xor %eax,%eax 00007ffff7bc881b: callq 0x7ffff7bb2460 <exp_init_tty@plt> 00007ffff7bc8820: lea -0x1c97(%rip),%rdi # 0x7ffff7bc6b90 00007ffff7bc8827: callq 0x7ffff7bb2540 <expDiagLogPtrSet@plt> 00007ffff7bc882c: mov 0x20c555(%rip),%rax # 0x7ffff7dd4d88 00007ffff7bc8833: mov (%rax),%rax 00007ffff7bc8836: mov 0x410(%rax),%rdi

LA RESPUESTA LLEGÓ CON

Esta es la solución que finalmente se me ocurrió, acepté la respuesta de szx porque me llevó por este camino que era trivial una vez que supe lo que estaba buscando.

//do not use TCL stubs as this is a main #undef USE_TCL_STUBS #include <iostream> using std::cout; using std::endl; //headers that must be included when using expectTcl as an extension to c++ program #include <stdio.h> #include <stdlib.h> #include <expectTcl/tcl.h> #include <expectTcl/expect_tcl.h> #include <expectTcl/expect.h> //enums representing cases of what expect found in loop enum{FOUNDSEARCH, PROMPT}; int main() { /* initialise expect and tcl */ Tcl_Interp *interp = Tcl_CreateInterp(); if(Tcl_Init(interp) == TCL_ERROR) { cout << "TCL failed to initialize." << endl; } if(Expect_Init(interp) == TCL_ERROR) { cout << "Expect failed to initialize." << endl; } /* end of intialisation procedure */ //open a shell with a pipe char shellType[] = "sh"; FILE* fp = exp_popen(shellType); //should we exit from the loop which is studying sh output bool shouldBreak = false; //did we find the pwd bool foundSearch = false; //does it look like expect is working bool expectWorking = false; //did we receive a prompt...therefore we should send a command bool receivedPrompt = false; while(shouldBreak == false) { switch(exp_fexpectl(fp, exp_glob, "/tools/test*", FOUNDSEARCH, //different exp_glob,"# ", PROMPT, //cases are shown here exp_end)) //that the expect loop could encounter { case FOUNDSEARCH: foundSearch = true; break; case PROMPT: if (receivedPrompt) { shouldBreak = true; expectWorking = true; } else { receivedPrompt = true; fprintf(fp, "%s/r", "pwd"); } break; case EXP_TIMEOUT: shouldBreak = true; break; case EXP_EOF: shouldBreak = true; break; } //cout << "exp_match : " << exp_match << endl; } cout << endl; if (foundSearch) { cout << "Expect found output of pwd" << endl; } else { cout << "Expect failed to find output of pwd" << endl; } if(expectWorking) { cout << "The expect interface is working" << endl; } else { cout << "The expect interface is not working" << endl; } cout << "The test program successfully reached the end" << endl; }

Todo lo que he hecho aquí muestra cómo inicializar expect / tcl para evitar el problema del que szx estaba hablando. Entonces acabo de hacer un típico problema de esperar como que prácticamente dije que si el intérprete de comandos le pide entrada, envíela pwd. Entonces, si le da el directorio actual, lo esperado está funcionando. Este tipo de estructura puede ser extremadamente útil para algo como ssh. Di si quieres automatizar sshing en alguna parte, hacer algo y luego salir de allí. Especialmente si quiere hacerlo un par de cientos de veces y no quiere confirmar la autenticidad de cada host y escribir una contraseña en todo momento.

Tenga en cuenta que nunca tuve que hacer esto en ubuntu por alguna razón ... posiblemente porque no lo construí desde la fuente y solo usé apt-get . Sin embargo, mi proyecto requiere que construya desde la fuente, así que encontré una forma realmente buena y ordenada de hacerlo en http://www.linuxfromscratch.org/lfs/view/development/chapter05/tcl.html y http: // www. .linuxfromscratch.org / lfs / view / development / chapter05 / expect.html ... de hecho, todo el sitio web parece realmente útil.

Gracias de nuevo a szx


La variable global TclStubs *tclStubsPtr definida dentro de Tcl pasa a ser NULL cuando exp_spawnv intenta acceder a Tcl_ErrnoMsg que se define como un miembro de esa estructura (ver tcl.h ):

#ifndef Tcl_ErrnoMsg #define Tcl_ErrnoMsg / (tclStubsPtr->tcl_ErrnoMsg) /* 128 */ #endif

No estoy familiarizado ni con el esperado ni con el Tcl, pero lo anterior sugiere que probablemente deba llamar a alguna subrutina de inicialización (si existe) o configurarla manualmente.