Repository: getsentry/symbolic (rust)

Issue:
Symcaches created from WASM files with symbol tables only contain 1 function
Zendesk: https://sentry.zendesk.com/agent/tickets/149793

Converting the mentioned WASM files to SymCaches produces something like
```
Cache info:
SymCache {
    version: 8,
    debug_id: DebugId {
        uuid: "1031808b-46af-1a4c-83a4-cc79b80638b1",
        appendix: 0,
    },
    arch: Wasm32,
    files: 0,
    functions: 1,
    source_locations: 109745,
    ranges: 109745,
    string_bytes: 44203617,
}
```
despite there being lots of symbols in the symbol table.

Pull request:
fix(symcache): Overwrite "empty" mappings for symbols
As of #897 we explicitly insert the ends of functions and symbols into symcaches to reduce bogus mappings. While this worked correctly for functions, we introduced a bug in the case of symbols that resulted in symbols not being properly inserted into symcaches.

This fixes the bug by explicitly overwriting previously inserted "empty" mappings.

Fixes #914. Fixes SYMBOL-9.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f2b56647..15741e5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## Unreleased
+
+**Fixes**
+
+- symcache: Fixed a bug introduced in 12.14.0 that resulted in symbols not being inserted. ([#915](https://github.com/getsentry/symbolic/pull/915))
+
 ## 12.15.3
 
 **Features**
diff --git a/symbolic-symcache/src/writer.rs b/symbolic-symcache/src/writer.rs
index 7eae227a..0565bda1 100644
--- a/symbolic-symcache/src/writer.rs
+++ b/symbolic-symcache/src/writer.rs
@@ -430,6 +430,24 @@ impl<'a> SymCacheConverter<'a> {
                     inlined_into_idx: u32::MAX,
                 });
             }
+            btree_map::Entry::Occupied(mut entry) if entry.get() == &NO_SOURCE_LOCATION => {
+                // This happens when an "empty" mapping was inserted in a previous iteration (see below).
+                // In this case we want to overwrite the mapping, so we do the same thing as in the `Vacant` case.
+                let function = raw::Function {
+                    name_offset: name_idx,
+                    _comp_dir_offset: u32::MAX,
+                    entry_pc: symbol.address as u32,
+                    lang: u32::MAX,
+                };
+                let function_idx = self.functions.insert_full(function).0 as u32;
+
+                entry.insert(raw::SourceLocation {
+                    file_idx: u32::MAX,
+                    line: 0,
+                    function_idx,
+                    inlined_into_idx: u32::MAX,
+                });
+            }
             btree_map::Entry::Occupied(entry) => {
                 // ASSUMPTION:
                 // the `functions` iterator has already filled in this addr via debug session.


Test patch:
diff --git a/py/tests/test_crashprobe.py b/py/tests/test_crashprobe.py
index 99c67aa8..16a3a43d 100644
--- a/py/tests/test_crashprobe.py
+++ b/py/tests/test_crashprobe.py
@@ -364,7 +364,7 @@ def test_jump_into_an_nx_page(res_path, make_report_sym, version, build, arch):
 
     # So let's assert for the second best
     else:
-        assert "full_path" not in bt[0]
+        assert basename(bt[0]["full_path"]) is None
         assert bt[0]["line"] in (None, 0)
 
     _test_doCrash_call(bt)
diff --git a/symbolic-symcache/tests/test_writer.rs b/symbolic-symcache/tests/test_writer.rs
index a95196a6..b106b572 100644
--- a/symbolic-symcache/tests/test_writer.rs
+++ b/symbolic-symcache/tests/test_writer.rs
@@ -371,6 +371,14 @@ fn test_lookup_between_functions() {
     // This address is exactly at the end of the function "-[CRLCrashNXPage desc]",
     // which starts at 0x8b0c and has size 0x2c. The next function,
     // "-[CRLCrashStackGuard category]", starts at 0x8b3c.
+    //
+    // However, there is an entry in the symbol table for "-[CRLCrashNXPage crash]" starting
+    // at this address.
     let symbols = symcache.lookup(0x8b38).collect::<Vec<_>>();
-    assert!(symbols.is_empty());
+    assert_eq!(symbols.len(), 1);
+
+    let function = symbols[0].function();
+
+    assert_eq!(function.name(), "-[CRLCrashNXPage crash]");
+    assert_eq!(function.entry_pc(), 0x8b38);
 }