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

树莓派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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 06:11:16