C 从共享内存读取Segfault

C 从共享内存读取Segfault,c,segmentation-fault,fork,shared-memory,C,Segmentation Fault,Fork,Shared Memory,我正在做一个家庭作业,用fork()和一个共享内存对象在C中编写collatz猜想的实现,在子进程中执行计算,并在父进程中打印结果。我对C不是很熟悉,所以我学习了很多工具。使用gdb,我在尝试访问父进程中的对象时识别了一个segfault。我使用的是我的代码: #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include

我正在做一个家庭作业,用fork()和一个共享内存对象在C中编写collatz猜想的实现,在子进程中执行计算,并在父进程中打印结果。我对C不是很熟悉,所以我学习了很多工具。使用gdb,我在尝试访问父进程中的对象时识别了一个segfault。我使用的是我的代码:

#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <math.h>

int main(int argc, const char* argv[])
{

const int SIZE  = 4096;
const char *name = "SM";
int shm_fd;
void  *ptr;

pid_t child;


if ((argc != 2) || (strtol(argv[1],NULL, 10) <= 0))
{
        printf("Invalid usage: requires 1 positive integer parameter\n");
        return -1;
}

child = fork();
if(child >=0 )
{
        if (child == 0)
        {
                shm_fd = shm_open(name, O_CREAT || O_RDWR, 0666);
                ftruncate(shm_fd, SIZE);
                ptr = mmap(0, SIZE, PROT_WRITE, MAP_SHARED, shm_fd, 0);
                int currentval = strtol(argv[1],NULL,10);
                sprintf(ptr,"%d",currentval);
                ptr++;/*  floor(log10(abs(currentval))) + 1;*/
                while (currentval > 1)
                {
                        sprintf(ptr, ", ");
                        ptr += 2;
                        if (currentval % 2 == 1)
                        {
                                currentval = currentval * 3 + 1;
                                sprintf(ptr, "%d", currentval);
                                ptr++;
                        }
                        else
                        {
                                currentval = currentval/2;
                                sprintf(ptr, "%d", currentval);
                                ptr++;
                        }
                }
                sprintf(ptr, "\n");
                ptr+= 1;
                return 0;
        }
        else
        {
                wait();

                shm_fd = shm_open(name, O_RDONLY, 0666);
                ptr = mmap(0, SIZE, PROT_READ, MAP_SHARED, shm_fd, 0);
                printf("%s\n",(char *)ptr);
                shm_unlink(name);
                return 0;
        }
}
else
{
        printf("error creating child process\n");
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
int main(int argc,const char*argv[]
{
常数int SIZE=4096;
常量字符*name=“SM”;
int shm_fd;
无效*ptr;
pid_t儿童;
如果((argc!=2)| |(strtol(argv[1],NULL,10)=0)
{
如果(子项==0)
{
shm|U fd=shm|U open(名称,O|U CREAT | O|U RDWR,0666);
ftruncate(shm_fd,尺寸);
ptr=mmap(0,大小,保护写入,映射共享,shm\u fd,0);
int currentval=strtol(argv[1],NULL,10);
sprintf(ptr,“%d”,currentval);
ptr++;/*地板(log10(abs(currentval))+1*/
而(当前值>1)
{
sprintf(ptr,“,”);
ptr+=2;
如果(当前值%2==1)
{
currentval=currentval*3+1;
sprintf(ptr,“%d”,currentval);
ptr++;
}
其他的
{
currentval=currentval/2;
sprintf(ptr,“%d”,currentval);
ptr++;
}
}
sprintf(ptr,“\n”);
ptr+=1;
返回0;
}
其他的
{
等待();
shm_fd=shm_open(名称,O_RDONLY,0666);
ptr=mmap(0,大小,保护读取,映射共享,shm\u fd,0);
printf(“%s\n”,(char*)ptr);
shm_取消链接(名称);
返回0;
}
}
其他的
{
printf(“创建子进程时出错”);
}
返回0;
}

我以前从未调试过segfault,因此欢迎提供任何建议。提前感谢。

您能否粘贴使用gdb创建的核心文件的回溯:

gdb -c <core file> <executable>
gdb-c

它将在gdb中打开内核,然后键入“bt”。这将为您找到问题所在的确切位置。您也可以将该输出粘贴到此处。

我发现了问题。它执行的是逻辑OR而不是按位OR,因此创建的文件描述符不正确

shm|U fd=shm|U open(名称,O|U CREAT | O|U RDWR,0666)

应该是


shm_fd=shm_open(name,O_CREAT | O_RDWR,0666);

我知道这与你问的问题无关,但由于我遇到了这个问题,对于其他可能遇到的人来说,可能会发现以下有用信息:

在阅读和打印Collatz猜想系列时,如果示例为8,则上面的程序运行良好,因为答案是:8,4,2,1 但是如果你试着运行10次,答案是:10,5,16,8,4,2,1,而上面的程序只会显示:1,5,16,8,4,2,1。因为它一次只能读取一个字符。所以这里需要做一些修改

int shift = 0;
char store[sizeof(int)];
while (currentval > 1)
{
        sprintf(ptr, ", ");
        ptr += 2;
        if (currentval % 2 == 1)
        {
                currentval = currentval * 3 + 1;
        }
        else
        {
                currentval = currentval/2;
        }
        sprintf(store, "%s", currentval);  /* Convert the number to a string */
        sprintf(ptr, "%s", store); /* Store the string */ 
        shift = strlen(store);
        ptr += shift;
}
sprintf(ptr, "\n");
ptr+= 1;            

我认为原因可能是您的mmap可能失败。您使用的指针甚至没有检查错误条件。失败时的mmap返回“-1”并设置错误号。我在转储时得到两个核心文件。子文件是:
0 0x00832f25 in _IO_str_overflow_internal()从/lib/tls/libc.so.6到/lib/tls/libc.so.6从/lib/tls/libc.so.6从/lib/tls/libc.so.6到vfprintf()中的/0x0080c4e8从/lib/tls/libc.so.6从/lib/tls/libc.so.6到vsprintf()中的3 0x00827b1b从/lib/tls/libc.so.6到sprintf()中的4 0x00814e3b从/lib/tls/libc.so.6到sprintf()从/lib/tls/libc.so.080x8b5e.so.6到arg2(arg=0x482e=arg2,arg2)在问题3_21.c:42
中,来自父级的bt:strlen()中的0 0x0083c26b来自/lib/tls/libc.so.6#vfprintf()中的1 0x0080f821来自/lib/tls/libc.so.6#2 0x00814dc0来自/lib/tls/libc.so.6#3 0x08048748主要(argc=2,argv=0xbfea2e84)来自问题3您从mmap获得的信息是错误的。处理mmap的错误案例将帮助您解决分段问题。同时检查mmap不起作用的原因。