I was reading the std.debug module and found the @disableInstrumentation() builtin, but I haven’t found any documentation that explains how it is supposed to be used.
That’s a case where reading the source is what one needs to do.
But good question: specifically what instrumentation does this refer to? Or is it generic, to be used by any kind of instrumentation being built in user land? and if so, how?
From my limited understanding it seems to be related to the implementation of Zig’s fuzzer/coverage-guided testing feature.
Which seems to instrument the code to be able to trace which paths the code has explored while fuzzing, but because there are things like the default/custom test runner which allows you to write Zig code to influence how you test and/or fuzz-test something, I imagine that within the implementation they ran into a problem where the code that orchestrates how to do the fuzzing was instrumented in ways that made the code not work. (I don’t know all the specific problems they had)
So they basically needed a way to separate between the code that is needed to implement the fuzzing and the code that actually should be fuzzed.
At least that is my best guess from the things I have read. Which is mostly the test runner lib/compiler/test_runner.zig and some searches on the old github search, for commits and issues.
Here are two I found pretty interesting:
- update start code to use `@disableInstrumentation` · ziglang/zig@bde8c4a · GitHub
- implement code coverage instrumentation manually · ziglang/zig@b8d99a3 · GitHub
I think @disableInstrumentation results in:
src/Sema.zig:
.disable_instrumentation => {
try sema.zirDisableInstrumentation();
i += 1;
continue;
},
→ zirDisableInstrumentation → InternPool.funcSetDisableInstrumentation(func):
pub fn funcSetDisableInstrumentation(ip: *InternPool, func: Index) void {
const unwrapped_func = func.unwrap(ip);
const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
extra_mutex.lock();
defer extra_mutex.unlock();
const analysis_ptr = ip.funcAnalysisPtr(func);
var analysis = analysis_ptr.*;
analysis.disable_instrumentation = true; // NOTE basically setting this
@atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
}
Which then connects back to src/codegen/llvm.zig:
const fuzz: ?FuncGen.Fuzz = f: {
if (!owner_mod.fuzz) break :f null;
if (func_analysis.disable_instrumentation) break :f null; // NOTE resulting in disabling fuzzing for the function in later codegen
...
I think the tl;dr is:
- if you need to ask what it is, you probably shouldn’t use it
(unless you write a custom test runner or something related to fuzzing) - it is related to coverage/fuzzing and instrumentation of code
… yeah this is a good undocumented feature for me to know about.
I do not think it’s responsible to add builtins and not document them. This should not happen.
Are there others? Because I just found out about something which should be in my code and isn’t, and now I’m paranoid there are more of those.
@disableInstrumentation() is the only undocumented builtin that I am aware of, I also think it would be good to actually document it, I still think that most people won’t need it, but a few may have good use for it.
I am unsure why it isn’t documented, my guess would be the general observation that fuzzing is a bit half-baked at the moment, so thoughts about the builtin and whether it should actually exist in this form long term might not be completely tackled yet, it seems a bit more like a hack to get fuzzing to work.
That kind of question comes closest to a defensible reason not to document a builtin. Doesn’t hit the mark but it’s not worth complaining about twice. I’ll stop trying to figure out the sed filter to put between rg and sort | unique to derive the list from first principles…