c-在目录外移动二进制文件时出现分段故障



大家好,这是我在这里的第一篇文章。

我认为我的问题很愚蠢,但我找不到任何解决方案,希望你能帮助我!

所以,我和一个朋友正在编写一个小型系统监视器(learn-better/fun),代码有两个部分:守护程序和命令行接口(目前),当我编译CLI部分时,一切都很好,守护程序是一个特殊的部分,因为当我编译并在编译目录中执行它时,它可以正常工作!神奇的是,当我移出编译目录时,它会给我一个分段错误!

编译器:GCC

这是存储库:https://github.com/StefanoBelli/JASM

Makefile:

 #!/usr/bin/make -f
SHELL=/bin/sh
####    CONFIGURATION    ####
CC=gcc
DEBUG=-g
CFLAGS=-O2 -pipe -Wall -std=c11 $(DEBUG)
LIBS=
BINOUT=jasm
####    SOURCES & RULES    ####
OBJS:=$(patsubst %.c,%.o,$(wildcard *.c))
install:$(OBJS)
    $(CC) $(CFLAGS) $(LIBS) -o $(BINOUT) $(OBJS) 
clean:
    rm -fv *.o
.PHONY: install,clean

GDB输出:

(gdb) run
Starting program: /home/stefanozzz123/Devel/C.Cpp/JASM/bin/jasm 
Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7a7db04 in vfprintf () from /usr/lib/libc.so.6
(gdb) 

谢谢大家!:)

编辑:正如你所要求的,这里是代码:

jasm.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "queue.h"
#include "miscellaneous.h"
#include "ipc.h"


int main(int argc, char *argv[])
{
  start_daemon();
  start_server();

}

ipc.c

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "ipc.h"
#include "miscellaneous.h"
#include "getter.h"

static void excecute_command(int fd, char *command)
{
  /*
   *  if get* -> modulo get
   *  if start* -> modulo dei moduli
   */
   // ************************** getter ***************************************
   if(strncmp("get", command, 3)==0) {  //ricevuto comando getter
     int i;
     //char buf[BUFSIZ];
     strcpy(command, &command[3]);
     for(i=0; i<NGETTER; i++) {
       if(strcmp(getterName[i], command)==0) { //se esiste getter
         log_string("getter found :)");
         getterFunction[i](fd);
         return;
       }
     }
     log_error("getter NOT found :(");
     write(fd, "null", 4);
     return;
   }
   // ************************** starter **************************************
   if(strncmp("start", command, 5)==0) {  //ricevuto start modulo

     log_error("starter NOT found :(");
     write(fd, "null", 4);
     return;
   }

   // ************************** miscellaneous ********************************
   if(strcmp("halt", command)==0) { //spegne jasm
        log_string("# halt and catch fire, done");
        write(fd, "halt", 4);
        exit(0);
   }

  /*if(strcmp("getVersion", command)==0) {
    write(fd, (void *)VERSION, sizeof(VERSION));
    log_string("server reply <version> with success");
    return;
  }*/
    log_error("request not found");
    write(fd, "null", 4);
}
void start_server()
{
int server_sockfd, client_sockfd;
int server_len;
socklen_t client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
int result;
fd_set readfds, testfds;
  server_sockfd=socket(AF_INET, SOCK_STREAM, 0);
  server_address.sin_family=AF_INET;
  server_address.sin_addr.s_addr=htonl(INADDR_ANY);
  server_address.sin_port=htons(SERVER_PORT);
  server_len=sizeof(server_address);
  bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
  listen(server_sockfd, 5);
  FD_ZERO(&readfds);
  FD_SET(server_sockfd, &readfds);
  log_string("server started");
  while(1) {
    char buf[BUFSIZ];
    char received[BUFSIZ];
    int fd;
    int nread;
    testfds=readfds;
    result=select(FD_SETSIZE, &testfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
    if(result<1) {
      log_error("server fail");
      exit(1);
    }
    for(fd=0; fd<FD_SETSIZE; fd++) {
      if(FD_ISSET(fd, &testfds)) {
        if(fd==server_sockfd) {
          client_len=sizeof(client_address);
          client_sockfd=accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);
          FD_SET(client_sockfd, &readfds);
          sprintf(buf, "adding client on fd %d", client_sockfd);
          log_string(buf);
        } else {
          ioctl(fd, FIONREAD, &nread);
          if(nread==0) {
            close(fd);
            FD_CLR(fd, &readfds);
            sprintf(buf, "removing client on fd %d", fd);
            log_string(buf);
          } else {
            read(fd, &received, BUFSIZ);
            sprintf(buf, "received from fd %d command <%s>", fd, received);
            log_string(buf);
            excecute_command(fd, received);
          }
        }
      }
    }
  }
}

