在Malbolge编译器/解释器中,三次操作、右转操作和疯狂操作都不能正常工作,并造成分段错误。
在看到关于编码挑战和Code的惊人答案之后,我决定开始用Malbolge编程,并学习用一种硬编程语言编程。
当我试图输出一个固定的字符时,我注意到*和p (在规范化的Malbolge中)在我尝试使用它们的大部分时间里都会抛出分段错误。
我试图使用互联网,并查找字符串(在谷歌上) "'Malbolge‘疯狂的操作’分段故障‘和’‘Malbolge’旋转右‘分段故障’“。我还尝试在不同的上下文中使用这些命令,发现如果没有输入(这不是我想要的),它就能工作。
我正在使用由在线翻译托管的tio.run,或者在网上试用它。
我尝试使用的代码:
归一化Malbolge:/*<
马尔博格:u&a
归一化Malbolge:/p*<v
马尔博格:u=%`M
归一化Malbolge:/pp<v
马尔博格:u=<`M
我预计u&a、u=%`M和u=<`M的输出不会引发任何错误,但实际输出是分段错误。
准确的错误:/srv/wrappers/malbolge: line 3: 21992 Segmentation fault (core dumped) /opt/malbolge/malbolge .code.tio < .input.tio,其中21992可以是任意数字(最有可能是几千到万)
发布于 2019-08-14 02:54:41
为了诊断这里发生了什么,我一直在通过调试器中的Malbolge解释器。我想说的是“恭喜,您在Malbolge解释器中发现了一个bug”,但考虑到规范和解释器在其他方面不匹配(通常将权威版本视为解释器),而且这就是Malbolge,因为我知道这是有意的行为。(好吧,它可能并不是真正想要的行为,但也没有将许多其他特性作为重要的编程技术来处理。)
Malbolge将所有内容存储在一个大数组中,包括代码和数据。命令的目的是在运行后修改( Malbolge术语中的“encrypt”)本身,但是解释器最终没有完全正确地实现它:它实际上所做的是运行一个命令,然后查看代码指针指向的地址并对其进行加密。这就是为什么跳跃会在跳转目标之前加密指令,而不是跳转指令本身。
如果运行的命令超出了33到126的范围,那么命令就不会运行(实际上,在我所拥有的Malbolge解释器版本中,代码和数据指针也没有增加,这似乎不可避免地会导致无限循环;也许还有其他版本可以解决这个问题)。这是一个重要的检查,因为加密例程只是通过索引到查找表来工作;33到126范围之外的值最终将读取数组之前或之后的一些任意字节的内存。
不幸的是,由于代码和数据存储在一个大数组中,一个命令在运行时可能会修改自己:在运行之前它可能在33到126之间(从而导致安全检查成功),但是在运行之后,它超出了范围,然后加密将完成查找表的超出范围的索引。Malbolge解释器是用C编写的,它具有未定义的超出范围的读取行为,但是对于超出范围的很长一段时间的读取,分段错误很可能(但不是保证)行为。
让我们看看代码u&a发生了什么
Command A C D memory
start 0 0 0 117, 38, 97, 29432, 98, 29431, 98, 29432, 97, ...
/ input 0 0 117, 38, 97, 29432, 98, 29431, 98, 29432, 97, ...
encrypt input 1 1 111, 38, 97, 29432, 98, 29431, 98, 29432, 97, ...
* 39378 1 1 111, 39378, 97, 29432, 98, 29431, 98, 29432, 97, ...
encrypt 39378 2 2 111, ???, 97, 29432, 98, 29431, 98, 29432, 97, ...如您所见,您实际上并不是在旋转加载到A中的输入;旋转操作从D (而不是从A)指向的地址读取,因此您正在旋转38 (内存位置1中的*命令的内存中表示形式)以生成39378。该值被存储到A和内存位置1中。不幸的是,内存位置1是当前正在执行的命令,因此当需要对其进行加密时,解释器会对查找表执行超出界限的读取(试图在一个表中查找对应于39378的位置,该位置仅涵盖33到126之间的范围),如果幸运的话,这将产生一个分段错误。
这种行为在“简单”Malbolge程序中很可能发生,因为C和D从相同的值开始,并且以相同的速度增长。如果希望旋转指令影响当前运行的命令以外的其他内容,则必须以某种方式对它们进行反同步。最简单的方法通常是使用j命令(注意:使用结果数据指针可能不是特别容易,但至少它可能在代码指针之外的其他地方)。
顺便说一句,实际上旋转用户输入比在你给出的示例程序中花费更多的精力。您必须首先将其存储到内存中,唯一能够根据A值编写内存的操作是p,它要求所讨论的单元格已经有一个适当的值(为了避免丢失信息,这需要通过Malbolge的算术生成的值为29524,因为它不能作为原始程序的一部分输入,即使这样,您也会以输入值中的1 trits替换0 trits )。然后,您必须将数据指针发送回写入输入的单元格,这样您就可以在它上运行*来旋转它。
https://stackoverflow.com/questions/57484219
复制相似问题