我该如何修复这个8年前的VBA 64位编译器错误?

58

因此这里有一个bug: 在一个64位的VBA宿主环境中(例如Access 365 64位或Excel 2016 64位),创建一个类模块SomeClass:

' this needs to be here to trigger the bug: 
Private Sub Class_Terminate()
End Sub

然后是一些模块 Test

Function ReturnFalse(o As Object) As Boolean
    ReturnFalse = False
End Function

Sub Test()
    Debug.Print ReturnFalse(New SomeClass)
    If ReturnFalse(New SomeClass) Then
        Debug.Print True
    Else
        Debug.Print False
    End If    
End Sub

现在,如果您使用的是32位VBA主机并在立即窗口中运行“Test”,则预期结果将显示出来:

False
False

然而,如果您使用的是64位 VBA 主机,则出现以下情况:

False
True

如果您删除或重命名 Class_Terminate() 子例程,则正确的输出将显示。

我已将此错误追踪到此最小示例。显然,问题似乎是使用临时对象 (new SomeClass 在这里) 破坏了 IF 条件的评估,使其看起来无论如何都是条件值为 True

好吧,这是个严重的错误,因为64位编译器很疯狂,所有的 IF 都会出问题。

所有的 IF?那 WHILE 呢?

While ReturnFalse(New SomeClass)
 Debug.Print "Oh no!"
Wend

是的,WHILE也有问题,因为它会在循环中打印“哦不!”。

这是一个大问题,我在所有版本的Office中都可以重现:

  • Microsoft® Access® für Microsoft 365 MSO (16.0.14026.20294) 64-Bit
  • Microsoft Access 2016 MSO (16.0.9029.2167) 64-Bit
  • Microsoft Access 2013 (15.0.4420.1017) MSO (15.0.4420.1017) 64-Bit

当然,在 Excel 中也有这个问题。

总结:我在拥有的所有Office版本中都发现了这个bug,从2013年开始,可能已经有至少8年了。

好的,之前有其他人受到这个bug的影响吗?是的:

去年的这篇帖子:

VBA takes wrong branch at If-statement - severe compiler bug?

excel.uservoice.com上的这篇帖子(显然是Microsoft的用户建议箱或者什么)来自2018年10月

https://excel.uservoice.com/forums/304921-excel-for-windows-desktop-application/suggestions/35735881-fix-inlined-member-calls-on-user-objects-on-64-bi

好的,那我们来报告一个bug吧。

https://answers.microsoft.com/en-us/msoffice/forum/msoffice_excel-mso_mac-mso_mac2016/how-do-i-report-vba-bugs/bb4e5dea-9996-4232-9b5b-7dd57f76736c

如果在与其他人测试后,代码出现了错误,而实际上不应该出错,则可以使用Excel中的Smile按钮直接向Microsoft报告此问题。

什么?

https://answers.microsoft.com/en-us/msoffice/forum/msoffice_excel-mso_win10-mso_2016/excel-2016-vba-bug/b799dfc2-7cef-417d-8a41-96661a360c43

  1. 打开Excel > 文件 > 反馈 > 发送不满意反馈
  2. 通过UserVoice - 点击以下链接查看其他人的反馈并提供反馈 - https://excel.uservoice.com/

这不是关于新图标颜色方案的建议。这是一个8年前的bug,使得具有宏的Access应用程序和Excel表格计算错误答案(还阻止了我们迁移到Office 64位,因为我们无法把代码取出)。

现在我有几个问题:

更新:交叉发布到

https://answers.microsoft.com/en-us/msoffice/forum/msoffice_excel-msoffice_custom-mso_2019/invalid-code-by-vba-64-bit-compiler/b91f984a-194c-4453-b8c5-02881afaf83b

更新2:

我有机会在Office 365 for Mac安装上尝试这段代码(其中Win64被定义为true),该bug在那里没有出现。所以现在只是电脑问题。

更新3:

帖子发布到了HN和The Register:

https://www.theregister.com/2021/08/19/64_bit_microsoft_vba_bug/ https://news.ycombinator.com/item?id=28188251

更新4:

我今天(2021-11-15)检查了一下Office 365,缺陷已经消失了!看起来有人注意到了。但我还不知道我今年收到的无数累积更新中哪些修复了该问题,也不知道其他版本的Office是否也已经被修复。


