Complex case leads to free before allocation
- Dominant language
- Haskell
- Stars
- 6k
- Forks
- 187
- Avg merge
- 8d 22h
- Merged PRs (30d)
- 4
Description
I've run into a case where a String is freed before it's actually used, here's the code:
```clojure
(defn binary-partial [f x]
(fn [y]
(f x y)))
(doc lift-binary
"Lifts a binary function into an applicative structure.")
(defn lift-binary [f cx cy]
(sequence (fmap &(binary-partial binary-partial f) cx) cy))
(deftype (Box a) [of a])
(defmodule Box
(implements fmap fmap)
(defn fmap [f b]
(let [val (~f @(Box.of &b))]
(Box.init val)))
(implements fmap! fmap!)
(defn fmap! [f b]
(let [val (~f @(Box.of b))]
(Box.set-of! b val)))
(implements lift Box.init)
(implements sequence seq)
(defn seq [box-f box]
(let [f @(Box.of &box-f)
v @(Box.of &box)]
(Box.init (f v))))
(implements sequence! seq!)
(defn seq! [box-f box]
(let [f @(Box.of box-f)
v @(Box.of box)]
(Box.set-of! box (f v))))
)
```
Loading up this code and then running:
```clojure
鲤 (defn foo [] (Applicative.lift-binary (fn [x y] (String.append &x &y)) (Box.init @"foo") (Box.init @"bar")))
鲤 (foo)
Compiled to 'out/Untitled' (executable)
Untitled(3776,0x10c0a7dc0) malloc: *** error for object 0x7fc502c05830: pointer being freed was not allocated
Untitled(3776,0x10c0a7dc0) malloc: *** set a breakpoint in malloc_error_break to debug
[RUNTIME ERROR] '"out/Untitled"' exited with return value -6.
鲤
```
It emits a free before allocation here:
```c
void FP__Lambda_binary_MINUS_partial__String_String_String_12_env_delete(FP__Lambda_binary_MINUS_partial__String_String_String_12_env* p) {
Function_delete__String_String_String(p->f);
String_delete(p->x);
}
```
commenting out `String_delete(p->x);` makes it run fine:
```
./foo
(Box @"foobar")
```
I thought this might have to do with capturing vars, but it perhaps doesn't since this works fine:
```clojure
鲤 (defn foo [] (Applicative.lift-binary (fn [x y] (+ x y)) (Box.init 1) (Box.init 2)))
鲤 (foo)
Compiled to 'out/Untitled' (executable)
(Box 3)
=> 0
```
Seems specifically related to Strings or `String.append`as well, not references in general:
```clojure
鲤 (defn foo [] (Applicative.lift-binary (fn [x y] (add-ref &x &y)) (Box.init 1) (Box.init 2)))
鲤 (foo)
Compiled to 'out/Untitled' (executable)
(Box 3)
=> 0
鲤
```
Contributor guide
Research direction
Reproduce the String case and inspect the emitted FP__Lambda_binary_MINUS_partial__String_String_String_12_env_delete function, especially its String_delete call and the surrounding allocation and capture behavior. Compare it with the integer and add-ref examples. Done means the String example runs without an invalid free and produces (Box @"foobar").
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100