Open iamanonymouscs opened 11 months ago
Seems like this triggers an assertion failure in InstrTypes.h.
clang: llvm/include/llvm/IR/InstrTypes.h:1503: void llvm::CallBase::setCalledFunction(FunctionType *, Value *): Assertion `getType() == FTy->getReturnType()' failed.
@jyknight I see you added this comment and assert, do you have an idea about what's going on here? I assume from skimming the file and the stack trace that there is probably an invalid pointer assigned here and things bumble along until we try to write the bitcode out. Feels like maybe this should be a fatal error, but I haven't figured out the calling context that triggers the assert yet to know if that even makes sense, or if there is just a missing check at the call site.
ah, so this seems related to the fact that fprintf()
is special, and is mentioned in the system ignore list referenced in the -fsanitize-system-ignorelist=
option passed to -cc1
. Not sure how we'd like to handle that edgecase, though.
The reason I added the assert is that it didn't seem likely to be correct to update the FTy member, but not the Value type of the call. But I didn't know what behavior would actually change if I fixed that. The answer was apparently: nobody ever did that, until now.
Notably, the only other function in that class which updates FTy, mutateFunctionType, does adjust the Value type too.
I don't know if this assert was catching a bug in your code, or if it would've been correct for this API to update the type in your use-case?
I'm not sure what use case @iamanonymouscs had. Judging from the file name, I'd hazard this was generated from some kind of fuzzing. I was just responding to the bug report, since a reproducer is usually straightforward to run down, and ICE is one of my pet peeves.
DFSan isn't something I've looked into all that much, at least not on an implementation level, so I was hoping you'd have an idea. I'll try to set aside some time on Monday to dig a little deeper and figure out a good solution.
So, near as I can tell this is sort of a weird case, since casting a function pointer and calling it like that is UB.
The crash seems to be caused by the interaction of a few things.
First, the above assert fires because fprintf
is listed asunistrumented
in the default AbiList file, changing that or the funcion name will prevent the crash.
If we ignore the assert, like a release build, we eventually still run into an issue because CanonicalizeAliasPass will transform the call from:
call void (...) @fprintf()
into
call i32 (ptr, ptr, ...) @fprintf()
This causes an error because the function requires more parameters than were provided. Seems like by default the verifier is disable in the -cc1
command line, and would otherwise fire.
Even without the verifier, though, in an assert build, this would eventually get caught in IstrTypes.h when the index is out of range, but instead it returns something out of bounds as a pointer value and eventually faults when derefing that pointer.
I guess the only thing to do is to try and detect the situation in the dfsan
pass, but I'm not sure yet on how to do that. Maybe we need to check if the function has an alias before we call setCalledFunction()
in visitWrappedCallBase()
?
Clang-18 with -fsanitize=dataflow -fwhole-program-vtables -flto -c crashes on the test case. Compiler explorer: https://gcc.godbolt.org/z/vf5rGThx5