added: `conv.encode_hex` `conv.decode_hex`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Jun 2023 01:59:59 +0000 (20:59 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 12 Jun 2023 01:59:59 +0000 (20:59 -0500)
CHANGELOG
core/alloc/heap.onyx
core/conv/conv.onyx
core/runtime/common.onyx
tests/hex_autocoder [new file with mode: 0644]
tests/hex_autocoder.onyx [new file with mode: 0644]

index ce3268b3b466d4c42d7fede964849ee9c3fe9728..447b40240b753349a001189db9da1082c14802f5 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -6,10 +6,16 @@ Additions:
 - New syntax for declaring quoted code blocks.
     - `[captures] { body }` for blocks.
     - `[captures] ( expr )` for expressions.
+- User-level stack trace.
+    - Enable with `--stack-trace`
+    - Use `runtime.info.get_stack_trace()` to get the current stack trace.
+    - Used in assertions and heap allocator for better error reporting
 - `Optional.with` for running a block of code with the value in an Optional, if one is present.
 - `iter.flatten`
 - `-Dvariable=value` command line option to add symbols to the `runtime.vars` package.
 - `--no-type-info` command line option to omit type information from the binary.
+- `conv.encode_hex` and `conv.decode_hex`
+    - Quickly convrt a byte array to and from its hex equivalent.
 
 Removals:
 - Remove old syntax for quoted blocks, `#quote` and `#()`.
index 7ef8932e3a9d2a43fa206ca9ec4bfba6f3e20cdb..c9508f296d1646af1dd6eaea45a010300d44aece 100644 (file)
@@ -15,8 +15,9 @@ use core
 // Enable this to enable checking for invalid blocks and other corruptions
 // that may happen on the heap, with the added overhead of checking that
 // on every alloc/resize/free.
-Enable_Debug :: #defined( runtime.vars.Enable_Heap_Debug )
-Enable_Clear_Freed_Memory :: #defined(runtime.vars.Enable_Heap_Clear_Freed_Memory)
+#local Enable_Debug :: #defined( runtime.vars.Enable_Heap_Debug )
+#local Enable_Clear_Freed_Memory :: #defined(runtime.vars.Enable_Heap_Clear_Freed_Memory)
+#local Enable_Stack_Trace :: runtime.Stack_Trace_Enabled
 
 #load "core/intrinsics/wasm"
 
@@ -195,18 +196,31 @@ get_freed_size :: () => {
         #if runtime.Multi_Threading_Enabled do sync.scoped_mutex(&heap_mutex);
 
         #if Enable_Debug {
+            // RELOCATE
+            trace :: macro () {
+                #if Enable_Stack_Trace {
+                    trace := runtime.info.get_stack_trace();
+                    for trace {
+                        log(.Error, "Core", core.tprintf("in {} ({}:{})", it.func_name, it.file, it.line));
+                    }
+                }
+            }
+
             if cast(uintptr) hb_ptr < cast(uintptr) __heap_start {
                 log(.Error, "Core", "FREEING STATIC DATA");
+                trace();
                 return;
             }
 
             if hb_ptr.size & Allocated_Flag != Allocated_Flag {
                 log(.Error, "Core", "INVALID DOUBLE FREE");
+                trace();
                 return;
             }
 
             if hb_ptr.magic_number != Alloc_Block_Magic_Number {
                 log(.Error, "Core", "FREEING INVALID BLOCK");
+                trace();
                 return;
             }
         }
index fc483c3eccca2ea307e478b0a1a25f7a04295ed3..8f8357207250b33d2c4c2b1c8c6cdaaec4ec9e98 100644 (file)
@@ -331,3 +331,39 @@ parse_float :: str_to_f64
 format_int :: i64_to_str
 format_uint :: u64_to_str
 format_float :: f64_to_str
+
+
+
+
+encode_hex :: (s: str, allocator := context.allocator) -> str {
+    #persist encode_map := u8.['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+
+    new_str := make([] u8, s.count * 2, allocator);
+    for i: s.count {
+        new_str[2 * i + 0] = encode_map[(s[i] & 0xf0) >> 4];
+        new_str[2 * i + 1] = encode_map[s[i] & 0xf];
+    }
+
+    return new_str;
+}
+
+decode_hex :: (s: str, allocator := context.allocator) -> str {
+    assert(s.count & 1 == 0, "Expected string of even length");
+
+    new_str := make([] u8, s.count >> 1, allocator);
+    for i: range.{0, s.count, 2} {
+        new_str[i >> 1] = ~~((digit_to_value(s[i + 0]) << 4) | (digit_to_value(s[i + 1])));
+    }
+    
+    return new_str;
+
+    digit_to_value :: (it: u8) -> u32 {
+        switch it {
+            case #char "0" .. #char "9" do return ~~(it - #char "0");
+            case #char "a" .. #char "f" do return ~~(it - #char "a" + 10);
+            case #char "A" .. #char "F" do return ~~(it - #char "A" + 10);
+        }
+
+        return 0;
+    }
+}
\ No newline at end of file
index 1b41acdf801ec1b841d822ba3d624ff0700d77d5..0f36e8b66921d82ada1663941b85526cff79ec07 100644 (file)
@@ -16,9 +16,23 @@ __assert_handler :: (msg: str, site: CallSite) {
     __output_string("Assert failed: ");
     __output_string(msg);
 
-    if site.file.data != null {
-        __output_string(" in ");
-        __output_string(site.file);
+
+    #if Stack_Trace_Enabled {
+        __output_string("\n");
+        trace := info.get_stack_trace();
+        for trace[1..trace.length] {
+            __output_string(" in ");
+            __output_string(it.func_name);
+            __output_string(" (");
+            __output_string(it.file);
+            __output_string(")\n");
+        }
+
+    } else {
+        if site.file.data != null {
+            __output_string(" in ");
+            __output_string(site.file);
+        }
     }
 
     __output_string("\n");
diff --git a/tests/hex_autocoder b/tests/hex_autocoder
new file mode 100644 (file)
index 0000000..75b9c42
--- /dev/null
@@ -0,0 +1,3 @@
+The quick brown fox jumps over the lazy dog
+54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67
+The quick brown fox jumps over the lazy dog
diff --git a/tests/hex_autocoder.onyx b/tests/hex_autocoder.onyx
new file mode 100644 (file)
index 0000000..cbcbbd3
--- /dev/null
@@ -0,0 +1,13 @@
+
+use core {*}
+
+main :: () {
+    s := "The quick brown fox jumps over the lazy dog";
+    println(s);
+
+    encoded := conv.encode_hex(s);
+    println(encoded);
+    
+    decoded := conv.decode_hex(encoded);
+    println(decoded);
+}