2011-02-05 3 views
0

Mac OSX 10.6.6과 Xcode 3.2.4에서 몇 가지 코드를 실행 중입니다. 상당히 표준적인 코드가 있습니다. : pid == 0, execvp, args (args에 명령이 포함되어있는 경우) 배열의 첫 번째 요소로, 배열은 null로 끝납니다.EXC_SOFTWARE 및 기괴한 cin.getline 루프가 발생하는 execvp()?

내 운영 체제 클래스에서이 문제를 해결할 것이며 간단한 쉘을 작성하는 과제가 있습니다. args 및 스위치와 함께 명령을 실행하면 리디렉션 (< 및>)과 파이프 (|)가 모두 리디렉션됩니다. 몇 가지 문제가 있습니다.

1) 때로는 디버깅하는 동안 EXC_SOFTWARE 신호가 나타납니다 (지금까지는 Xcode 외부에서 앱을 실행하면 얻지 못했지만 Mac을 처음 사용하고 내가 한)

2) 가끔 다음 명령에 대한 getline이 다른 couts에 의해 인쇄 된 것처럼 보이는 쓰레기를 얻습니다. 이것은 영원히 루핑되기 시작합니다. 필자는 모든 프롬프트에서 getpid()를 테스트하고 시작 프로세스 만이이를 인쇄하고 우연한 "포크 폭탄"이없는 것으로 보입니다.

는 여기에 지금까지이 작업은 다음과 같습니다

#include <iostream> 
#include <string> 
#include <unistd.h> 

using namespace std; 

char** Split(char* buffer, int &count) { 
    count = 1; 
    for (int i = 0; i < strlen(buffer); i++) { 
     if (buffer[i] == ' ') { 
      count++; 
     } 
    } 
    const char* delim = " "; 
    char* t = strtok(buffer, delim); 
    char** args = new char*[count + 1]; 
    for (int i = 0; i < count; i++) { 
     args[i] = t; 
     t = strtok(NULL, delim); 
    } 
    args[count] = 0; 
    return args; 
} 

void Run(char** argv, int argc) { 
    int pid = 0; 
    if ((pid = fork()) == 0) { 
     //for testing purposes, print all of argv 
     for (int i = 0; i < argc; i++) { 
      cout << "{" << argv[i] << "}" << endl; 
     } 
     execvp(argv[0], argv); 
     cout << "ERROR 1" << endl; 
     exit(1); 
    } else if (pid < 0) { 
     cout << "ERROR 2" << endl; 
     exit(2); 
    } 
    wait(NULL); 
} 

int main(int argc, char * const argv[]) { 
    char buffer[512]; 
    char prompt[] = ":> "; 
    int count = 0; 
    while (true) { 
     cout << prompt; 
     cin.getline(buffer, 512); 
     char **split = Split(buffer, count); 
     Run(split, count); 
    } 
} 

정확히 내가 무엇을, 당신이, 붙여 넣기를 절단하고 구축 할 수있을 것입니다.

나는 C++에서 최고가 아니며, split을 삭제하지 않을 때 메모리 누수가 발생할 수 있습니다. 그러나 주된 관심사는 EXC_SOFTWARE 신호이며 루핑 문제가 무엇인지 잘보아야합니다. 이견있는 사람?

편집 :

할당은 매우 제한적인 오류 검사를 필요로하고 내가 모든 입력이 올바른지 있으리라 믿고있어. 올바른 말은 올바른 형식의 응용 프로그램 및 명령을 실행하는 데 제한이 있다는 것입니다. 즉, 기괴한 공간 수가없고 & 비동기를 실행할 수 없으며 다중 파이프 명령이 없습니다.

답변

0

하나의 문제는 cin.getline()에서 반환을 확인하지 않으므로 EOF를 입력하면 코드가 좁은 루프가됩니다. 너는 또한 기억을 새고있다.

시도 :

while (cout << prompt && cin.getline(buffer, sizeof(buffer)) 
{ 
    int count = 0; 
    char **split = Split(buffer, count); 
    Run(split, count); 
    delete[] split; 
} 

Split()의 코드가 정말로 잘 빈 줄을 처리하지 않습니다. 유일한 인수가 null 포인터 인 경우 aeon을 사용하여 execvp()을 실행하는 것처럼 보입니다. 빈 포인터를 반환하면 어떻게됩니까?


나는 그런 '정력 메이크'와 '쉘을'과 '1! -l'와 '고양이 셸 (여러 간단한 명령을 실행할 수 있어요.cpp '등등 - 나는 두 개 이상의 인수로 몇 개를 만들었습니다.) 이것으로 OK, 그리고 Control-D 등으로 명령 (쉘)을 종료 할 수 있습니다. g++ -O -Wall -o shell shell.cpp에서 경고없이 컴파일되도록 수정했습니다. 빈 줄이나 빈 줄을 올바르게 처리 할 수 ​​있도록 분할 코드를 수정하지 않았습니다.

#include <iostream> 
#include <string> 
#include <unistd.h> 

using namespace std; 

char** Split(char* buffer, int &count) { 
    count = 1; 
    for (size_t i = 0; i < strlen(buffer); i++) { // #1 
     if (buffer[i] == ' ') { 
      count++; 
     } 
    } 
    char** args = new char*[count + 1]; 
    const char* delim = " "; 
    char* t = strtok(buffer, delim); 
    for (int i = 0; i < count; i++) { 
     args[i] = t; 
     t = strtok(NULL, delim); 
    } 
    args[count] = 0; 
    return args; 
} 

