Pointers haskell中的低级指针

Pointers haskell中的低级指针,pointers,haskell,ffi,Pointers,Haskell,Ffi,外部函数接口允许haskell使用C world。现在Haskell端允许使用Storable实例处理指针。例如,如果我在C世界中有一个整数数组,那么在haskell世界中这个数组的一个合理表示就是Ptr Int。现在假设我想翻译C表达式a[0]=a[0]+1。在haskell端实现这一点的唯一方法是查看int,然后返回加法的结果。这种方法的问题是,由此产生了一个临时值。(我不确定优化编译器是否总能避免这样做) 现在,大多数人可能认为这种影响是无害的,但想想指针对象包含一些敏感数据的情况。我在c

外部函数接口允许haskell使用C world。现在Haskell端允许使用
Storable
实例处理指针。例如,如果我在C世界中有一个整数数组,那么在haskell世界中这个数组的一个合理表示就是
Ptr Int
。现在假设我想翻译C表达式
a[0]=a[0]+1
。在haskell端实现这一点的唯一方法是查看int,然后返回加法的结果。这种方法的问题是,由此产生了一个临时值。(我不确定优化编译器是否总能避免这样做)

现在,大多数人可能认为这种影响是无害的,但想想指针对象包含一些敏感数据的情况。我在c端创建了这个指针,它总是保证其内容永远不会被移出内存(使用mlock系统调用)。现在,在haskell端查看结果不再保证敏感数据的安全性


那么,在哈斯克尔的世界里,什么是避免这种情况的最好方法呢?在haskell中,是否有其他人遇到过类似的低级指针操作问题。

我刚刚用代码构建了一个测试用例:

foo :: Ptr CInt -> IO ()
foo p = peek p >>= poke p ∘ (+1)
并使用GHC 7.6.3
-fllvm-O2-ddump asm
查看相关说明:

0x0000000000000061 <+33>:    mov    0x7(%r14),%rax
0x0000000000000065 <+37>:    incl   (%rax)
其结果是:

0x0000000000000000 <+0>:     addl   $0x1,(%rdi)
0x0000000000000000:addl$0x1,(%rdi)

综上所述,我坦率地承认,我不清楚您关心的是什么,因此我可能没有抓住您的重点,这样做是错误的。

您能否澄清,调出是如何有害的?如果你的意思是以后有人可以扫描磁盘来找到交换出来的值,那么其他C端的东西也是如此。一旦开始使用该“敏感值”,您就无法预测它将在何处结束—甚至堆栈、本地变量、任务状态中的寄存器……都可以移动到磁盘。我希望内存区域会因为性能原因而被锁定——例如,不要调出Java堆,因为调出很少访问的堆页会使GC变慢。您可以使用mlock系统调用锁定内存。因此,例如,如果您锁定上述阵列,则保证永远不会将其交换出去。像gnupg这样的程序使用libgcrypt将敏感信息锁定在内存中,这是出于安全原因。由于纯haskell值可以被垃圾收集器移动,因此我无法锁定它们,因此我必须使用在c端分配的安全内存(在我的例子中使用ForeignPtr)。mlock调用通常是void*或char*上的don。出于“安全”原因,我从未见过在int*上执行此操作。@jonke char*上的mlock与int*上的mlock相比安全性如何?假设我执行
a,没有任何东西可以保证总是这样。如果您必须控制寄存器中的内容和不在寄存器中的内容,或者控制堆中分配和潜在存储的内容和不在寄存器中的内容,那么,除了用某种语言生成或编写代码,使用匹配的编译器为您提供这些保证,然后进行外部绑定以访问Haskell中的功能之外,我没有一个令人信服的解决方案。这是你一直努力保护的加密密钥吗?而且,可能值得注意的是C并没有给出这样的承诺。您可能可以接受它将导致内存增量指令,但不能保证它不会首先移动到寄存器(也可能是上下文切换、存储在内存中并交换到硬盘驱动器)。如果这也与您有关,那么汇编或专用硬件似乎是您的主要选择。感谢您对C端非安全性的思考。我认为直接使用汇编是我保证它永远不会被替换掉的唯一方法?我希望我能提供一些抽象,用它来保证haskell方面也一样。
0x0000000000000000 <+0>:     addl   $0x1,(%rdi)