惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - Franky
T
Tailwind CSS Blog
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
博客园 - 叶小钗
N
Netflix TechBlog - Medium
罗磊的独立博客
量子位
MyScale Blog
MyScale Blog
A
About on SuperTechFans
Blog — PlanetScale
Blog — PlanetScale
V
Visual Studio Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
GbyAI
GbyAI
B
Blog
腾讯CDC
爱范儿
爱范儿
Recent Announcements
Recent Announcements
有赞技术团队
有赞技术团队
F
Fortinet All Blogs
雷峰网
雷峰网
G
Google Developers Blog
Google DeepMind News
Google DeepMind News

The Old New Thing

std::call_once vs. std::async - The Old New Thing Magic statics vs. std::call_once - The Old New Thing Why do Microsoft job levels start in the high 50's instead of starting at a sane number like 1? - The Old New Thing Why didn't Read­Directory­ChangesW provide a way to correlate the two sides of a rename operation? - The Old New Thing How can I remove the Close button from my window caption? - The Old New Thing What algorithm did Windows XP use to choose your initial user picture? - The Old New Thing A sample use of the winstart.bat file in Windows 95 - The Old New Thing Why don't we allow stacks to be sparse, instead of forcing them to be contiguous? - The Old New Thing What happens if you change a window class's GCL_CB­WND­EXTRA? - The Old New Thing The case of the progress callback that never got called when progress happened - The Old New Thing The perils of binding to value types in XAML - The Old New Thing Microspeak: Funded / unfunded - The Old New Thing AWE does not require PAE, though PAE makes it much more useful - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 2 - The Old New Thing On forcing all derived classes to implement a specific non-virtual method, part 1 - The Old New Thing In the product end game, every change carries significant risk, episode 2 - The Old New Thing Why didn't the Windows Entertainment Pack just run the MS-DOS version inside an emulator? - The Old New Thing Comparing the two holograms on the Windows 95 box - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function, practical exam - The Old New Thing Reducing C++ template bloat by factoring out the type-dependent portions of the function - The Old New Thing On wrapping a callable in a lambda that just calls it with the same parameters - The Old New Thing Why did the Microsoft Entertainment Pack for Windows have a special sticker announcing that it also had Tetris? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing How do functions like alloca allocate memory from the stack? - The Old New Thing Forcing an ARM64X executable to run as a specific architecture - The Old New Thing A little helper class for managing LPPROC_THREAD_ATTRIBUTE_LISTs - The Old New Thing The comments that go into code versus those that go into the pull request description - The Old New Thing The little-known winstart.bat batch file - The Old New Thing How can I perform a Copy­File&shy in unbuffered mode? - The Old New Thing Creating a fake agile wrapper that is technically agile but is not useful outside its home apartment, part 5 - The Old New Thing
Why is the x86 undefined instruction called ud2? Why 2? -...
Raymond Chen · 2026-09-10 · via The Old New Thing

If you look at x86 compiler output (or if, like me, you’re looking at a crash caused by some software that tried to detour an API), you may see an instruction ud2. What’s up with that?

The ud2 instruction is an architecturally undefined instruction, guaranteed to raise an “invalid opcode” exception. Some compilers generate it to mark “unreachable” code, so that if execution somehow manages to reach it, you get a crash rather than executing random instructions. For example, if a function marked [[noreturn]] somehow returns, the compiler will put a ud2 after the call so that the program crashes instead of falling through to the next function.

Anyway, why is this instruction called ud2 instead of just ud? Was there a ud1? What was so wrong about ud1 that we had to make a ud2?

I think I can reconstruct what happened.

Originally, there was no architecturally undefined instruction on x86. So people who wanted to force an invalid opcode exception went looking for some byte sequence that reliably raised the invalid opcode exception when executed.

Somebody found that the 0F FF sequence led to an invalid opcode exception. Though, for whatever reason, the instruction internally decoded as if it took two parameters, a register destination and a register-or-memory source. The parameters aren’t actually used because the invalid opcode exception gets raised before anything else can happen.

Meanwhile, somebody else found that the 0F B9 sequence also had the same properties. So you now had two factions, the 0F FF believers and the 0F B9 adherents. There really wasn’t much of a battle between them, because both techniques seemed to work, and it’s not like one was coming at the detriment of the other.

Intel then worked on their next processor, and maybe they made some changes that resulted in 0F FF no longer raising an invalid opcode exception. Maybe they tried introducing a new instruction that uses 0F FF. Or maybe it was still undefined but just performed some random operation instead of raising the invalid opcode instruction. And when they started running software on their new processor, they found that some programs stopped working, and after laborious investigation, they discovered that the programs were relying on 0F FF being an invalid opcode.

In other words, they ran into Hyrum’s Law: With a sufficient number of users, all observable behaviors will be depended upon by somebody. Obligatory XKCD.

A similar discovery was made with 0F B9.

Now that they realized that people wanted a reliable way to trigger an invalid opcode exception, the folks at Intel decided to make it official, and they created an actual supported permanently-invalid instruction and called it ud2.

It’s called ud2 because the 0F FF variant was retroactively named ud0, and the 0F B9 variant was retroactively named ud1, leaving ud2 as the recommended undefined opcode.

One advantage of ud2 is that it is a two-byte instruction with no parameters, so you don’t have to deal with the random decoded-but-unused source and destinations.

Bonus chatter: But why do we care about the unused parameters to ud0 and ud1? Can’t we just say that ud0 and ud1 are also two-byte invalid opcodes? I mean, sure, there’s a third byte, or possibly more if the memory operand has an offset or a scaled index, but the processor doesn’t use it.

It matters, because even though the processor doesn’t use it, it still decodes it. And if the decoding of the instruction crosses into a not-present page, you don’t get an invalid opcode exception at all. You get an access violation.

Bonus bonus chatter: Except that some older processors raised the invalid opcode instruction as soon as they decoded the 0F FF without checking whether the rest of the instruction decoded properly. So if your 0F FF is at the end of a page, and the next page is not present, you sometimes got an invalid opcode exception and you sometimes got an access violation.

Better to stuck with ud2. Its behavior is consistent and architecturally guaranteed.

Category

Topics

Author

Raymond Chen

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.