Weird ud2 generation

First off, sorry if this is the wrong place to send this.

I’m attempting to debug a crash in the Atom editor for users of Arch Linux on kernels before 4.6.0. We compile Atom with Clang, and users of old kernels are now reporting that the main native-code component, Electron, is getting SIGILLs. Hand-decompiling (so there might be mistakes) the area near the crash in the core dump, I found a function that looks like:

void xyzzy(void* addr, size_t len) {

if(madvise(addr, len, MADV_FREE) != 0)

asm(“ud2”); // We’re crashing on the ud2.

}

It doesn’t correspond to any code we’re compiling, however. In Electron and all its dependencies, madvise is only used once, in a completely separate context from the surrounding code. The code looks a lot more like it was generated by Clang than by GCC, though, so I’m suspecting it’s used in some sort of intrinsic or compiler support function?

For reference, Atom is structured like:

Atom → Electron → Chromium --\

-----> node.js ------> V8

The code surrounding the “xyzzy” function seems to be coming from a file in V8, node/platform-posix.cc at ee8c429deaee0adeeef069c3ad34c0defe53a567 · electron/node · GitHub

I’m wondering if either a) someone recognizes this off the bat as something Clang uses for some purpose, or b) if someone with more experience with Clang, or the V8 codebase could help with solving? The part where it’s related to the kernel version is what’s really throwing me off…

ud2 is used for __builtin_trap() and a few other cases of implicit stop
instructions. But the most likely candidate is the former. A good start
for further debugging on your part is the -save-temps output. It should
created annotated assembly, giving you some clue for where the
instruction comes from.

Joerg

Thanks, I’ll try that. Any reason why it’d only affect older (but only by a few months) kernels?

The other use for ud2 is in code that the optimisers believe is unreachable (or, more accurately, only reachable as a result of undefined behaviour). If you do madvise and then later do something that would only be valid if the return value is non-zero then you may end up with a ud2.

David