C# 程序似乎正在修改标记为只读的参数

C# program seems to be modifying a parameter marked as readonly

提问人:Nathaniel Aquino 提问时间:2/5/2022 最后编辑:Nathaniel Aquino 更新时间:2/5/2022 访问量:113

问:

我有一个名为 ARCMF 的函数,它应该为每组相同的输入返回相同的伪随机输出,并且它们都通过使用关键字通过只读引用传递。但是,当我尝试运行此函数两次时,第一个和第二个结果永远不会相等(但每次重新启动程序时都是相等的)。经过广泛的调试,似乎有问题的变量被修改了。我尝试将其设置为只读,但它仍然以某种方式被修改。这让我难住了好几个小时......statekeysin

我所有的代码都在这个存储库中。

这是有问题的变量(从现在开始,我将称为 IV),我在调试期间将其放在监视窗口中,并将其传递到一个名为 ARCMF 的函数中......

var arc = new ARC128(key, iv);
var mf0 = arc.ARCMF(iv, arc.Schedule(key, iv, 1));
arc.PrintArray(mf0, "Main Function Iteration 0 Results");
var mf1 = arc.ARCMF(iv, arc.Schedule(key, iv, 1));
arc.PrintArray(mf1, "Main Function Iteration 1 Results");
c.WriteLine(Enumerable.SequenceEqual(mf0, mf1) ? "MF Gen success." : "MF Gen fail.");

internal byte[] ARCMF(in byte[] state, in byte[][] keys)
        {
            var output = state;
            for (int i = 0; i < 9; i++)
            {
                ARCLT.Permutate(ref output, ARCLT.MBLTv1, i);
                ARCBMGR(ref output);
                ARCLT.Permutate(ref output, ARCLT.SBLTv1, i);
                output = OTPArray(output, keys[i]);
            }
            return output; 
        }

IV 的修改专门发生在ARCLT.Permutate(ref output, ARCLT.MBLTv1, i);

为了帮助展示这一点,这里有一些屏幕截图。

之前(我不能嵌入图像:()之后

函数本身如下所示:

internal static void Permutate(ref byte[] io, in byte[] table, int seed =  1)
        {
            seed = (seed == 0) ? 1 : seed;
            for (int i = 0; i <= io.Length - 1; i++)
                io[i] = (byte)((io[i] * seed % 256) ^ table[i]);
        }

对于那些好奇的人,以下是该程序输出的内容:

Main Function Iteration 0 Results: 785B62AFE54AB7FA7A4EE63D67A311A8
Main Function Iteration 1 Results: F47B4EF85524B92B6F210F9EDCD5786
MF Gen fail.

我该怎么办?

更新 1:将 Permutationate 函数更改为

internal static byte[] Permutate(byte[] io, in byte[] table, int seed =  1)
        {
            var o = io;
            seed = (seed == 0) ? 1 : seed;
            for (int i = 0; i <= io.Length - 1; i++)
                o[i] = (byte)((o[i] * seed % 256) ^ table[i]);
            return o;
        }

没有区别。

C# .NET Visual-Studio 加密 引用

评论

0赞 Alexei Levenkov 2/5/2022
我没有看到任何东西(无论如何都不太可能改变问题中的任何内容)......我很确定你对“方法不能分配值或修改参数”意味着什么的期望是不现实的。您能否编辑问题以显示您认为不应该起作用的最小可重现代码示例?我想你想作为一定行不通的代码的例子。readonlyvoid X(in byte[] v){v[0]=42;}
0赞 Daniel A. White 2/5/2022
参数修饰符不能防止内部可变性

答:

1赞 Rivo R. 2/5/2022 #1

因为你正在使用关键字。 它允许子方法修改参数在内存中的值。 在本例中,每次使用以下命令设置值时,参数(字节结构类型化)都会被修改两次:refoutput

io[i] = (byte)((io[i] * seed % 256) ^ table[i]);.

评论

0赞 Nathaniel Aquino 2/5/2022
更改函数无济于事。internal static byte[] Permutate(byte[] io, in byte[] table, int seed = 1) { var o = io; seed = (seed == 0) ? 1 : seed; for (int i = 0; i <= io.Length - 1; i++) o[i] = (byte)((o[i] * seed % 256) ^ table[i]); return o; }
0赞 Train 2/5/2022 #2

你把它和 Ref 关键字混合在一起。Ref 将修改这些值。

复制它并使用该副本。

var output = new byte[state.Length];
state.CopyTo(output, 0);

or 

var output = state.ToArray();

评论

0赞 Nathaniel Aquino 2/5/2022
谢谢!这奏效了,尽管我有点困惑为什么......是因为设置在引用上复制吗?outputstate
1赞 Amit 2/5/2022
这是因为 new 它在内存堆中创建了一个由变量 “output” 重新保护的新对象,并且对这个新对象进行了任何更改,变量 “state” 引用的旧对象保持不变。您之前的代码未按预期工作,因为调用函数中的变量和“Permutate”函数仍在内存中引用同一对象。推荐阅读 jonskeet.uk/csharp/references.html 和其中的链接
0赞 Nathaniel Aquino 2/5/2022
威尔科,这是有道理的。请务必阅读那篇文章。