树莓派Simulink S-function运行时出现free(): invalid pointer错误
问题描述
我开发了一个通过自定义API控制电机控制器的程序,API负责打开COM端口、读取输出和写入命令。程序在Linux和Windows终端运行正常;直接部署到树莓派4通过命令终端运行也无崩溃问题。但将其封装为Simulink S-function块部署到树莓派后出现异常:
- Simulink块在Windows和Linux的Matlab中编译正常,仿真运行无问题
- 部署到树莓派硬件后,执行几个命令就崩溃,抛出
free(): invalid pointer错误
编译及运行日志:
Top model targets built: Model Action Rebuild Reason ========================================================================================================================= RWComs_model_OLDER Code generated and compiled Dependency RWComs_Sfunc.mexa64 of S-function RWComs_Sfunc has changed. 1 of 1 models built (0 models already up to date) Build duration: 0h 0m 24.625s A run-time error is encountered when running External mode simulation on the Raspberry Pi hardware. This usually occurs when a hardware resource, such as a web camera or an audio card, is not available or configured incorrectly. The log file, /home/pi/MATLAB_ws/R2020b/RWComs_model_OLDER.log, storing model diagnostic information on the Raspberry Pi hardware has the following content: **** Starting the application **** Opening port: '/dev/ttyACM0'...succeeded. Initializing port......done. Detecting device version...v2.1. free(): invalid pointer
调试情况:
- 通过注释代码定位到问题与树莓派的读写操作相关
- 崩溃看似发生在
device->IssueCommand()调用时,但device->Connect()中隐式调用该函数却能成功,因此排除函数本身问题 - 代码中无显式
free()调用,无法确定根源
Simulink S-function封装代码如下:
/* * Include Files * */ #if defined(MATLAB_MEX_FILE) #include "tmwtypes.h" #include "simstruc_types.h" #else #include "rtwtypes.h" #endif /* %%%-SFUNWIZ_wrapper_includes_Changes_BEGIN --- EDIT HERE TO _END */ #include <iostream> #include <cstring> #include <string> #include <vector> #include "Device.h" #include "ErrorCodes.h" /* %%%-SFUNWIZ_wrapper_includes_Changes_END --- EDIT HERE TO _BEGIN */ #define u_width 1 #define y_width 1 /* * Create external references here. * */ /* %%%-SFUNWIZ_wrapper_externs_Changes_BEGIN --- EDIT HERE TO _END */ /* %%%-SFUNWIZ_wrapper_externs_Changes_END --- EDIT HERE TO _BEGIN */ /* * Start function * */ void RWComs_Sfunc_Start_wrapper(void **pW, const real_T *comPort, const int_T p_width0) { /* %%%-SFUNWIZ_wrapper_Start_Changes_BEGIN --- EDIT HERE TO _END */ Device* device = new Device(); string str = ""; pW[0] = device; //Sets com port depending on operating system #ifdef __linux__ char port[] = "/dev/ttyACM"; #else char port[] = R"(\\.\COM)"; #endif char integer_string[100]; sprintf(integer_string, "%d", (int)comPort[0]); strcat(port, integer_string); #ifndef MATLAB_MEX_FILE device->Connect(port); device->IssueCommand("!", "MG", "", 1, str, true); device->IssueCommand("", R"(/"d=",":"?bs 1_?a 1_?V 2_# 10_)", "", 1, str, true); #endif /* %%%-SFUNWIZ_wrapper_Start_Changes_END --- EDIT HERE TO _BEGIN */ } /* * Output function * */ void RWComs_Sfunc_Outputs_wrapper(const real_T *cmd, real_T *rpm, real_T *current, real_T *voltage, void **pW, const real_T *comPort, const int_T p_width0) { /* %%%-SFUNWIZ_wrapper_Outputs_Changes_BEGIN --- EDIT HERE TO _END */ Device* device = (Device*) pW[0]; string str = ""; device->IssueCommand("!", "G " + to_string(cmd[0]), "", 0, str, false); returnData rtn = device->readRpmVoltageCurrent(str); rpm[0] = rtn.rpm; current[0] = rtn.cur / 10.0; voltage[0] = rtn.volt / 10.0; /* %%%-SFUNWIZ_wrapper_Outputs_Changes_END --- EDIT HERE TO _BEGIN */ } /* * Terminate function * */ void RWComs_Sfunc_Terminate_wrapper(void **pW, const real_T *comPort, const int_T p_width0) { /* %%%-SFUNWIZ_wrapper_Terminate_Changes_BEGIN --- EDIT HERE TO _END */ printf("I'm in Terminate\n"); Device* device = (Device*) pW[0]; #ifndef MATLAB_MEX_FILE device->Disconnect(); delete(device); #endif /* %%%-SFUNWIZ_wrapper_Terminate_Changes_END --- EDIT HERE TO _BEGIN */ }
可能的原因及解决方案
1. 栈溢出破坏内存结构(最可能)
在Start_wrapper函数中,你使用栈分配的字符数组port:
#ifdef __linux__ char port[] = "/dev/ttyACM"; #else char port[] = R"(\\.\COM)"; #endif
这个数组的长度刚好等于字符串长度加1,后续用strcat拼接端口号时,会直接超出数组的栈空间,破坏栈上的其他数据(包括堆管理的元信息),导致后续堆操作(比如delete(device)或API内部的内存管理)触发free(): invalid pointer错误。
修复方法:
增大port数组的长度,改用C++字符串更安全:
// 替换原port相关代码 std::string port; #ifdef __linux__ port = "/dev/ttyACM"; #else port = R"(\\.\COM)"; #endif port += std::to_string(static_cast<int>(comPort[0])); // 转成const char*传给Connect device->Connect(port.c_str());
2. 实时线程与串口操作的线程安全问题
Simulink的Output函数运行在实时调度线程中,而Device类的串口操作可能存在未加锁的共享资源,在实时调度下导致缓冲区或内存结构被破坏。
修复方法:
在S-function中添加互斥锁保护串口操作:
// 在Start_wrapper中初始化互斥锁(需包含<mutex>头文件) #include <mutex> void RWComs_Sfunc_Start_wrapper(void **pW, const real_T *comPort, const int_T p_width0) { Device* device = new Device(); std::mutex* dev_mutex = new std::mutex(); pW[0] = device; pW[1] = dev_mutex; // ... 其他端口初始化代码 ... } // 在Output_wrapper中加锁 void RWComs_Sfunc_Outputs_wrapper(const real_T *cmd, real_T *rpm, real_T *current, real_T *voltage, void **pW, const real_T *comPort, const int_T p_width0) { Device* device = static_cast<Device*>(pW[0]); std::mutex* dev_mutex = static_cast<std::mutex*>(pW[1]); std::lock_guard<std::mutex> lock(*dev_mutex); std::string str = ""; device->IssueCommand("!", "G " + std::to_string(cmd[0]), "", 0, str, false); returnData rtn = device->readRpmVoltageCurrent(str); rpm[0] = rtn.rpm; current[0] = rtn.cur / 10.0; voltage[0] = rtn.volt / 10.0; } // 在Terminate_wrapper中删除互斥锁 void RWComs_Sfunc_Terminate_wrapper(void **pW, const real_T *comPort, const int_T p_width0) { printf("I'm in Terminate\n"); Device* device = static_cast<Device*>(pW[0]); std::mutex* dev_mutex = static_cast<std::mutex*>(pW[1]); #ifndef MATLAB_MEX_FILE device->Disconnect(); delete(device); delete(dev_mutex); #endif }
3. 内存分配器不匹配
如果Device类内部混用了C风格的malloc/free和C++的new/delete,或者Simulink编译环境使用了特殊的内存分配器,可能导致内存管理冲突。
修复方法:
- 确保
Device类中所有内存操作统一使用C++的new/delete,避免混用C风格分配函数。 - 检查是否有跨模块的内存传递(比如API返回的指针被S-function错误释放)。
4. 树莓派串口权限或配置问题
虽然直接运行程序没问题,但Simulink部署的程序可能以不同用户权限运行,或者串口参数被Simulink环境修改。
修复方法:
- 将树莓派用户加入
dialout组,确保串口访问权限:sudo usermod -aG dialout pi - 在
Device::Connect中显式配置串口参数(波特率、数据位、停止位、流控),避免依赖系统默认配置。
调试建议
- 在树莓派上用
gdb调试部署的程序,定位具体崩溃点:gdb /home/pi/MATLAB_ws/R2020b/RWComs_model_OLDER run # 崩溃后输入bt查看完整调用栈 - 在
Device类的关键函数中添加日志,记录内存分配/释放的地址,排查重复释放或非法释放的情况。
内容的提问来源于stack exchange,提问作者Noah Bruckner
相关产品推荐
相关产品推荐