void Run(char** argv, int argc) { 
    int pid = 0; 
    if ((pid = fork()) == 0) { 
     //for testing purposes, print all of argv 
     for (int i = 0; i < argc; i++) 
     { 
      if (argv[i] != 0) // #2 
       cout << "{" << argv[i] << "}" << endl; 
      else 
       cout << "{ NULL }" << endl; // #3 
     } 
     execvp(argv[0], argv); 
     cout << "ERROR 1" << endl; 
     exit(1); 
    } else if (pid < 0) { 
     cout << "ERROR 2" << endl; 
     exit(2); 
    } 
    wait(NULL); 
} 

int main(int argc, char * const argv[]) { 
    char buffer[512]; 
    char prompt[] = ":> "; 
    while (cout << prompt && cin.getline(buffer, sizeof(buffer))) // #4 
    { 
     int count = 0; 
     char **split = Split(buffer, count); 
     if (count > 0) // #5 
      Run(split, count); 
     delete[] split; // #6 
    } 
} 

중요한 변경 사항을 표시했습니다 (대부분 큰 것은 아닙니다). MacOS X 10.6.6에서 GCC 4.2.1로 컴파일 중입니다.

버퍼에서보고있는 가비지 문자를 쉽게 설명 할 수 없습니다.

+0

EOF를 cin으로 넣을 수있는 것은 무엇입니까? 그게 내 문제의 뿌리라고 생각해. 난 당신의 코드를 시도하고 지금 루핑 대신 종료. 개인적으로 그것은 개선 하하입니다. 나는 "ls"와 "ls -l"을 따옴표없이 단지 (현재는) 테스트하고있다. 두 명령이 무엇인지에 관계없이 항상 두 번째 명령을 실행하면 항상 실패하는 것으로 보입니다. –

+0

@corey : 쉘을 종료하려면 어떻게해야합니까? 누군가 인터럽트를 입력하도록 강요하는 것은 불쾌합니다. 파일에서 입력을 리다이렉트하면 파일은 EOF에 도달하고 코드는 '포크 폭탄'이 아니더라도 '프롬프트 폭탄'으로 엉망이됩니다. 빈 입력, 빈 줄은 항상 축약 된 경우를 처리해야합니다. –

+0

우리는 Ctrl + C를 사용하여 끝내라고했습니다. Ctrl + D에 대해 알고 있으며 나중에 설명 할 수 있습니다. 네가 말하는 정확한 폭탄 테러 문제가있어. 포크에서 명령을 실행하면 (입출력 방향이 바뀐 명령 포함), EOF가 주 프로세스의 cin.getline (...)에 영향을 미치지 않을까요? –

0

입력 줄에 다음과 같은 내용이 포함되어 있다고 가정합니다. 공백보다 하나 더 많은 토큰. 이 가정은 입력 행이 비어 있거나 끝나거나 공백으로 시작되거나 여러 개의 연속 공백을 포함하면 실패 할 수 있습니다. 이 경우, strtok에 대한 호출 중 하나는 NULL을 리턴 할 것이고, Run에서 해당 인수를 인쇄하려고하면 분기 된 프로세스가 충돌합니다. 이들은 내가 문제를 겪은 유일한 경우입니다. 다른 사람을 만나면 입력 내용을 지정하십시오.

이러한 가정을 피하기 위해 토큰 화하는 것과 같은 방법으로 strtok를 계산할 수 있습니다. 이것은 일반적으로 좋은 생각입니다. 일치하는 데 두 가지가 필요하고 동일한 방식으로 수행 할 수있는 경우, 대신 다른 방식으로 수행하면 오류의 추가 원인이 발생합니다.

+0

매우 제한적인 오류 검사가 필요하며 모든 입력이 정확하다고 가정합니다. 올바른 말은 내 응용 프로그램이 명령을 실행하도록 적절하게 형식화되고 제한된다는 의미입니다. 즉, 기괴한 공간 수, 아니오 & 비동기, 다중 파이프 명령 등을 실행할 수 없습니다. "공백보다 하나 많은 토큰"에 대해서는 명령 " ls "는 공백이없는 하나의 토큰을 포함하고"ls -l "은 1 개의 공백을 갖지만 2 개의 토큰을가집니다. 결코 이것이 완료된 프로젝트가 아니며, 나는 심지어 시작하지 않았다 <, > 및 | 하지만 명령을 실행할 수있게되면 그 명령에 문제가있을 것이라고 생각하지 않습니다. 나는 미안하다. –

+0

OK, 문제는 없지만 코드가 실패 할 때 "올바른"입력을하십시오.이 코드는 저에게 효과가있는 것 같습니다. – joriki

+0

"ls"와 "ls -l"을 따옴표없이 사용하려고합니다. 포크에 대해 배울 때 끊임없이 "터치"명령이나 "rm"명령을 실행하려는 부작용이없는 간단한 간단한 명령. 어쨌든 Jonathan Leffler의 의견으로는 진전을 이루고 있지만 어떤 명령을 입력했는지 상관없이 항상 두 번째 명령이 실패합니다. –