0

我创建了这个函数,它充当基于终端的应用程序的主菜单:

bool wizard_run() {
   char *command = NULL;
   bool repeat = false;
   bookmark:

   terminal_prepare();
   terminal_message(MESSAGE_INTRODUCTION);

   loop: /* repeat until a valid command */ {
      free(command); /* free any previous command */
      command = terminal_command(PROMPT_COMMAND, COMMAND_LENGTH, repeat);

      if (!strcmp(command, COMMAND_ENCRYPT)) wizard_encrypt();
      else if (!strcmp(command, COMMAND_DECRYPT)) wizard_decrypt();
      else if (!strcmp(command, COMMAND_CONCEAL)) wizard_conceal();
      else if (!strcmp(command, COMMAND_REVEAL)) wizard_reveal();
      else if (!strcmp(command, COMMAND_ERASE)) wizard_erase();
      else if (!strcmp(command, COMMAND_GENERATE)) wizard_generate();
      else if (!strcmp(command, COMMAND_NAVIGATE)) directory_navigate(RDS_HOME)
      else if (!strcmp(command, COMMAND_SESSION)) wizard_session();
      else if (!strcmp(command, COMMAND_SAFEMODE)) wizard_safemode();
      else if (!strcmp(command, COMMAND_HELP)) wizard_help(HELP_MAINMENU)
      else if (!strcmp(command, COMMAND_EXIT)) {free(command); return false;}
      else {repeat = true; goto loop;}
   }

   free(command); /* free last command */
   return true;
}

所有大写的值都是#defined常量,除了宏之外...(...)都是函数(这就是为什么没有分号结束这些行的原因)。wizard_help(...)directory_navigate(...)

这是应用程序的主要功能:

void main() {
   // initialize any Components needed
   if (!directory_rdsload()) return;
   packager_reset();

   // show the Splash Screen
   SPLASH();

   // continuously execute the Main Thread
   while (wizard_run()); /* execution loop */

   // perform any Clean-UP needed before exit
   reset();
   encryption_reset();
   directory_reset(is_safemode);
}

在这里,只有SPLASH()一个宏。

所有布尔值(即true, false)都是预定义的 unsigned char 值,而boolis typedef unsigned char bool;

它的正常行为是在用户输入(COMMAND_EXIT 的当前值)wizard_run()时退出循环,执行然后正常终止应用程序。相反,当我第一次键入时,它会重新显示菜单,当我第二次键入时,它会终止并出现以下错误:exitreset(); encryption_reset(); directory_reset(is_safemode);exitexit

application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.
Aborted (core dumped)

当程序在 下运行时gdb,我收到此错误:

application: cxa_atexit.c:99: __new_exitfn: Assertion `l != ((void *)0)' failed.

Program received signal SIGABRT, Aborted.
0xb7fdd424 in __kernel_vsyscall ()

main()除了调用之外没有其他功能wizard_run(),因此这不是重新显示菜单而不是退出的原因。有任何想法吗?

提前致谢!!!:D

4

1 回答 1

0

好的,最终我发现了问题!它位于SPLASH(). 这是一个宏定义为:

#define SPLASH() { \
   if (!vfork()) execlp("/bin/splash", "/bin/splash", NULL); \
   else wait(); \
}

由于我的应用程序仍处于测试阶段,因此我没有放入splashdirectory /bin。我从没想过这会是个问题。但是,这里有一个问题:我使用vfork而不是fork,因为我只想执行一个新程序(vfork当您不需要 Child 成为 Parent 进程的副本时会更快)。由于不/bin/bash存在,execlp 没有为子进程加载新的应用程序映像。因此,我可以想象这两个进程都在共享他们的图像的一部分?(看这里

因此,当SPLASH()被调用时,子进程接管并再次显示主菜单。一切看起来都很好。但是当我打电话时exit,孩子正常终止,父母控制终端并重新显示主菜单(这就是它显示两次的原因!)。再次exit调用时,轮到父进程终止。但是,与父进程共享相同进程映像的子进程已经终止,从而改变了一些数据。一定是这个改变的数据导致了退出错误。

当我的函数清除终端并覆盖之前的消息时,我无法注意到子进程首先显示主菜单!;)

我对整个问题的性质感到非常兴奋。虽然我无法更好地解释它(我的术语肯定犯了一些错误),但我希望你明白哪里出了问题!感谢大家的有用评论(尤其是 WhozCraig)!!!:D

于 2013-08-26T13:04:24.053 回答