Java7中的"Solr/Lucene"漏洞有多严重?

66

显然,Java7在循环优化方面存在一些严重的bug:谷歌搜索.

从报告和错误描述中,我很难判断这个bug有多严重(除非你使用Solr或Lucene)。

我想知道:

  • 我的(任何)程序受影响的可能性有多大?
  • 这个bug足够确定吗,普通测试是否能够捕获它?

注意:我不能让我的程序用户使用-XX:-UseLoopPredicate来避免这个问题。

5个回答

78
任何热点错误的问题在于,你需要达到编译阈值(例如10000)才能遇到它:因此,如果你的单元测试是“琐碎的”,你可能不会发现它。例如,我们在lucene中发现了错误结果问题,因为这个特定的测试创建了20000个文档索引。在我们的测试中,我们随机化不同的接口(例如不同的目录实现)和索引参数等,并且测试仅有1%的失败率,当然可以使用相同的随机种子进行重现。我们还在每个测试创建的索引上运行checkindex,这些测试执行一些合理性测试以确保索引未损坏。对于我们找到的测试,如果你有一个特定的配置:例如RAMDirectory + PulsingCodec + 为字段存储有效载荷,那么在它达到编译阈值后,枚举过程中的帖子回报计算不正确,在这种情况下,术语的返回文档数!=存储的术语docFreq。我们有很多压力测试,重要的是要注意这个测试中的正常断言实际上是通过的,只是最后的checkindex部分失败了。这个大问题在于,lucene的增量索引基本上是通过将多个段合并成一个来工作的:因此,如果这些enums计算无效数据,则此无效数据将被“存储”到新合并的索引中:即损坏。
我认为这个错误比我们之前遇到的循环优化热点错误(例如符号翻转问题https://issues.apache.org/jira/browse/LUCENE-2975)要难以捉摸得多。在那种情况下,我们得到了古怪的负文档增量,这使得容易发现。我们也只需要手动展开一个方法来避免它。另一方面,最初我们对此唯一的“测试”是一个巨大的10GB http://www.pangaea.de/索引,因此将其缩小到这个错误是非常痛苦的。
在这种情况下,我花了很多时间(例如上周每晚)尝试手动展开/内联各种东西,试图创建一些解决方法,以便我们可以避免出现错误并且不会有可能创建出损坏的索引。我可以避免一些情况,但还有更多情况我无法避免... 我相信如果我们可以在我们的测试中触发这些内容,那么还有更多的情况存在...

3
直接从来源获取。+1 - aroth
3
顺便说一句,我看到了关于此事的各种评论:请注意捕捉到“错误结果”的测试设置是在6月30日提交的(https://issues.apache.org/jira/browse/LUCENE-3264),然而Java 7版本的时间戳实际上是6月27日(http://blog.thetaphi.de/2011/07/real-story-behind-java-7-ga-bugs.html),还有这个漏洞自5月13日以来一直存在于Oracle(http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7044738)。 - Robert Muir
2
感谢Robert提供详细的第一手答案。这真是一场灾难:我的当前项目使用了大量的加密和密码哈希。对数组进行数百万次迭代。我可以处理崩溃,但是错误加密文件或哈希可能只有在数年后才会显现出来,并带来可怕的后果。 - Carsten
Carsten: 我有同样的感觉。崩溃错误比悄无声息地出错要轻微得多。崩溃不会破坏你的Lucene索引。 - Robert Muir
“-XX:-UseLoopPredicate” 标志是否足以避免已知的损坏/崩溃情况?还是像一个 bug 中提到的那样,需要使用“-XX:LoopUnrollLimit=1”?或者是否存在已知问题,在任何启动选项中都无法修复(在 pre-u01 版本之前)? - gojomo

8

复制错误的方法很简单。打开Eclipse(我的版本是Indigo),然后进入帮助/搜索。输入一个搜索字符串,你会注意到Eclipse崩溃了。查看日志即可。

# Problematic frame:
# J  org.apache.lucene.analysis.PorterStemmer.stem([CII)Z
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# If you would like to submit a bug report, please visit:
#   http://bugreport.sun.com/bugreport/crash.jsp
#

---------------  T H R E A D  ---------------

Current thread (0x0000000007b79000):  JavaThread "Worker-46" [_thread_in_Java, id=264, stack(0x000000000f380000,0x000000000f480000)]

siginfo: ExceptionCode=0xc0000005, reading address 0x00000002f62bd80e

Registers:

这是描述的同一个罗伯特吗? - OscarRyz
3
不,Narayan描述了http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7070134。这是Java7中影响Lucene的一个错误(因为如果使用Porter Stemmer,您的JRE将崩溃),但可能是最不严重的,因为您只会遇到崩溃:没有索引损坏的可能性。 - Robert Muir

4
问题仍然存在,截至2012年12月2日 在Oracle JDK和openjdk中 java -version java version "1.7.0_09" Java(TM) SE Runtime Environment (build 1.7.0_09-b05) Java HotSpot(TM) 64-Bit Server VM (build 23.5-b02, mixed mode) java version "1.7.0_09-icedtea" OpenJDK Runtime Environment (fedora-2.3.3.fc17.1-x86_64) OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)
奇怪的是,任何一个选项 -XX:-UseLoopPredicate 或 -XX:LoopUnrollLimit=1 单独使用可以防止出现错误, 但是当它们一起使用时,JDK会失败 例如参见 https://bugzilla.redhat.com/show_bug.cgi?id=849279

1

现在已经两年过去了,我相信这个错误(或其变体)仍然存在于OSX上的1.7.0_25-b15版本中。

通过非常痛苦的试错,我已经确定使用Java 1.7与Solr 3.6.2和自动提交<maxTime>30000</maxTime>似乎会导致索引损坏。只有当我使用1.7和maxTime为30000时才会发生问题,如果我切换到Java 1.6,就没有问题了。如果我将maxTime降低到3000,也没有问题。

JVM不会崩溃,但它会导致RSolr在Ruby中死机,并出现以下堆栈跟踪:https://gist.github.com/armhold/6354416。在保存几百条记录后,它可靠地执行此操作。

鉴于这里涉及到许多层面(Ruby,Sunspot,Rsolr等),我不确定是否能将其简化为明确证明JVM错误的内容,但感觉就是这种情况。顺便提一下,我也尝试了JDK 1.7.0_04,它也出现了这个问题。


-7
据我所了解,这个bug只在服务器jvm中发现。如果你在客户端jvm上运行程序,那么就没问题了。如果你在服务器jvm上运行程序,那么问题的严重程度取决于程序本身。

6
这种说法是有误导性的:在我的机器上,使用Java 7时,“-client”没有任何作用,所有错误仍然会发生。请注意,这里的“-client”是指Java虚拟机启动参数中的一个选项。 - Robert Muir

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