【问题标题】:How to identify places in MATLAB where data is stored outside the bounds of an array?如何识别 MATLAB 中数据存储在数组边界之外的位置?
【发布时间】:2015-05-22 23:38:24
【问题描述】:

我正在尝试使用 MATLAB Coder 将代码从 Matlab 转换为 MEX 文件。如果我有以下形式的代码 sn-p:

x = zeros(a,1)
x(a+1) = 1

然后在 Matlab 中,这将调整数组的大小以适应新元素,而在 MEX 文件中,这将给出“索引超出矩阵尺寸”错误。我预计代码中有很多地方会发生这种情况。

我想要做的是运行代码的 MATLAB 版本(不使用编码器),但是当它调整数组大小时让 MATLAB 生成错误或警告,因为我分配给边界之外的东西。 (我可以只使用 MEX 文件并查看错误弹出的位置,但这需要在我每次更改代码时使用 MATLAB Coder 重新构建整个 MEX 文件,这需要一段时间。)

有没有办法做到这一点? MATLAB 中是否有任何设置可以关闭“如果分配给越界索引则自动调整大小”,或者如果发生这种情况会发出警告?

【问题讨论】:

  • 有趣的问题。 “如果分配给越界索引,自动调整大小”是 Matlab 的基本功能。拦截这种行为似乎很棘手
  • 您是否只对 single-dimensionsingle-index 作业感兴趣?也就是说,您的代码可以包含x = zeros(a,1) x(a+1:a+10) = 1; 之类的内容吗?还是x = zeros(a,b) x(a+1,b) = 1;
  • 我几乎想说不,因为我觉得 Matlab 的一些核心工具箱依赖于这个功能......
  • 您可能会发现this question and answers 很有用。
  • 一个想法是隐藏subsasgn函数;但这行不通。来自documentation:“如果A 是一个基本类,那么对A 的索引引用调用内置的subsasgn 函数。它不调用subsasgn 方法您已经为该类重载。因此,如果 A 是类 double 的数组,并且您的 MATLAB 路径上有一个 @double/subsasgn 方法,则语句 A(I) = B 调用 MATLAB 内置的 subsasgn函数”。

标签: arrays matlab matlab-coder


【解决方案1】:

编辑:As of Matlab 2015b,Coder 现在可以选择运行时错误检查(来自 Matlab 发行说明):

在 R2015b 中,生成的独立库和可执行文件可以检测和报告运行时错误,例如越界数组索引。在 以前的版本,仅生成 MEX 检测并报告运行时 错误。

默认情况下,为 MEX 启用运行时错误检测。经过 默认情况下,独立库禁用运行时错误检测 和可执行文件。

启用独立的运行时错误检测 库和可执行文件:

在命令行,使用代码 配置属性RuntimeChecks

cfg = coder.config('lib'); % 要么 'dll' 或 'exe'

cfg.RuntimeChecks = true;

codegen -config cfg myfunction

使用 MATLAB Coder 应用程序,在项目构建设置中, 在调试选项卡上,选择生成运行时错误检查检查 盒子。

生成的库和可执行文件使用fprintf编写 错误消息到 stderr 并中止以终止应用程序。如果 fprintf 和 abort 不可用,您必须提供它们。错误 消息是英文的。

请参阅 Run-Time Error Detection and Reporting in Standalone C/C++ CodeGenerate Standalone Code That Detects and Reports Run-Time Errors

原答案: cmets 中关于声明从 double 子类化的类的答案,其中 subsref 方法被重载以禁止增长,这将是一种好方法。

另一种简单的方法是在整个代码中(在每个循环迭代中或在函数的底部)散布assert 命令,以断言大小没有增加超过分配的大小。

例如,如果您的代码格式为:

x = zeros(a,1)
x(a+1) = 1
... lots of other operations

if coder.target('MATLAB')
    assert(isequal(size(x), [a,1]), 'x has been indexed out of bounds')
end

如果分配了任何扩展数组的值,这将使断言失败。

为了使这更整洁,您甚至可以创建一个函数来检查您关心的所有变量,再次将coder.target if 语句包裹在它周围。然后你可以把它洒在你的代码中。

它不像重载 double 类那样优雅,但另一方面它根本不会给编译的代码增加任何开销。它也不会在溢出发生时准确地给你错误,但它会让你相信代码在各种情况下都能正常工作。

另一种让您对分配更有信心的方法是在可能合适的情况下对分配进行自己的边界检查。我在作业中看到的一个常见问题是这样的。我们有一个分配的数组,并且正在从另一个数组中复制数据并分配向量。例如,考虑以下情况:

t = char(zeros(5,7));              % Allocate a 5 by 7 char array
tempstring = 'hello to anyone';    % Here's a string we want to put into it.
t(1, 1:numel(tempstring)) = tempstring;  % A valid assignment in MATLAB

>> size(t)
ans =
5    15   

哦,哦,你关心的问题已经发生了:t 数组在赋值过程中自动调整大小,这在 MATLAB 中有效,但在 Coder 中创建的代码会导致 segfault 或 MEX 错误。另一种方法是使用end 函数的强大功能来保持赋值整洁(但被截断)。如果我们将赋值更改为:

t(1,1:min(end,numel(tempstring))) = tempstring(1:size(t, 2));

t 的大小将保持不变,但分配将被截断。使用end 允许在分配期间进行边界检查。在某些情况下,这可能是处理问题的好方法,并且会让您确信永远不会超出界限,但显然在某些情况下这是非常不可取的(并且不会在 MATLAB 中给您错误消息。) /p>

MATLAB 提供的另一个有用工具是编辑器本身。如果您在代码中使用%#codegen 标记,它将向编辑器的语法检查器发出信号以突出显示各种代码生成问题,包括您明显通过索引增加数组大小的地方。这不能捕捉所有情况,但它是一个很好的帮助。

最后一点。如问题中所述,Coder 生成的 MEX 文件会在分配时给您“索引超出矩阵维度”错误,并且会优雅地退出,甚至会告诉您发生错误的原始代码行。从 Coder 生成的 C 库没有这样好的行为或边界检查,并且会在没有诊断的情况下完全出现段错误。中间的答案是完全按照您正在做的事情,即将代码作为 MEX 运行。这对您的问题没有多大帮助(正如您所说,重建 MEX 可能需要时间),但对于我们这些为外部 C 代码的冷酷世界编写代码的人来说,能够运行 MEX 的中间测试以找到这些错误是救命稻草。

归根结底,这是 MATLAB 和 Coder 生成的 C 代码之间的行为差​​异,它可能是重大问题的根源。在我自己的代码中,正是出于这个原因,我对数组访问和增长非常小心。这是我希望看到 Coder 工具本身改进的一个领域,但是在编写针对 Coder 的 MATLAB 代码时,有一些方法需要非常小心。

【讨论】:

    猜你喜欢
    • 2011-04-15
    • 2018-10-26
    • 1970-01-01
    相关资源
    最近更新 更多