EXC_BAD_ACCESS:使用 std::array 的问题

EXC_BAD_ACCESS: Issues using std::array

我正在尝试将 boost 库的 odeint 与 std::vectorstd::array 一起使用。在这两种情况下我都没有编译问题,但是,在 std::array 的情况下,我有 运行 关于写入未知地址的时间问题。下面给出的是一个 MWE。

我在header文件中分别用std::vectorstd::array定义了两个类:ODE1ODE2ode.hpp.

#ifndef ODE_HPP_
#define ODE_HPP_

// c++ standard library headers
#include <array>
#include <iostream>
#include <vector>

namespace ode {
constexpr size_t n_variables = 1e4;
}  // namespace ode

class ODE1 {
 public:
  ODE1(const double o) : V_(ode::n_variables, o) {}  // explicit constructor

  std::vector<double>& GetVoltage() { return V_; }

  void operator()(const std::vector<double>& Y, std::vector<double>& dYdt,
                  const double /* time */) {
    using namespace ode;
    for (size_t n = 0; n < n_variables; n++) dYdt[n] = Y[n];
  }

 private:
  std::vector<double> V_{};
};

class ODE2 {
  using Array = std::array<double, ode::n_variables>;

 public:
  // constructors
  ODE2(const double o) { V_.fill(o); }  // explicit constructor

  Array& GetVoltage() { return V_; }

  void operator()(const Array& Y, Array& dYdt, const double /* time */) {
    using namespace ode;
    for (size_t n = 0; n < n_variables; n++) dYdt[n] = Y[n];
  }

 private:
  Array V_{};
};
#endif  //   ODE_HPP_

主要函数定义在文件`ode.cpp'

// related header
#include "ode.hpp"

// other library headers
#include <boost/numeric/odeint.hpp>

int main() {
  constexpr double abs_err = 1.0e-10;
  constexpr double rel_err = 1.0e-8;
  constexpr double sim_duration = 20.0;              // ms
  constexpr double t_start = 0;                      // ms
  constexpr double t_stop = t_start + sim_duration;  // ms
  constexpr double dt = 5e-3;                        // ms
  {
    std::cout << "ODE1\n";
    using namespace boost::numeric::odeint;
    using error_stepper_type = runge_kutta_dopri5<std::vector<double>>;

    ODE1 o(-60.0);
    integrate_adaptive(make_controlled<error_stepper_type>(abs_err, rel_err), o,
                       o.GetVoltage(), t_start, t_stop, dt);
  }
  {
    std::cout << "ODE2\n";
    using namespace boost::numeric::odeint;
    using error_stepper_type =
        runge_kutta_dopri5<std::array<double, ode::n_variables>>;

    ODE2 o(-60.0);
    integrate_adaptive(make_controlled<error_stepper_type>(abs_err, rel_err), o,
                       o.GetVoltage(), t_start, t_stop, dt);
  }
  return 0;
}

我在 macOS Big Sur (11.5.2) 上使用 clang 编译器进行编译,如下所示 c++ -O0 -g -fsanitize=address -fno-omit-frame-pointer -Wall -Wextra -Wpedantic -std=c++17 ode.cpp -o ode

正如我上面提到的,我不 运行 关注编译问题。当我 运行 可执行文件时,我遇到以下问题

ODE1
ODE2
AddressSanitizer:DEADLYSIGNAL
=================================================================
==30573==ERROR: AddressSanitizer: stack-overflow on address 0x7ffee6a1e3f8 (pc 0x00010896439e bp 0x7ffee6d18610 sp 0x7ffee6a1e400 T0)
    #0 0x10896439e in unsigned long boost::numeric::odeint::integrate_adaptive<boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_fsal_tag>, ODE2, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::null_observer>(boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_fsal_tag>, ODE2, std::__1::array<double, 10000ul>&, double, double, double, boost::numeric::odeint::null_observer) integrate_adaptive.hpp:40
    #1 0x10894335e in unsigned long boost::numeric::odeint::integrate_adaptive<boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_fsal_tag>, ODE2, std::__1::array<double, 10000ul>, double>(boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_fsal_tag>, ODE2, std::__1::array<double, 10000ul>&, double, double, double) integrate_adaptive.hpp:83
    #2 0x10894262c in main ode.cpp:30
    #3 0x7fff203d0f3c in start+0x0 (libdyld.dylib:x86_64+0x15f3c)

SUMMARY: AddressSanitizer: stack-overflow integrate_adaptive.hpp:40 in unsigned long boost::numeric::odeint::integrate_adaptive<boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations, boost::numeric::odeint::initially_resizer>, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::array_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_fsal_tag>, ODE2, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::null_observer>(boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_dopri5<std::__1::array<double, 10000ul>, double, std::__1::array<double, 10000ul>, double, boost::numeric::odeint::array_a
==30573==ABORTING
zsh: abort      ./ode

很奇怪,当我在 header 从 10000 到 1000 中更改参数 n_variables 时没有问题。

另外,我用lldb调试了问题,好像是stop reason = EXC_BAD_ACCESS (code=2, address=0x7ffeef3fbc58)

我不太确定这里的问题是什么!任何帮助将不胜感激。

ASAN 增加了程序所需的堆栈内存量,而您的程序已经需要很多。增加堆栈大小限制:

$ ulimit -s 81920
$ ./ode
ODE1
ODE2
$