杂项。c

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "miscellaneous.h"
char * getTime()
{
  time_t curtime;
  struct tm *loctime;
  static char *ret;
  curtime=time(NULL);
  loctime=localtime(&curtime);
  ret=asctime(loctime);
  ret[24]='';
  return ret;
}
void log_string(const char *message)
{
  FILE *fp;
  fp=fopen(LOGPATH, "a+");
  fprintf(fp, "[%s] %sn", getTime(), message);
  fclose(fp);
}
void log_error(const char *message)
{
  FILE *fp;
  fp=fopen(LOGPATH, "a+");
  fprintf(fp, "[%s] ERROR: %s!n", getTime(), message);
  fclose(fp);
}
void start_daemon()
{
  pid_t pid;
  char buf[BUFSIZ];
  log_string("boot");
  pid=fork();
  switch(pid) {
    case -1:
      log_error("fork fail");
      exit(1);
      break;
    case 0:
      log_string("fork success");
      break;
    default:
      exit(0);
      break;
  }
  if(setsid()<0) {
    log_error("setsid fail");
    exit(1);
  } else {
    log_string("setsid success");
  }
  //chiude i file descriptor di stdin, stdout, stderr
  close(0);
  close(1);
  close(2);
  sprintf(buf, "jasm started with pid %d and ppid %d", getpid(), getppid());
  log_string(buf);
}

本质上,这些是主要的src。。。

GDB Backtrace什么也没说,因为程序运行立即停止

由于这个问题被标记为gdb,让我们看看gdb如何提供帮助。在我的例子中,我已经为libc安装了debuginfo文件,这样我就可以检查C库函数的参数,但在这种情况下,你并不真正需要它,因为我们可以通过查看用户的源代码来发现错误。

(gdb) run
Starting program: ./jasm 
Program received signal SIGSEGV, Segmentation fault.
_IO_vfprintf_internal (s=0x0, format=0x4019b1 "[%s] %sn", 
    ap=ap@entry=0x7fffffffbd38) at vfprintf.c:1295
1295    vfprintf.c: No such file or directory.
(gdb) bt
#0  _IO_vfprintf_internal (s=0x0, format=0x4019b1 "[%s] %sn", 
    ap=ap@entry=0x7fffffffbd38) at vfprintf.c:1295
#1  0x00007ffff7a693f7 in __fprintf (stream=<optimized out>, 
    format=<optimized out>) at fprintf.c:32
#2  0x000000000040149d in log_string (message=0x4019cb "boot")
    at miscellaneous.c:46
#3  0x000000000040151f in start_daemon () at miscellaneous.c:64
#4  0x0000000000401400 in main (argc=1, argv=0x7fffffffdf78) at jasm.c:31

vfprintf的声明是:

int vfprintf(FILE *restrict stream, const char *restrict format, va_list ap);

尽管我们没有安装vfprintf的源代码,但我们可以看到传递给它的第一个参数s是一个NULL流指针,这很可能是seg错误的原因。

让我们来看看我们的源代码:帧2,log_string

(gdb) frame 2
#2  0x000000000040149d in log_string (message=0x4019cb "boot")
    at miscellaneous.c:46
46    fprintf(fp, "[%s] %sn", getTime(), message);
(gdb) print fp
$2 = (FILE *) 0x0

就在那里。

#define LOGPATH "../../../../data/log/jasm.log"
void log_string(const char *message)
{
  FILE *fp;
  fp=fopen(LOGPATH, "a+");
  fprintf(fp, "[%s] %sn", getTime(), message);
  fclose(fp);
}
void log_error(const char *message)
{
  FILE *fp;
  fp=fopen(LOGPATH, "a+");
  fprintf(fp, "[%s] ERROR: %s!n", getTime(), message);
  fclose(fp);
}

检查fopen的返回值。它可能为NULL,这取决于程序运行的目录。最好使用一个绝对路径名,可能可以在Makefile中设置以便于移植。

write(fd, "halt", 4);

所有这些都应该有一个5的计数,包括后面的NUL。(并不是绝对需要在字符串文字中显式地包含,因为C字符串文字的末尾隐含地有一个。)

最新更新