4
可能相关:https://dev59.com/Buk5XIcBkEYKwwoY3dX9 - GSerg
10
说实话,Office软件中存在着很多漏洞,而且没有可靠的方法来解决它们。我遇到了好几个问题(例如:在参数下使用记录集对绑定表单进行排序时出现的严重崩溃当一个对象引用一个已关闭的窗体并被垃圾收集器删除时发生的严重崩溃, 使用@@identity而不是scope_identity导致问题)。没有直截了当的方法来解决这些问题。 - Erik A
6
Uservoice已经停用。 - HackSlash
4
恭喜,这篇帖子被《The Register》(https://www.theregister.com/2021/08/19/64_bit_microsoft_vba_bug/)刊登了! - Mathieu Guindon
2
@NordicMainframe 刚刚检查了一下,在 Office 2019 版本 2110 Build 14527.20276 中也已经修复了!所以看起来他们已经修复了所有版本。 - Pᴇʜ
显示剩余5条评论
2个回答

30
Sub Test()
    Debug.Print ReturnFalse(New SomeClass)

    If ReturnFalse(New SomeClass) Then
        Debug.Print True
    Else
        Debug.Print False
    End If
    
    If True = ReturnFalse(New SomeClass) Then
        Debug.Print True
    Else
        Debug.Print False
    End If
End Sub

返回

False
True
False

所以,如果 If True = ReturnFalse(New SomeClass) Then,它就可以解决这个问题。

对于这个循环,这也可以解决它。

Do While True = ReturnFalse(New SomeClass)
    Debug.Print "Oh no!"
    Exit Do
Loop

强烈建议对上述解决方法的每个使用进行注释,以便将来没有人删除True =(例如,因为他在32位模式下开发并且甚至没有遇到此问题)。

' Don't remove `True =` due to a compiler bug in x64 the condition would always be true. 
' See https://dev59.com/TFEG5IYBdhLWcg3wUaI2
If True = ReturnFalse(New SomeClass) Then

即使存在这个bug,If ReturnFalse(New SomeClass) And False = True Then 也会返回 True

11
太糟糕了。虽然有绕过方法,但如果我在代码中看到那个True =的部分,我会立刻删除它,而不知道我刚刚引入了一个错误。这是一个开发领域的地雷。 - HackSlash
3
@HackSlash 是的,对每个 True = 的使用添加注释行并附带一个关于该 bug 的备注是非常推荐的。因此,一个解决方法可能是目前最接近解决这个问题了,直到微软内部修复这个 bug。 - Pᴇʜ
2
问题在于,我是否应该投资于一个没有明确的流程让用户报告错误、修复错误或者甚至获取一个未解决错误列表的开发平台。 - Nordic Mainframe
3
@NordicMainframe 自从 VBA 问世以来,你就可以问自己这个问题了。微软并没有投入太多精力在它身上,它一直很混乱、杂乱无章和不准确,开发停滞多年(他们只做必要的事情来维持其生命力)。也许你可以看看 Office-js,它可能会是 VBA 的某种替代品(或者不是)。• 即使我讨厌 VBA,有时可能没有其他选择,这取决于你正在开发什么。但是这完全是一个离题的讨论。我猜微软不会在合理的时间内修复这个问题。 - Pᴇʜ
2
我授予您1000个网络积分,因为您建议对绕过解决方案的每个使用进行注释。否则,甚至可能会在6个月后被代码作者遗忘并将其删除。 - Drew
显示剩余3条评论

1
你已经做得很好了,除非你想直接/单独联系技术开发人员并冒着被列入烦人列表的风险,否则你无法做更多事情,这可能并不能提高实际修复的机会。
Uservoice正面临废弃,但产品开发团队仍然注意并使用它,包括2021年的现在。
VBA不是可编程性开发的当前重点,因此我对它能否进入优先级队列并没有太多信心。

6
“VBA不是当前可编程性开发的重点” - 对于微软来说应该是这样:VBA可能是唯一使支付业务客户仍然依赖MS Office的东西。但是,VBA的过时会让“酷孩子们”对其学习失去兴趣,于是他们转而学习Python或JS,这些语言无法做到VBA所能做的事情- 因此他们转而使用Google表格和Firebase,而非Excel和Access。 - Dai
我并不是说它不应该成为重点,只是观察到它目前还不是。实际上,我同意你的很多观点。希望当OfficeScripts进入桌面版Excel时,它会带来VBA集成,以帮助企业用户群体过渡(我认为这个群体在遥测数据中被低估了)。与此同时,基于Web的Excel正在快速改进,但仍远远落后于桌面版Excel,所以正如你所说,与启用VBA的桌面版Excel相比,优势比较薄弱。VBA在过去20年中几乎没有什么变化,从某些方面来说,这本身就是一个非常有用的特性! - ed2

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