Dlaczego otrzymuję błąd segmentacji w moim prostym programie c ++ używającym libexpect.so?

Jestem zajęty projektem, w którym muszę zautomatyzować niektóre procesy w bash lub ssh, więc zdecydowałem się użyć biblioteki libexpect.so. Jeśli nie wiesz, czym jest libexpect, zapewnia ono oczekiwane rozszerzenie, którego mogę używać w programie c ++, i oczekuję, że jest to program, w którym możesz uruchamiać zautomatyzowane skrypty dla rzeczy takich jak ssh. Mogę więc wykonać skrypt, który próbuje gdzieś ssh ... gdy zapytanie o hasło zostanie znalezione przez oczekiwanie, że mogłem już podać oczekiwane hasło do wysłania.

Moim problemem jest to, że kiedy uruchamiam program, nawet bardzo prosty, otrzymuję błąd segmentacji, który zawęziłem, używając gdb, do funkcji w libexpect.so nazywanej exp_spawnv.

Wiem, że dobrze połączyłem bibliotekę, kompiluje się dobrze i cały problem nie istnieje, gdy kompiluję się i uruchamiam w ubuntu, ale w moim arch Linux instalacyjnym otrzymuję błąd segmentacji, który omówię później. Powodem, dla którego buduję go na łuku, jest to, że w końcu chcę zbudować projekt na większości dystrybucji.

Moje myśli są takie, że w mojej instalacji łuku są uprawnienia, które zawodzą, gdy wywoływana jest funkcja exp_spawnv, być może potok, widelec lub cokolwiek innego.

Aby udowodnić, że nie robię czegoś funky, oto prosty main.cpp dla celów ilustracyjnych.

#include <tcl8.5/expect.h>

int main()
{
  FILE* file = exp_popen("bash");
}

Tak więc jest to najbardziej prosty program, jakiego można się spodziewać. Tutaj kompiluję i łączę.

$ g ++ -ggdb -c main.cpp

main.cpp: W funkcji „int main ()”:

main.cpp: 5: 32: warning: nieaktualna konwersja ze stałej łańcucha na „char *” [-Wwrite-strings]

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

Dostałem więc mój główny mainprog ... właśnie działający, który da mi błąd segmentacji i nic więcej.

Jeśli uruchomię mainprog w gdb, powie mi, że w exp_spawnv jest błąd seg. Oto, co zrobiłem w gdb z powrotem na końcu.

(gdb) uruchom

Program startowy: / home / user / testlibexpect / mainprog

Ostrzeżenie: Nie można załadować symboli biblioteki współdzielonej dla linux-vdso.so.1.

Czy potrzebujesz „ustawić solib-search-path” lub „set sysroot”?

Sygnał odebranego programu SIGSEGV, Błąd segmentacji.

0x00007ffff7bc8836 w exp_spawnv () z /usr/lib/libexpect.so

(gdb) backtrace

0 0x00007ffff7bc8836 w exp_spawnv () z /usr/lib/libexpect.so

1 0x00007ffff7bc8cb4 w exp_spawnl () z /usr/lib/libexpect.so

2 0x00007ffff7bc8d01 w exp_popen () z /usr/lib/libexpect.so

3 0x000000000040069e w main () at main.cpp: 5

Dwie rzeczy mnie niepokoją.

patrząc na stronę podręcznika libexpect, znam exp_spawnv forks nowy proces i będę mógł komunikować się przez PLIK *. Sądzę więc, że sygnał SIGSEGV jest odbierany, ponieważ coś złego stało się z widelcem?

Ta linia (ostrzeżenie: nie można załadować symboli biblioteki współdzielonej dla linux-vdso.so.1.) W śledzeniu wygląda podejrzanie?

Podsumowując, moje pytanie brzmi: co powinienem sprawdzić, aby rozwiązać ten problem? Próbowałem zbudować bibliotekę oczekiwań ze źródła i nabywając ją za pomocą programu pacman menedżera pakietów arch ... problem nadal występuje, więc nie sądzę, aby kompilacja biblioteki była uszkodzona, jeśli wiesz o co mi chodzi.

EDIT: punkt 2 moich obaw nie jest problemem według badań, które przeprowadziłem, tylko kosmetycznych.

Demontaż z zaćmienia jest poniżej:

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

ODPOWIEDŹ PRZYWOŁAŁEM SIĘ

Oto rozwiązanie, które w końcu wymyśliłem, zaakceptowałem odpowiedź szx, ponieważ prowadzi mnie w dół ścieżką, która była banalna, gdy tylko wiedziałem, czego szukam.

//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;
}

Wszystko, co zrobiłem tutaj, pokazuje, jak zainicjować oczekiwanie / tcl, aby zapobiec problemowi, o którym mówił szx. Wtedy właśnie zrobiłem typowy problem typu „oczekuj jak”, gdzie prawie powiedziałem, czy powłoka monituje o podanie danych wysyłanych przez pwd. Wtedy, jeśli daje ci to oczekiwany katalog bieżący, działa. Taka struktura może być bardzo przydatna w przypadku czegoś takiego jak ssh. Powiedz, czy chcesz gdzieś zautomatyzować ssanie, zrobić coś, a potem wyjść. Zwłaszcza, jeśli chcesz to zrobić kilkaset razy i nie chcesz potwierdzać autentyczności każdego hosta i wpisywać hasła za każdym razem.

Zauważ, że nigdy nie musiałem tego robićubuntu z jakiegoś powodu ... prawdopodobnie dlatego, że nie zbudowałem go ze źródła i po prostu użyłemapt-get. Jednak mój projekt wymaga ode mnie zbudowania ze źródła, więc znalazłem naprawdę dobry, zgrabny sposób na tohttp://www.linuxfromscratch.org/lfs/view/development/chapter05/tcl.html ihttp://www.linuxfromscratch.org/lfs/view/development/chapter05/expect.html... w rzeczywistości cała strona wygląda naprawdę użytecznie.

Jeszcze raz dziękuję za szx

questionAnswers(2)

yourAnswerToTheQuestion