You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspbian Buster与Ubuntu 20.04中shm_open调用触发段错误排查

问题:shm_open触发段错误且共享内存残留的原因分析

问题描述

我在树莓派4(Raspbian Buster)和普通PC(Ubuntu 20.04)上用C语言编写增量编码器数据采集进程时,遇到shm_open()触发段错误的问题,程序崩溃后/dev/shm目录中仍能看到该共享内存段的名称。GCC版本分别为10.2.1(Raspbian)和9.4.0(Ubuntu),添加额外编译标志无效。

编码器进程代码

#include <signal.h>     
#include <stdlib.h>
#include <time.h>
#include "stdio.h"
#include <string.h>
#include <unistd.h>
#include "encbuffer.h"


#define ENNAME          "/test"

int mode = 4;
int pulses_amount_gpio_4 = 0;
int encoder_buffer_fd = 0;
double local_angle = 1;

struct encoder_buffer *enc_buffer;

void* shm_enc_buffer;

void  Handler(int signo)
{
    mode = 2;
}


int main(void)
{
    
// the issue is here
    encoder_buffer_fd = shm_open(ENNAME, O_CREAT|O_RDWR|O_TRUNC, 0666);

   if(encoder_buffer_fd < 0)
   {    
    perror("shm_open()");
    return 1;
   }

    printf("passed buffer opening");
    
   ftruncate(encoder_buffer_fd, sizeof(struct encoder_buffer));
   shm_enc_buffer = mmap(0, sizeof(struct encoder_buffer), PROT_WRITE|PROT_READ, MAP_SHARED,  encoder_buffer_fd, 0);

   // Exception handling:ctrl + c
   signal(SIGINT, Handler);
    
   if(sem_init(&(enc_buffer->semaphore), 1, 1) < 0)
   {
    return 3;
   }
    
   while(mode != 2)
   {
    /*printf("Angle: %f
",  local_angle);
    sleep(1);*/
   }
    
   munmap(0, sizeof(struct encoder_buffer));
   shm_unlink(ENNAME);
  
   return 0;
}

编码器缓冲区头文件(encbuffer.h)

#ifndef _ENCBUFFER_H_
#define _ENCBUFFER_H_


#include <stdlib.h>     
#include <signal.h>     
#include "stdio.h"
#include <semaphore.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/mman.h>
#include <assert.h>
#include <sys/stat.h>      
#include <fcntl.h>   


struct encoder_buffer {
    double angle;
    double previous_angle;
    sem_t semaphore;
};

#endif

Makefile

CC = gcc
MSG = -g -O0 -Wall -I. -lrt -pthread
CFLAGS += $(MSG)

DEPS = encbuffer.h
OBJ = anglecollect.o 

%.o: %.c $(DEPS)
        $(CC) -c -o $@ $< $(CFLAGS)

angle: $(OBJ)
        $(CC) -o $@ $^ $(CFLAGS) 

原因分析

  • 野指针访问导致段错误
    代码中声明了struct encoder_buffer *enc_buffer;但从未对其赋值,直接在sem_init(&(enc_buffer->semaphore), 1, 1)中访问其成员,属于非法内存访问,直接触发段错误。你错误地认为shm_enc_buffer和enc_buffer有关联,但两者没有任何绑定,enc_buffer始终是未初始化的野指针。

  • shm_open()并非段错误触发点
    程序能打印passed buffer opening说明shm_open()执行完全成功。段错误实际发生在后续访问野指针的代码处。而/dev/shm中残留共享内存是因为程序崩溃时还没执行到shm_unlink(ENNAME),POSIX共享内存对象不会随进程退出自动销毁,必须显式调用shm_unlink才能删除。

  • munmap()参数错误
    munmap()的第一个参数必须是mmap()返回的内存地址(即shm_enc_buffer),而不是0。这个错误会导致内存释放失败,但并非本次段错误的直接原因。

修复方案

  1. 绑定共享内存指针
    在mmap()之后,将返回的地址赋值给enc_buffer,建立指针与共享内存的关联:

    shm_enc_buffer = mmap(0, sizeof(struct encoder_buffer), PROT_WRITE|PROT_READ, MAP_SHARED, encoder_buffer_fd, 0);
    enc_buffer = (struct encoder_buffer*)shm_enc_buffer; // 新增该行
    
  2. 修正munmap()参数
    将munmap(0, sizeof(struct encoder_buffer))改为:

    munmap(shm_enc_buffer, sizeof(struct encoder_buffer));
    
  3. 调试输出优化(可选)
    为printf添加换行,确保输出及时刷新到终端,方便调试:

    printf("passed buffer opening\n");
    
  4. 异常退出时清理资源
    在信号处理函数中添加资源清理逻辑,避免Ctrl+C退出时残留共享内存:

    void Handler(int signo)
    {
        mode = 2;
        // 清理共享内存
        if (shm_enc_buffer != NULL) {
            munmap(shm_enc_buffer, sizeof(struct encoder_buffer));
        }
        shm_unlink(ENNAME);
        exit(0); // 确保进程退出
    }
    

内容的提问来源于stack exchange,提问作者V8Interceptor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 04:17:22