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

execve后无法访问共享内存中动态分配的struct destinations指针问题

共享内存中动态分配指针跨execve进程访问异常问题

问题描述

我重新整理了完整的最小可复现代码,希望能解决这个问题:

struct destinations* 在getDestinations和createDestination函数中动态分配,写入共享内存shmp的airplane_array后,当前进程能正常读取它的city和airport元素。但通过execve启动的新进程尝试访问airplane_array里的动态分配元素时,程序直接停住了(最后的printf根本没执行)。

注意:

  • 新进程会先脱离共享内存,再重新挂载到之前初始化的内存区域(地址存在shmatAddress里)
  • 就算不重新挂载,访问int company字段也完全没问题

我已经确认共享内存地址和元素地址都是正确的,输出日志可以证明。想请教怎么在execve之后访问city和airport变量,或者该怎么重新设计struct destinations*这个变量?

CLASS.C

#define SHM_KEY 0x105

#include <stddef.h>
#include <stdlib.h>

#include <time.h>
#include <stdio.h> 
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/types.h>

struct destinations *getDestinations();
struct destinations createDestination();

struct destinations{
   int city;
   int airport;
};

struct airplane {
   int company;
   struct destinations *destinations;
};

struct shmseg {      
   void *shmatAddress;
   struct airplane airplane_array[];
};

int num_airplanes = 10;
int shmid;
pid_t childPid;

