kicad运行时出错,_Pnext->_Myproxy = nullptr;访问内存出错

花费了比较长的时间,解决了编译过程中遇到的许多问题后,终于把这个开源的工程编译好了,运行post build 脚本将需要的链接文件拷贝好。正当我以为没有任何问题了,双击可执行程序运行。

结果运行起来的时候报错了,提示无法正常启动,根据这个这个报错的提示,网上搜了一下,都说是缺少dll库导致的,于是将post build脚本又运行了一遍,重新双击打开可执行程序,还是报一样的错。

那么是缺少那个dll库导致的呢?于是我打开系统的事件查看器,从里面找到了应用程序错误事件,点击看到了详细信息,从描述来看出错的模块是libprotobufd.dll,是在运行这个dll的过程中出现的异常,并非缺少dll导致。

{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(msvc) launch",
            "type": "cppvsdbg",
            "request": "launch",
            "program": "D:\\Kicad\\kicad-source-mirror\\build\\out\\bin\\kicad.exe"
        }

    ]
}

为了进一步弄清楚这个库出错的原因和位置,于是在vscode编辑器中将C/C++相关的插件安装上,设置好debug条件,运行debug功能后,跳转到了出现异常的代码位置。

从给的错误信息可以看出来_Pnext是一个非法值,那么这个值为什么是一个非法值,目前猜测它是一个空指针,或者指向的内存不对,目前只是有这样一个概念,带着这样的疑惑继续分析原因。

_EXPORT_STD template <class _Ty, class _Other = _Ty>
_CONSTEXPR20 _Ty exchange(_Ty& _Val, _Other&& _New_val)
    noexcept(conjunction_v<is_nothrow_move_constructible<_Ty>, is_nothrow_assignable<_Ty&, _Other>>) {
    // assign _New_val to _Val, return previous _Val
    _Ty _Old_val = static_cast<_Ty&&>(_Val);
    _Val         = static_cast<_Other&&>(_New_val);
    return _Old_val;
}

exchange的作用是将第一个参数设置成第二个参数的值,然后返回第一个参数的值,所以auto _Pnext = _STD exchange(_Myproxy->_Myfirstiter, nullptr)可以理解为:

_Pnext = _Myproxy->_Myfirstiter;

_Myproxy->_Myfirstiter = nullptr;

上述只是简单理解这个函数的功能,这样看这里也没有问题

到了这里我们还是无法知道_Pnext指向的区域为什么变成非法的,还有就是_Pnext到底指向的是什么,也就是它到底是什么,怎么来的,于是根据发生异常的调用栈进一步追踪,看一下具体是怎么发生的。根据调用栈我们看到了一个明显的可能有问题的地方那就是std::string::~basic_string(),这里先猜测string对象析构的时候发生了异常,析构的时候一般会去释放资源,是不是释放的资源出来问题,所以才导致的异常。

bool EncodedDescriptorDatabase::DescriptorIndex::AddSymbol(
    absl::string_view symbol) {
  SymbolEntry entry = {static_cast<int>(all_values_.size() - 1),
                       EncodeString(symbol)};
  std::string entry_as_string = entry.AsString(*this);

  // We need to make sure not to violate our map invariant.

  // If the symbol name is invalid it could break our lookup algorithm (which
  // relies on the fact that '.' sorts before all other characters that are
  // valid in symbol names).
  if (!ValidateSymbolName(symbol)) {
    ABSL_LOG(ERROR) << "Invalid symbol name: " << entry_as_string;
    return false;
  }

  auto iter = FindLastLessOrEqual(&by_symbol_, entry);
  if (!CheckForMutualSubsymbols(entry_as_string, &iter, by_symbol_.end(),
                                *this)) {
    return false;
  }

  // Same, but on by_symbol_flat_
  auto flat_iter =
      FindLastLessOrEqual(&by_symbol_flat_, entry, by_symbol_.key_comp());
  if (!CheckForMutualSubsymbols(entry_as_string, &flat_iter,
                                by_symbol_flat_.end(), *this)) {
    return false;
  }

  // OK, no conflicts.

  // Insert the new symbol using the iterator as a hint, the new entry will
  // appear immediately before the one the iterator is pointing at.
  by_symbol_.insert(iter, entry);

  return true;
}

于是继续追踪代码里面是哪个执行造成的,还是根据前面的调用栈,我们看到执行完AddSymbol后,会调用~basic_string(),那么根据上面的代码来看,应该是entry_as_string这个对象的使用有问题。

根据debug信息,看到entry_as_string的内存有问题,到这来还不知道是因为被释放了,还是本身创建出来的就有问题,继续追踪这个是怎么创建出来的。

std::string AsString(const DescriptorIndex& index) const {
      auto p = package(index);
      return absl::StrCat(p, p.empty() ? "" : ".", symbol(index));
    }
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
  std::string result;
  // Use uint64_t to prevent size_t overflow. We assume it is not possible for
  // in memory strings to overflow a uint64_t.
  constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
  const uint64_t result_size = static_cast<uint64_t>(a.size()) +
                               static_cast<uint64_t>(b.size()) +
                               static_cast<uint64_t>(c.size());
  ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
  strings_internal::STLStringResizeUninitialized(
      &result, static_cast<size_t>(result_size));
  char* const begin = &result[0];
  char* out = begin;
  out = Append(out, a);
  out = Append(out, b);
  out = Append(out, c);
  assert(out == begin + result.size());
  return result;
}

