agrafix / agrafix/superrecord

!!! `project` causes memory inconsistencies

未關閉
#38 10 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
主要語言
Haskell
星號
83
分支
16
PR 合併指標
30 天內沒有已合併 PR

描述

`project` (and potentially also `inject`, we haven’t verified`, will cause undefined behavior, which we noticed & verified in a production system.

*The bug only appears with optimizations enabled (only tested `-O2`), not in ghci*

I don’t have a minimal repro (yet), but I can describe what we did:

There was one function which loaded some data in `IO`, constructed a ist of `rec`, then before returning used `project` to reduce unnecessary fields in every list element:

```haskell
loadData :: IO (Record '[ "foo" := Text ])
loadData = do
listOfRes <-
pure
$ map
(project @'["foo" := Text, "bar" := Int] @'["foo" := Text])
listOfRes
```

And another function that pulled *a subset* of fields from the record, like this:

```haskell
requestBody = do
dat <- loadData

let mapDat d = (Json.object [
("foo", get #foo d)
])

pure $ Json.Array (map mapDat dat)
```

Let’s say the final data was

```haskell
[
{ foo = "xx" },
{ foo = "yy" },
{ foo = "zz" },
]
```

Then what would be actually returned was (!!):

```haskell
[
{ foo = "xx" },
{ foo = "xx" },
{ foo = "xx" },
]
```

now, if you rewrote the function to deeply evaluate the `project`ed record:

```haskell
loadData :: IO (Record '[ "foo" := Text ])
loadData = do
listOfRes <-

print listOfRes -- <- deeply evaluate the record by printing it

pure
$ map
(project @'["foo" := Text, "bar" := Int] @'["foo" := Text])
listOfRes
```

It would again return

```haskell
[
{ foo = "xx" },
{ foo = "yy" },
{ foo = "zz" },
]
```

When we rewrote the original function to construct a new record instead of `project`ing:

```haskell
loadData :: IO (Record '[ "foo" := Text ])
loadData = do
listOfRes <-
pure
$ map
(\res -> rcons #foo (get #foo res) rnil)
listOfRes
```

The problem went away.

貢獻指南

這個儲存庫沒有索引到貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。