I think eventually there could be static analyzers for Zig that can detect and point out if you have used a different one for closing then was used for opening. Static analyzers might not be able to catch all cases. So the remaining cases would require dynamic techniques, theoretically you could use techniques like DynamoRIO Automated Function Tracing - #4 by Sze to create arbitrary runtime checks.
Zig also could use these or similar techniques, but I am not sure whether it makes sense to have a safety-check for using the wrong allocator / IO, maybe. Zig might not need something like DynamoRIO (although I think it could be useful when working on projects that use a lot of non-zig code), but I think considering something in the direction (basically I think Zig should eventually enable some of the kinds of things you can do with DynamoRIO, though it might choose a different way to implement these capabilities) could potentially lead to a very interactive and nice way to work with code and edit, debug and profile it in development.
Maybe once incremental and the compiler communication protocol is implemented it would allow similar things like DynamoRIO (through instructing the compiler to compile and hot-swap a version of the code that includes some kind of tracing code). I think there is a a bunch of tradeoffs between the kinds of applications you can use it with vs how nicely it is integrated into the build system / language / ecosystem. I think eventually it would be nice if you could use --webui and then toggle on a bunch of optional debugging features for modules where you want it. (If some of those are too expensive to always run in debug mode)
Overall it seems to me that if such checks would be done, they should be implemented through some mostly automatic way, whether that is by compiling code with some kind of tracing enabled or similar techniques.