How to Zero a StringHashMap?

I have a StringHashMap, with sensitive data, and I need to zero it.
There are two problems when using an Iterator:

  1. Zeroing the value or key mutates the hash map, and invalidates the iterator.
  2. The key is []const u8, so it can’t be mutated.
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
    var iterator = self.hash_map.iterator();

    while (iterator.next()) |entry| {
        
        // Problems 1 and 2.
        std.crypto.secureZero(u8, entry.key_ptr.*);
        allocator.free(entry.key_ptr.*);

        // Just problem 1.
        entry.value_ptr.deinit(allocator);
    }

    self.fields.deinit();
}

This is a deinit function so it doesn’t matter if the zeroing destroys the StringHashMap’s ability to do anything after.

self.* = undefined is typical.

Isn’t undefined mean just whatever memory is already there, so wouldn’t this just not do anything?

I think there’s some misunderstanding here. I believe that neither using secureZero to zero out, nor freeing the key or value pointers, would actually modify the hash map. Only actually adding or removing entries from the hash map will really invalidate the iterator.

Yes, because StringHashMap assumes that the ownership of the keys is managed by the caller. That means you probably have other places managing the pointers to all the keys (for example, an arena). In that case, the problem of zeroing out shifts from how to iterate over the hash map to zeroing to how to zero the arena. If you want the HashMap to be the ultimate owner of the keys, you might want to consider something like AutoHashMap([]u8, V), but I still recommend using an arena to store the keys’ memory and try zeroing them that way.

Thanks!

So I could use an arena only for the StringHashMap and zero all memory from there, or I could use AutoHashMap that owns the string.

  1. Iterators will still work even if you change the key because it doesn’t use key values for iteration. So as long as you don’t do anything else with hashmap after that it will still work.

  2. If you know values in hashmap are definitely mutable (not string literals) you can just @constCast() them so you can zero them out. Or alternatively you can use underling HashMap but with []u8 instead of []const u8. If you never modify the keys outside of zeroing them out it might actually be more appropriate to use []const u8 with @constCast() because it will catch potential mutations in all other parts of the code.

  3. You can also consider using StringArrayHashMapUnmanaged which provides access to keys and values without iterator. It just gives you slice of keys and slice of values. Since no iterator is involved you can be sure its impossible for logic inside to break.

  4. Just using ArenaAllocator doesn’t mean keys will be zeroed out. It writes undefined to keys on deinit which doesn’t do anything in ReleaseFast.

  5. Also hashmaps store hashes of values inside and if data is really sensitive you might want to zero out hashes as well. Not sure how to do that tho if not just dig into hashmap implementation. I think it really depends on how secure hash function you use in hashmap is. Default one is unsalted wyhash which is probably not super secure.