Carp/core
Scott Olsen 892a972660
Pointer: Add utility functions (#1012)
* Pointer: Add utility functions

This commit adds a few more utility functions to `Pointer.carp`.

- Pointer.set-unsafe: Sets the value of a pointer to some arbitrary Carp
  value, without type checking. Users need to ensure this operation is
  safe.
- Pointer.set: Sets the value of a pointer to a value of type t to a
  value that has the same type.
- Pointer.cast: Casts a pointer to a value of type t to a pointer to a
  value of type `a`--the argument passed is ignored, it is only used to
  determine the type to cast to.
- Pointer.leak: Copies a Carp reference to a new pointer to the same
  value. This creates a leak since Carp will not automatically clean up
  this memory.
- Pointer.free: Frees a pointer p. Users need to ensure calls to this
  function are safe and do not produce errors like a double free.
  Intended for use with leak.

Here's an example of some of these functions in action:

```
(defn foo []
  (let-do [p (Pointer.leak "leaky")] ;; create a new pointer
    (ignore (Pointer.set p @"foo")) ;; set the pointer to "foo"
    (println* (Pointer.to-value p)) ;; convert to a Carp val to print
    (Pointer.free p) ;; finally, free it.
    0))
(foo)
=> Compiled to 'out/Untitled' (executable)
foo
0
```

And the C of interest:

```
int foo() {
    int _35;
    /* let */ {
        static String _6 = "leaky";
        String *_6_ref = &_6;
        String* _7 = Pointer_leak__String(_6_ref);
        String* p = _7;
        /* let */ {
            static String _15 = "foo";
            String *_15_ref = &_15;
            String _16 = String_copy(_15_ref);
            String* _17 = Pointer_set__String(p, _16);
            String* _ = _17;
            /* () */
        }
        String _26 = Pointer_to_MINUS_value__String(p);
        String _27 = StringCopy_str(_26);
        String* _28 = &_27; // ref
        IO_println(_28);
        Pointer_free__String(p);
        int _34 = 0;
        _35 = _34;
        String_delete(_27);
    }
    return _35;
}
```

As mentioned, and as w/ other Pointer functions users need to ensure the
safety of these operations themselves. For example, calling `free` on
`p` twice in the example above produces the expected double free:

```
(defn foo []
  (let-do [p (Pointer.leak "leaky")] ;; create a new pointer
    (ignore (Pointer.set p @"foo")) ;; set the pointer to "foo"
    (println* (Pointer.to-value p)) ;; convert to a Carp val to print
    (Pointer.free p) ;; finally, free it.
    (Pointer.free p) ;; !Double free!
    0))
(foo)
Compiled to 'out/Untitled' (executable)
foo
Untitled(38328,0x10d9a1dc0) malloc: *** error for object 0x7feb86c01790:
pointer being freed was not allocated
Untitled(38328,0x10d9a1dc0) malloc: *** set a breakpoint in
malloc_error_break to debug
[RUNTIME ERROR] '"out/Untitled"' exited with return value -6.
```

Still, these should come in handy in rare cases in which users need to
circumvent the type checker or borrow checker.

diff --git a/core/Pointer.carp b/core/Pointer.carp
index a662c636..4f29d587 100644
--- a/core/Pointer.carp
+++ b/core/Pointer.carp
@@ -20,6 +20,29 @@ The user will have to ensure themselves that this is a safe operation.")
   (doc from-long "converts a long integer to a pointer.")
   (deftemplate from-long (Fn [Long] (Ptr p)) "$p* $NAME(Long p)" " $DECL { return ($p*)p; }")

+  (doc set-unsafe
+    "Sets the value of a pointer."
+    "The user will have to ensure this operation is safe.")
+  (deftemplate set-unsafe (Fn [(Ptr p) (Ref a b)] (Ptr p)) "$p* $NAME($p* p, void* a)" "$DECL { *p = *($p*)a; return p;}")
+
+  (doc cast
+     "Cast a pointer to type p to a pointer to type a."
+     "The value of the `a` argument is ignored.")
+  (deftemplate cast (Fn [(Ptr p) a] (Ptr a)) "$a* $NAME($p* p, $a a)" "$DECL { *($a*)p = CARP_MALLOC(sizeof($a)); return ($a*)p;}")
+
+  (doc leak
+     "Allocate a new pointer that's a copy of the value of `Ref`"
+     "The Carp borrow checker won't delete this pointer. You will need to delete it manually by calling `Pointer.free`.")
+  (deftemplate leak (Fn [(Ref a b)] (Ptr a)) "$a* $NAME($a* r)" "$DECL { void *leak = CARP_MALLOC(sizeof($a)); memcpy(leak, r, sizeof($a)); return ($a*)leak;}")
+
+  (doc free
+     "Free a pointer."
+     "Users need to manually verify that this operation is safe.")
+  (deftemplate free (Fn [(Ptr p)] Unit) "void $NAME($p* p)" "$DECL {CARP_FREE(p);}")
+
+  (doc set "Sets the value of a pointer.")
+  (deftemplate set (Fn [(Ptr p) p] (Ptr p)) "$p* $NAME($p* p, $p a)" "$DECL { *p = a; return p;}")
+
   (defn inc [a] (Pointer.add a 1l))
   (implements inc Pointer.inc)
   (defn dec [a] (Pointer.sub a 1l))

* Pointer: Change signature of leak to make it more sensible

Instead of `leak` copying a previously allocated value, it now takes
(unmanaged) ownership of a fresh value and allocates. This makes more
sense semantically, as we're just instantiating a new pointer that won't
be managed by Carp and will leak unless freed explicitly.

Thanks to @TimDeve for the suggestion!

* Pointer: Improve apis on set and alloc

- Rename set-unsafe to align w/ naming conventions
  Most unsafe functions are prefixed with `unsafe`, not suffixed.
- Rename leak to `unsafe-alloc` to better convey its semantics (leak
  also already exists as `Unsafe.leak`.
- Remove `cast` since its use is covered by `Unsafe.coerce`.

Thanks to TimDeve and hellerve for the suggestions!

* Pointer: Make unsafe-set take ownership

* Pointer: Correctly cast in unsafe-alloc; add unsafe-realloc

Here's a short illustration of why we need `realloc` even though we
already have `Pointer.add`:

```
(defn foo []
  (let-do [p (Pointer.unsafe-alloc 2)]
    (set! p (Pointer.add p (Pointer.width (Pointer.unsafe-alloc @"foo"))))
    (ignore (Pointer.unsafe-set p @"foo"))
    (println* (Pointer.to-value (the (Ptr String) (Unsafe.coerce p))))
    (Pointer.free p)
    0))
```

This function seems fine at first glance, but since `add` returns a new
pointer, `p` is reset to the new pointer, the reference to the original
is lost, and `free` is called on a value that was never actually
allocated since `add` does not malloc.

Using unsafe-realloc, we can avoid the additional allocation:

```
(defn foo []
  (let-do [p (Pointer.unsafe-alloc 2)]
    (Pointer.unsafe-realloc p @"foo")
    (ignore (Pointer.unsafe-set p @"foo"))
    (println* (Pointer.to-value (the (Ptr String) (Unsafe.coerce p))))
    (Pointer.free p)
    0))
```

The allocation is what we care about here. One still needs to use
`Unsafe.coerce` since as far as the Carp compiler is concerned, `p` is
still a (Ptr Int) even though the corresponding c has cast it silently
to a `String` in order to reallocate.

* Pointer: Change signature of unsafe-set to align with set!

* Pointer: Change signature of `set` to align with `set!`

* Pointer: Remove unsafe-realloc

* Pointer: Update docs for unsafe-alloc and free

* System: Remove System.free

Pointer.free serves a similar function, and is more restrictive, so
we'll remove System.free. One can use `delete` or cast to a pointer and
free that way.See PR #1012 for further discussion.
2020-11-30 07:06:04 +01:00
..
Array.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
ArrayExt.carp core: update dcostring for range-or-default 2020-05-24 12:51:11 +02:00
Bench.carp core: move elapsed_time into bench module 2020-01-27 16:56:22 +01:00
Binary.carp Move Byte Order type outside of the Binary module 2020-03-20 19:02:55 -04:00
Bool.carp core: add Bool.zero 2020-06-23 12:26:53 +02:00
Byte.carp core: make bit-* interfaces 2020-07-08 21:11:28 +02:00
carp_bench.h Replace return by pure. (#1009) 2020-11-24 06:09:15 +01:00
carp_binary.h all: various long fixes 2020-04-23 21:50:30 +02:00
carp_bool.h core: do not have short functions on single lines 2019-10-30 11:07:32 +01:00
carp_byte.h core: fix #688 by using the correct formatting macros\n\n(and pray that windows does c99) 2020-02-21 12:28:34 +01:00
carp_char.h Merge 2020-05-11 16:10:35 +02:00
carp_debug.h Preserve includes order in generated output. 2019-10-03 00:23:27 +02:00
carp_double.h Long type to ensure longs are actually 64 bits. 2020-04-22 10:40:06 +02:00
carp_float.h core: do not have short functions on single lines 2019-10-30 11:07:32 +01:00
carp_int.h core: do not have short functions on single lines 2019-10-30 11:07:32 +01:00
carp_io.h Hopefully portable and simple get-line. 2020-05-11 16:08:40 +02:00
carp_long.h Detect __builtin_x_overflow() based on __GNUC__ macro. 2020-05-23 19:03:07 +02:00
carp_memory.h all: various long fixes 2020-04-23 21:50:30 +02:00
carp_pattern.h Remove braces so different clang-formats output the same. 2020-05-30 09:32:50 +02:00
carp_safe_int.h Detect __builtin_x_overflow() based on __GNUC__ macro. 2020-05-23 19:03:07 +02:00
carp_stdbool.h core: remove stdbool dependency 2018-11-17 15:42:36 +01:00
carp_stdint.h Use CARP_MALLOC throughout carp_stdint (#1024) 2020-11-27 10:19:32 +01:00
carp_string.h Fix crash reported in #923. 2020-11-16 23:46:16 +01:00
carp_system.h core: use static array for args 2020-08-24 11:20:52 +02:00
carp_utf8.h Unicode fixes (#994) 2020-11-22 06:45:26 +01:00
Char.carp Add some more calls to implement to make tests pass 2020-05-10 13:32:22 -04:00
Collection.carp Add some more calls to implement to make tests pass 2020-05-10 13:32:22 -04:00
Color.carp Add some more calls to implement to make tests pass 2020-05-10 13:32:22 -04:00
Control.carp Fix signature of Control.iterate-until 2020-05-20 23:40:46 -04:00
ControlMacros.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Core.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
core.h Add support for cross-compilation. 2020-10-10 20:01:18 +02:00
Debug.carp core: fix Debug.trace for new evaluator 2020-05-16 12:46:05 +02:00
Double.carp Add remaining implements declarations 2020-05-10 22:53:35 -04:00
Dynamic.carp Implement load-stack. 2020-06-28 19:53:43 +02:00
Filepath.carp Return reference from unsafe-first/unsafe-last (#1027) 2020-11-27 10:19:06 +01:00
Float.carp core: add implements for FloatRef comparators 2020-05-12 22:45:29 +02:00
Format.carp Implement private 2020-06-19 10:30:55 -04:00
Function.carp Adds Function.unsafe-ptr & Function.unsafe-env-ptr (#1026) 2020-11-27 10:17:29 +01:00
Generics.carp core: fix typo in docs for Generis.approx 2020-05-13 16:45:11 +02:00
Gensym.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Geometry.carp Generics no longer propagated. 2019-09-09 22:08:50 +02:00
GLFW.carp Added some of GLFW constants 2020-06-18 23:19:31 +02:00
Heap.carp Fix all nth usage 2019-10-31 06:23:23 -03:00
Int.carp core: make bit-* interfaces 2020-07-08 21:11:28 +02:00
Interfaces.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Introspect.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
IO.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
List.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Long.carp Add support for cross-compilation. 2020-10-10 20:01:18 +02:00
Macros.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Map.carp Add some more calls to implement to make tests pass 2020-05-10 13:32:22 -04:00
Maybe.carp core: make NULL Ptr a instead of a 2020-05-18 23:21:16 +02:00
Opaque.carp Update Opaque docs; fix typos 2020-06-18 09:57:28 -04:00
OpenGL.carp Add header/lib for OpenGL on each platform. 2020-06-29 11:57:06 +02:00
Pattern.carp Return reference from unsafe-first/unsafe-last (#1027) 2020-11-27 10:19:06 +01:00
Phantom.carp core: add docs for phantom 2020-06-17 19:06:49 +02:00
Platform.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Pointer.carp Pointer: Add utility functions (#1012) 2020-11-30 07:06:04 +01:00
Project.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
Random.carp core: call Random.reseed at program start 2020-10-14 15:31:26 +02:00
Result.carp Add some more calls to implement to make tests pass 2020-05-10 13:32:22 -04:00
SafeInt.carp Added --compile-fast to compile with tcc. 2020-05-21 20:04:54 +02:00
SDL_gfx.carp Refactored flags handling (add-pkg). 2019-06-17 09:02:34 +02:00
SDL_image.carp Add support for cross-compilation. 2020-10-10 20:01:18 +02:00
SDL_mixer.carp Merge 2020-05-11 16:10:35 +02:00
SDL_ttf.carp Merge 2020-05-11 16:10:35 +02:00
SDL.carp Add support for cross-compilation. 2020-10-10 20:01:18 +02:00
SDLHelper.h core: fix SDL for newer versions 2020-10-15 13:14:31 +02:00
Sort.carp core: add sort flavors with custom comparators 2018-11-13 11:11:21 +01:00
StaticArray.carp Adds unsafe-raw to StaticArray module 2020-11-07 17:49:41 +00:00
Statistics.carp Fix all nth usage 2019-10-31 06:23:23 -03:00
StdInt.carp Moves StdInt functions with dependency on String into String.carp 2020-10-26 19:14:50 +00:00
String.carp refactor: Move code out of Macros.carp into other files (#1014) 2020-11-28 12:53:18 +01:00
System.carp Pointer: Add utility functions (#1012) 2020-11-30 07:06:04 +01:00
Test.carp Add support for cross-compilation. 2020-10-10 20:01:18 +02:00
Tuples.carp Meta set fix and refactor (#1008) 2020-11-24 19:27:34 +01:00
Unit.carp Unit: Add implementations of = (#1017) 2020-11-24 19:31:53 +01:00
Unsafe.carp core: rearrange templates 2020-05-12 21:58:40 +02:00
Vector.carp Add remaining implements declarations 2020-05-10 22:53:35 -04:00