int main(int argc, char *argv[]){
   struct shmseg *shmp;
   int i, j, k = 0;
   
   size_t shmp_size = sizeof(struct shmseg) + (num_airplanes * sizeof(struct airplane));
   shmp = (struct shmseg *) malloc(shmp_size);
   
   if (shmp == NULL) {}
   
   if((shmid = shmget(SHM_KEY, sizeof(struct shmseg) + (num_airplanes * sizeof(struct airplane)), IPC_CREAT | S_IRUSR | S_IWUSR)) == -1){
   }
   
   if ((shmp = shmat(shmid, NULL, 0)) == (void*) -1){
   }
   
   shmp->shmatAddress = (void *)shmp;
   
   
   for(i=0; i<1; i++){
   switch(childPid = fork()){
      case -1:{}
      case 0:{
         char *argv[] = {NULL};
         char *envp[] = {NULL};
         
         struct destinations *destinations_array = NULL;
         destinations_array = getDestinations();
         
         shmp->airplane_array[i].destinations = malloc(num_airplanes * sizeof(struct destinations));
               
         for( j=0;j<4;j++){
            memcpy(&shmp->airplane_array[i].destinations[j], &destinations_array[j], sizeof(struct destinations));
         }
         
         for ( k = 0; k < 4; k++) {
            printf("SHMP: %d - %d\n", 
            shmp->airplane_array[i].destinations[k].city, shmp->airplane_array[i].destinations[k].airport);
         }
         
         printf("Address of destinations before execve: %p\n", (void *)shmp->airplane_array[0].destinations);
         printf("Address of destinations[0] before execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0]);
         printf("Address of destinations[0].city before execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0].city);
         printf("Address of destinations[0].airport before execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0].airport);
         
         printf("shmp address before execve: %p\n", (void *)shmp);
         
         execve("./newprogram", argv, envp);
         
      }
      default:
   }
   }
   return 0;
}

struct destinations *getDestinations(){
   struct destinations *destinationsRet = NULL;
   int countDestinations = 0;
   int i = 0;
   for(i=0; i<4; i++){
      struct destinations my_destination = createDestination();
      destinationsRet = (struct destinations *) realloc(destinationsRet, (countDestinations + 1) * sizeof(struct destinations));
      destinationsRet[i] = my_destination;
      countDestinations++;
   }
   return destinationsRet;
}

struct destinations createDestination(){
   struct destinations my_destination;
   my_destination.city = 100;
   my_destination.airport = 200;
   return my_destination;
}

NEWPROGRAM.C

#define SHM_KEY 0x105

#include <stddef.h>
#include <stdlib.h>

#include <time.h>
#include <stdio.h> 
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/msg.h>
#include <sys/types.h>

struct shmseg *shmp;

struct destinations{
   int city;
   int airport;
};

struct airplane {
   int company;
   struct destinations *destinations;
};

struct shmseg {      
   void *shmatAddress;
   struct airplane airplane_array[];
};

int shmid;

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

   int num_airplanes = 10;
   int k = 0;

   void *address;

   if ((shmid = shmget(SHM_KEY, sizeof(struct shmseg) + (num_airplanes * sizeof(struct destinations)), 0)) == -1) {
   }

   if ((shmp = (struct shmseg *)shmat(shmid, NULL, 0)) == (void *)-1) {
   }
   
   address = shmp->shmatAddress;
   
   printf("shmp address after execve (before re-attaching): %p\n", (void *)shmp);
   
   if (shmdt(shmp) == -1) {
   }
   
   if ((shmp = (struct shmseg *)shmat(shmid, address, SHM_RND || SHM_REMAP)) == (void *)-1) {
   }
   
   printf("shmp address after execve (after re-attaching): %p\n", (void *)shmp);
   
   printf("Address of destinations after execve: %p\n", (void *)shmp->airplane_array[0].destinations);
   printf("Address of destinations[0] after execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0]);
   printf("Address of destinations[0].city after execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0].city);
   printf("Address of destinations[0].airport after execve: %p\n", (void *)&shmp->airplane_array[0].destinations[0].airport);

   for ( k = 0; k < 4; k++) {
      printf("SHMP from new program: %d - %d\n", 
      shmp->airplane_array[0].destinations[k].city, shmp->airplane_array[0].destinations[k].airport);
   }

   printf("program will die before this.\n");
   
   return 0;

}

输出日志

SHMP: 100 - 200
SHMP: 100 - 200
SHMP: 100 - 200
SHMP: 100 - 200
Address of destinations before execve: 0x1045380
Address of destinations[0] before execve: 0x1045380
Address of destinations[0].city before execve: 0x1045380
Address of destinations[0].airport before execve: 0x1045384
shmp address before execve: 0x7f3ceeb60000
shmp address after execve (before re-attaching): 0x7ff2ff80d000
shmp address after execve (after re-attaching): 0x7f3ceeb60000
Address of destinations after execve: 0x1045380
Address of destinations[0] after execve: 0x1045380
Address of destinations[0].city after execve: 0x1045380
Address of destinations[0].airport after execve: 0x1045384

问题根源与解决方法

问题根源

核心问题很明确:shmp->airplane_array[i].destinations指向的是原进程私有堆内存的地址,不是共享内存区域。

原进程用malloc分配的内存属于该进程独有的堆空间,execve启动的新进程是完全独立的地址空间,这个0x1045380地址在新进程里是无效的,访问时直接触发段错误,程序崩溃,所以最后的printf根本执行不到。

而company字段是直接存在共享内存的struct airplane结构体中,属于共享内存区域,所以跨进程访问完全正常。

解决方法

有两种简单可行的改造方案:

方案1:直接把目标数组嵌入共享内存结构体

放弃使用指针,直接在struct airplane里定义固定大小的数组(和你的代码逻辑匹配):

struct airplane {
   int company;
   struct destinations destinations[4]; // 直接包含4个目标结构体
};

这样所有数据都存在共享内存里,跨进程访问不会有任何问题。如果需要动态数量,也可以用柔性数组,在创建共享内存时计算好总大小即可。

方案2:在共享内存内部分配目标数组空间

如果一定要用指针,不能用malloc,而是要从共享内存的预留空间里分配。比如创建共享内存时,把总大小设置为包含所有需要的空间:

// 总大小 = shmseg结构 + 10个airplane + 10个airplane各自的4个destinations
size_t total_shm_size = sizeof(struct shmseg) 
                       + num_airplanes * sizeof(struct airplane)
                       + num_airplanes * 4 * sizeof(struct destinations);
shmid = shmget(SHM_KEY, total_shm_size, IPC_CREAT | S_IRUSR | S_IWUSR);

然后在原进程里,把destinations指针指向共享内存内部的预留地址:

// 计算当前airplane对应的destinations起始地址
struct destinations *shared_dest = (struct destinations*)((char*)shmp 
                                   + sizeof(struct shmseg) 
                                   + num_airplanes * sizeof(struct airplane)
                                   + i * 4 * sizeof(struct destinations));
shmp->airplane_array[i].destinations = shared_dest;
// 直接赋值,无需memcpy
for(j=0;j<4;j++){
   shared_dest[j] = destinations_array[j];
}

这样指针指向的是共享内存内部的地址,新进程挂载共享内存后,这个地址在新进程的地址空间里也是有效的。

另外注意:代码里的SHM_RND || SHM_REMAP应该用位或运算符|,不是逻辑或||,虽然这不是当前崩溃的原因,但会导致重新挂载共享内存的参数错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:09:50