如何使R崩溃?

70

有没有一种简单的方法来触发R中的崩溃?这仅用于测试目的,以查看某个后台使用R的程序在崩溃情况下的反应,并帮助确定某些罕见问题是否由崩溃引起。


3
我曾尝试过“options(expressions=300000)”然后运行一个无限递归,但是R写得足够好,不会崩溃 :) - Szabolcs
1
这可能取决于您的平台。想要添加这个信息吗? - Stephan Kolassa
1
@StephanKolassa 我使用的是OS X系统,但为了日后读者的方便,我更愿意将问题保持通用性。针对任何平台的答案都可以接受。 - Szabolcs
5
请问给我下投票的人能否解释一下他们认为这个问题有什么问题?请@DirkEddelbuettel保持宽容,因为并非每个人都能轻易理解解决方案。提供一个链接到手册并不能清楚地说明如何做到这一点。 - Szabolcs
4
一定要崩溃吗?你可以选择以非零状态退出,而不是崩溃吗? - Joshua Ulrich
6个回答

53

最简单的方法是调用C代码。 C提供了一个标准函数abort()[1],可以实现您想要的功能。您需要调用:.Call("abort")

正如@Phillip所指出的,您可能需要通过以下方式加载libc

  • 在 Linux 上,在发出 .Call("abort") 命令之前,需要使用 dyn.load("/lib/x86_64-linux-gnu/libc.so.6")。当然,路径会因您的系统而异。

  • 在 OS X 上,需要使用 dyn.load("/usr/lib/libc.dylib")

  • 在 Windows 上(我只在 XP 上测试过,因为我无法获得更新版本),您需要安装Rtools[2]。安装后,应加载dyn.load("C:/.../Rtools/bin/cygwin1.dll")


1
当从命令行或使用官方GUI运行R时,我会收到Error in .Call("abort") : C symbol name "abort" not in load table的错误提示。而在使用RStudio时,则会崩溃。 - Szabolcs
2
你必须在之前加载libc:dyn.load("/lib/x86_64-linux-gnu/libc.so.6")。路径在你的系统上可能会有所不同,使用 locate libc.so.6 来查找它。 - Phillip
3
crash 软件包也调用了 abort 函数,至少就我所见,但我远不如您经验丰富! - lord.garbage
1
所以它永远不会进入CRAN :) - Dirk Eddelbuettel
3
您可能是指Rtools软件包,因为R从未支持Cygwin。Joshua没有直接提到的是,您的答案这样并不完全可移植。但是,是的,abort()是关键。 - Dirk Eddelbuettel
显示剩余4条评论

49

在 GitHub 上有一个完整的软件包专门用于此项任务:

crash

这是一个 R 软件包,旨在故意崩溃 R 会话。警告:仅供测试使用。

如何从 GitHub 安装软件包已在其他问题中介绍。


21
它调用了 abort,很好。 - lord.garbage
8
假设您已经安装了所需的工具(*nix, Windows),从github安装这个软件包的一种方法是:library(devtools); install_github('jdanielnd/crash')。然后您可以使用 library(crash); crash() 来使您的 R 会话崩溃。 - Joshua Ulrich

17

我要从@Spacedman那里偷个主意,但我会通过复制他的Twitter动态来全面认可他的概念:

一步骤导致#rstats出现故障: options(device=function(){});plot(1) 报告危险,将使您的R会话崩溃。 — Barry Rowlingson (@geospacedman) 2014年7月16日


注:Segfault是指由于编程错误而导致程序崩溃,通常是由于“段错误(Segmentation fault)”引起的。 #rstats是一个在推特中表示R统计软件标签的标识符。

1
这很有用,因为它不会立即退出,而是呈现一个提示,并询问下一步该做什么。这是一种不同的行为方式,这也可能是我自己的项目出了问题的原因... - Szabolcs

15

正如在评论中提到您的问题一样,最简单的方法是调用系统函数abort()。一种在一行中执行此操作的方法是

R> Rcpp::cppFunction('int crashMe(int ignored) { ::abort(); }'); 
R> crashMe(123)
Aborted (core dumped)
$ 

或者您可以使用内联包:

R> library(inline)
R> crashMe <- cfunction(body="::abort();")
R> crashMe()
Aborted (core dumped)
$ 

当然,您也可以在Rcpp或inline之外完成此操作,但那样的话就需要处理编译、链接和加载方面因系统而异的问题。


以上代码片段在低内存环境下第一行之后会导致崩溃。注意风险。 - Deer Hunter
1
@DeerHunter。我也注意到大概每五次尝试中有一次会出现这种情况。可能是某个地方出了问题。不过,R并不是为abort()而设计的。 - Dirk Eddelbuettel

6

由于我的C++水平不够,所以我将使用普通的C语言:

创建一个名为segv.c的C文件:

#include <signal.h>
void crashme(){raise(SIGSEGV);}

在命令行编译它(Windows用户需要自行解决):

R CMD SHLIB segv.c

在R中,加载并运行:
dyn.load("segv.so") # or possibly .dll for Windows users
.C("crashme")

产生段错误:

> .C("crashme")

 *** caught segfault ***
address 0x1d9e, cause 'unknown'

Traceback:
 1: .C("crashme")

Possible actions:
1: abort (with core dump, if enabled)
2: normal R exit
3: exit R without saving workspace
4: exit R saving workspace
Selection: 1
aborting ...
Segmentation fault

这与Thomas在图形系统错误报告中提到的行为相同,我已经提交了该报告,也许有一天会得到修复。然而,这两行代码始终会引发一个段错误...

也许Dirk可以将其压缩成一行Rcpp代码吗?


重新阅读我的帖子,内联使用完全是C语言--我在C模式下使用cfunction() i。你可以在这里做同样的事情,使你的答案更容易/更简洁/不那么依赖于操作系统。Rcpp的使用仅仅是为了部署更简单的构建机制,本质上没有C++。 - Dirk Eddelbuettel
3
spacedman <- inline::cfunction(body="raise(SIGSEGV);", include="#include <signal.h>") -- 这个答案没有使用任何C++。 - Dirk Eddelbuettel
spacedman <- Rcpp::cppFunction("void crashme() { ::raise(SIGSEGV); }", includes="#include <signal.h>") -- 就是这样。 - Dirk Eddelbuettel

0
如果你想让你的R崩溃,请尝试这个。
lapply("", function(x) eval(sys.call(1)))

(在运行之前保存所有内容,因为这会立即导致“R会话中止”)

编辑:这对我在Windows 10上有效。


至少在macOS上,似乎有一些保护措施来防止堆栈溢出。 这会导致“错误:C堆栈使用量7971744接近限制”,但不会崩溃。 - Szabolcs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接