这里重点是std::string result;这个result有问题,但是有实在看不出代码哪里有问题,于是只能继续debug,进入这个函数后一步步运行,看一下具体是哪里出了问题。

在运行的过程中,这个result的就没有显示出来,它的内存是什么,指向哪里根本不知道。

只知道这个函数返回的时候,entry_as_string指向了一个错误的内存,最终导致崩溃,目前从debug的过程来看不出具体是什么原因导致的问题。

于是写了一段类似的测试代码,看看能不能复现到这样的问题,也可以对比这个过程中有哪些不一样,看看能不能找出根本原因。

测试代码在运行的过程中没有出错,只能看到它们不一样的地方

异常代码测试代码
1std::string result 没有跑构造函数std::string result 正常跑构造函数
2debug过程没有显示result的信息debug过程会显示result的信息
3函数里面的begin、out等变量也没有信息函数里面的begin指向和显示没有问题

目前猜测可能是std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) 函数里面的代码被优化了导致的。

<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg"> <!-- 背景和边框 --> <rect width="800" height="600" fill="#f9f9f9" stroke="#333" stroke-width="1"/> <!-- 标题 --> <text x="400" y="30" font-family="Arial" font-size="20" text-anchor="middle" font-weight="bold">导热性测试装置电路原理图</text> <!-- 电源模块 --> <g transform="translate(100, 100)"> <rect width="150" height="120" fill="#e6f7ff" stroke="#1890ff" stroke-width="1.5" rx="5" ry="5"/> <text x="75" y="30" font-family="Arial" font-size="16" text-anchor="middle" font-weight="bold">电源模块</text> <!-- USB接口 --> <rect x="20" y="60" width="20" height="30" fill="#ddd" stroke="#666"/> <text x="10" y="75" font-family="Arial" font-size="12" text-anchor="end">USB</text> <!-- 稳压器 --> <rect x="60" y="50" width="40" height="40" fill="#fff" stroke="#666"/> <text x="80" y="70" font-family="Arial" font-size="12" text-anchor="middle">AMS1117-5.0</text> <!-- 滤波电容 --> <circle cx="120" cy="65" r="5" fill="#fff" stroke="#666"/> <text x="120" y="75" font-family="Arial" font-size="10" text-anchor="middle">100μF</text> <!-- 输出 --> <line x1="140" y1="65" x2="150" y2="65" stroke="#666" stroke-width="1.5"/> <text x="155" y="70" font-family="Arial" font-size="12">5V</text> </g> <!-- 主控模块 --> <g transform="translate(325, 100)"> <rect width="150" height="180" fill="#fff0f0" stroke="#f5222d" stroke-width="1.5" rx="5" ry="5"/> <text x="75" y="30" font-family="Arial" font-size="16" text-anchor="middle" font-weight="bold">主控模块</text> <!-- MCU --> <rect x="35" y="60" width="80" height="80" fill="#fff" stroke="#666"/> <text x="75" y="100" font-family="Arial" font-size="12" text-anchor="middle">STM32F103C8T6</text> <!-- 晶振 --> <rect x="15" y="110" width="20" height="15" fill="#fff" stroke="#666"/> <text x="25" y="120" font-family="Arial" font-size="8" text-anchor="middle">8MHz</text> <!-- 电源连接 --> <line
06-13
### 导热性测试装置电路原理图设计 导热性测试装置的电路原理图通常包含多个关键模块,例如电源模块、主控模块以及传感器接口模块。以下是关于这些模块的详细信息: #### 1. 电源模块 电源模块的设计需要确保为整个系统提供稳定且可靠的电压。常见的元件包括AMS1117-5.0稳压器,用于将输入电压转换为稳定的5V输出[^1]。此外,还需要添加滤波电容以减少电源噪声,推荐使用10μF和0.1μF的陶瓷电容并联连接在稳压器的输入和输出端[^2]。 ```python # 示例:电源模块的Python伪代码表示(仅作参考) def power_module(input_voltage): # AMS1117-5.0稳压器处理 output_voltage = 5.0 # 稳定输出电压 return output_voltage ``` #### 2. 主控模块 主控模块的核心通常是微控制器单元(MCU),如STM32F103C8T6。该芯片具有高性能的ARM Cortex-M3内核,支持多种外设接口,适用于复杂的控制任务[^3]。为了实现高效的导热性测试,可以通过GPIO引脚与外部传感器或执行器进行通信,并利用其内置的ADC功能采集温度数据[^4]。 ```c // 示例:初始化STM32F103C8T6 GPIO引脚的C语言代码 void GPIO_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 启用GPIOA钟 GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; // 配置PA0引脚 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 设置速度为50MHz GPIO_Init(GPIOA, &GPIO_InitStruct); // 初始化GPIOA } ``` #### 3. SVG格式的原理图 SVG(Scalable Vector Graphics)是一种基于XML的矢量图形格式,适合用于绘制电路原理图。可以使用专业的EDA工具(如KiCad、Eagle等)生成SVG格式的原理图文件[^5]。以下是一个简单的SVG示例,展示如何定义基本的矩形形状: ```xml <svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"> <rect x="10" y="10" width="80" height="80" style="fill:blue" /> </svg> ``` 通过上述方法,可以将电源模块、主控模块以及其他相关组件整合到一个完整的SVG原理图中[^6]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值