LmCast :: Stay tuned in

Why is the x86 undefined instruction called ud2? Why 2?

Recorded: Sept. 13, 2026, 3 p.m.

Original Summarized

Why is the x86 undefined instruction called ud2? Why 2? - The Old New Thing

Skip to main content

Dev Blogs

AI

All .NET posts

.NET MAUI
ASP.NET Core
Blazor
Entity Framework

C++
C#
F#
TypeScript

NuGet
Servicing
.NET Blog in Chinese

Microsoft for Developers
Agent Framework
Develop from the cloud
Xcode
ISE Developer
TypeScript
PowerShell
Python
Java
Java Blog in Chinese
Go
Microsoft Edge Dev
Microsoft 365 Developer
Microsoft Entra Identity Developer
Microsoft Entra PowerShell

Visual Studio
Visual Studio Code
Aspire

All things Azure
Azure SDK
Azure VM Runtime Team
Microsoft Azure
Azure Cosmos DB
Azure DocumentDB
Azure Data Studio
Azure SQL
DevOps
DirectX
Microsoft Foundry
Power Platform

OData
Unified Data Model (IDEAs)

Windows Command Line
#ifdef Windows
Inside MSIX
MIDI and music
React Native
The Old New Thing
Windows Developer

Dev BlogsThe Old New ThingWhy is the x86 undefined instruction called ud2? Why 2?

September 10th, 2026

4 reactions

Why is the x86 undefined instruction called ud2? Why 2?

Raymond Chen

Show more

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 stick with ud2. Its behavior is consistent and architecturally guaranteed.

4

7

0

Share on Facebook

Share on X

Share on Linkedin

CategoryOld New ThingTopicsOther
Share


Author
Raymond ChenRaymond 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.

7 comments
Join the discussion.
Leave a commentCancel replySign in

Code of Conduct

Sort by :

Newest

Newest
Popular
Oldest

John Musbach

September 12, 2026

0

Copy link to comment by John Musbach

Collapse comment by John Musbach

I think we really shouldn’t need to worry about assembly anymore as compilers are quite good at doing their thing these days. Of course if you want to be on a Microsoft core team that’s a different story but I wonder how many genz are assembly knowledgeable at all

Log in to Vote or Reply

Csaba Varga


7 minutes ago
0

Copy link to comment by Csaba Varga

Collapse comment by Csaba Varga

Worry about it? No, you don't need to do that. But you need to know the basics if you ever need to write performance-critical code. Even today's amazing compilers won't necessarily fix a badly chosen algorithm that contains unpredictable jumps or has poor cache utilization. They won't replace a linked list with a vector even if the latter would be faster and more memory-efficient. If you have at least a general idea about what your source code turns into, you can help the compiler make the best out of it.
Most of us won't need to hand-write assembly code anymore, I'll...Read moreWorry about it? No, you don’t need to do that. But you need to know the basics if you ever need to write performance-critical code. Even today’s amazing compilers won’t necessarily fix a badly chosen algorithm that contains unpredictable jumps or has poor cache utilization. They won’t replace a linked list with a vector even if the latter would be faster and more memory-efficient. If you have at least a general idea about what your source code turns into, you can help the compiler make the best out of it.
Most of us won’t need to hand-write assembly code anymore, I’ll grant you that. Being able to read it could be helpful in rare cases where you don’t have the source code available. It can also help you appreciate what your compiler does for you, when you play around on godbolt.org 😀
Read less

Log in to Vote or Reply

Shawn Van Ness


17 hours ago
0

Copy link to comment by Shawn Van Ness

Collapse comment by Shawn Van Ness

I’ve never really heard of UD2 and friends.. I’ve always seen and used 0xCC (INT 3) when I want my program to crash.. and break in the debugger, if present.
How does the handling of UD2 compare to 0xCC?

Log in to Vote or Reply

liamgraham

September 12, 2026

0

Copy link to comment by liamgraham

Collapse comment by liamgraham

CC (INT 3) is a trap. Mostly used to signal precondition/contract breach
UD2 is more a hard stop because “executing random instructions”, as Raymond put it, can cause a lot of bugs.

Log in to Vote or Reply

Henry Skoglund


2 days ago
0

Copy link to comment by Henry Skoglund

Collapse comment by Henry Skoglund

Reminds me of programming the 6502: if you had a bug and the processor jumped into unknown territory, if the unused RAM had been zeroed out, you might catch those bugs easier. because the 0x00 opcode is BRK (force break).
For x86, I guess that UD2 instruction came pretty late to the party so all “handy” opcodes like 0x00 of 0xFF were already taken 🙁

Log in to Vote or Reply

Darren Izzard


1 day ago
0

Copy link to comment by Darren Izzard

Collapse comment by Darren Izzard

On the Acorn machines, the BRK vector caught such instructions and read the following bytes as an error message. (Well, technically, an error code, then the ASCII message.) This allowed language and service ROMs to report errors very simply, and also allowed errors to be caught from any ROM or application via a single interface. Thus, BASIC's ON ERROR could catch errors not just from BASIC, but also the file system, the network, some ROM that supported some new hardware you plugged in, whatever. And so could your wordprocessor, FORTH program, game, debugger software, etc.
Of course, should your code hit...Read moreOn the Acorn machines, the BRK vector caught such instructions and read the following bytes as an error message. (Well, technically, an error code, then the ASCII message.) This allowed language and service ROMs to report errors very simply, and also allowed errors to be caught from any ROM or application via a single interface. Thus, BASIC’s ON ERROR could catch errors not just from BASIC, but also the file system, the network, some ROM that supported some new hardware you plugged in, whatever. And so could your wordprocessor, FORTH program, game, debugger software, etc.
Of course, should your code hit a random 0x00 in memory, the screen would fill with garbage until the next 0x00 was hit. Since the character output routine managed all graphics and text output, it could also clear the screen, change screen mode, redefine characters, activate the printer, even suppress all output if the right bytes were read.
So you could say, while making error handling much easier, it also made it much more confusing.
Read less

Log in to Vote or Reply

Joshua Hudson


2 days ago
0

Copy link to comment by Joshua Hudson

Collapse comment by Joshua Hudson

0x00 is taken. it’s an ADD instruction all the way back on the 8086
0xFF is a prefix byte of a two byte instruction. However 0xFF 0xFF is not a valid instruction even today (as least as far as my disassembler is concerned).

Log in to Vote or Reply

Read next

September 1, 2026
Microspeak: Funded / unfunded

Raymond Chen

July 14, 2026
Microspeak: Double-click and drill down

Raymond Chen

Stay informed
Get notified when new posts are published.

Email *

Country/Region *
Select...United StatesAfghanistanÅland IslandsAlbaniaAlgeriaAmerican SamoaAndorraAngolaAnguillaAntarcticaAntigua and BarbudaArgentinaArmeniaArubaAustraliaAustriaAzerbaijanBahamasBahrainBangladeshBarbadosBelarusBelgiumBelizeBeninBermudaBhutanBoliviaBonaireBosnia and HerzegovinaBotswanaBouvet IslandBrazilBritish Indian Ocean TerritoryBritish Virgin IslandsBruneiBulgariaBurkina FasoBurundiCabo VerdeCambodiaCameroonCanadaCayman IslandsCentral African RepublicChadChileChinaChristmas IslandCocos (Keeling) IslandsColombiaComorosCongoCongo (DRC)Cook IslandsCosta RicaCôte dIvoireCroatiaCuraçaoCyprusCzechiaDenmarkDjiboutiDominicaDominican RepublicEcuadorEgyptEl SalvadorEquatorial GuineaEritreaEstoniaEswatiniEthiopiaFalkland IslandsFaroe IslandsFijiFinlandFranceFrench GuianaFrench PolynesiaFrench Southern TerritoriesGabonGambiaGeorgiaGermanyGhanaGibraltarGreeceGreenlandGrenadaGuadeloupeGuamGuatemalaGuernseyGuineaGuinea-BissauGuyanaHaitiHeard Island and McDonald IslandsHondurasHong Kong SARHungaryIcelandIndiaIndonesiaIraqIrelandIsle of ManIsraelItalyJamaicaJan MayenJapanJerseyJordanKazakhstanKenyaKiribatiKoreaKosovoKuwaitKyrgyzstanLaosLatviaLebanonLesothoLiberiaLibyaLiechtensteinLithuaniaLuxembourgMacau SARMadagascarMalawiMalaysiaMaldivesMaliMaltaMarshall IslandsMartiniqueMauritaniaMauritiusMayotteMexicoMicronesiaMoldovaMonacoMongoliaMontenegroMontserratMoroccoMozambiqueMyanmarNamibiaNauruNepalNetherlandsNew CaledoniaNew ZealandNicaraguaNigerNigeriaNiueNorfolk IslandNorth MacedoniaNorthern Mariana IslandsNorwayOmanPakistanPalauPalestinian AuthorityPanamaPapua New GuineaParaguayPeruPhilippinesPitcairn IslandsPolandPortugalPuerto RicoQatarRéunionRomaniaRwandaSabaSaint BarthélemySaint Kitts and NevisSaint LuciaSaint MartinSaint Pierre and MiquelonSaint Vincent and the GrenadinesSamoaSan MarinoSão Tomé and PríncipeSaudi ArabiaSenegalSerbiaSeychellesSierra LeoneSingaporeSint EustatiusSint MaartenSlovakiaSloveniaSolomon IslandsSomaliaSouth AfricaSouth Georgia and South Sandwich IslandsSouth SudanSpainSri LankaSt HelenaAscensionTristan da CunhaSurinameSvalbardSwedenSwitzerlandTaiwanTajikistanTanzaniaThailandTimor-LesteTogoTokelauTongaTrinidad and TobagoTunisiaTurkeyTurkmenistanTurks and Caicos IslandsTuvaluU.S. Outlying IslandsU.S. Virgin IslandsUgandaUkraineUnited Arab EmiratesUnited KingdomUruguayUzbekistanVanuatuVatican CityVenezuelaVietnamWallis and FutunaYemenZambiaZimbabwe

I would like to receive the The Old New Thing Newsletter. Privacy Statement.

Subscribe


Follow this blog

Are you sure you wish to delete this
comment?

OK
Cancel

Sign in

Theme

Insert/edit link

Close

Enter the destination URL

URL

Link Text

Open link in a new tab

Or link to existing content

Search

No search term specified. Showing recent items.

Search or use up and down arrow keys to select an item.

Cancel

Code Block

×

Paste your code snippet

Ok
Cancel

Surface Pro
Surface Laptop
Surface Laptop Ultra
Surface RTX Spark Dev Box
Copilot for organizations
Copilot for personal use
Explore Microsoft products
Windows 11 apps

Account profile
Download Center
Microsoft Store support
Returns
Order tracking
Certified Refurbished
Microsoft Store Promise
Flexible Payments

Microsoft in education
Devices for education
Microsoft Teams for Education
Microsoft 365 Education
How to buy for your school
Educator training and development
Deals for students and parents
AI for education

Microsoft AI
Microsoft Security
Dynamics 365
Microsoft 365
Microsoft Power Platform
Microsoft Teams
Microsoft 365 Copilot
Small Business

Azure
Microsoft Developer
Microsoft Learn
Support for AI marketplace apps
Microsoft Tech Community
Microsoft Marketplace
Software companies
Visual Studio

Careers
About Microsoft
Company news
Privacy at Microsoft
Investors
Diversity and inclusion
Accessibility
Sustainability

Your Privacy Choices Opt-Out Icon

Your Privacy Choices

Your Privacy Choices Opt-Out Icon

Your Privacy Choices

Consumer Health Privacy

Sitemap
Contact Microsoft
Privacy
Manage cookies
Terms of use
Trademarks
Safety & eco
Recycling
About our ads

The x86 undefined instruction, ud2, arises from an evolution concerning how software can reliably trigger exceptions and the subsequent need for architectural consistency in instruction handling. Originally, there was no designated architecturally undefined instruction on x86. Developers seeking to force an invalid opcode exception searched for specific byte sequences that would reliably generate this error. This search led to the discovery of sequences like 0F FF and 0F B9, both of which, despite seemingly taking two parameters, functioned as invalid opcodes because the exception was raised before the parameters could be processed.

The naming convention for the undefined operations was established retroactively by Intel as better practice emerged. The 0F FF variant was eventually named ud0, and the 0F B9 variant was named ud1, leaving ud2 as the designated and recommended undefined opcode. This choice reflects a systematic approach to defining these states. A key advantage of ud2 is its simplicity: it is a two-byte instruction containing no parameters, thereby avoiding the complexity introduced by ud0 and ud1, which still contained unused source and destination parameters that the processor might decode. This complexity is problematic because if the instruction decoding crosses into a not-present page, the system might raise an access violation instead of the desired invalid opcode exception, depending on the specific processor implementation and historical context.

The rationale for preferring ud2 is based on ensuring consistent and architecturally guaranteed behavior. While the unused parameters in ud0 and ud1 allowed for ambiguous outcomes based on memory state, ud2 provides a clear, uncontroversial state. This distinction is crucial because the behavior of these instructions must be predictable, especially in systems where the instruction decoding process can interact with memory management, making the consistent behavior of ud2 superior to the variants derived from other sequences. Consequently, ud2 is the standard used by implementers, providing a reliable mechanism for handling unintended execution paths, particularly when compilers generate it to denote unreachable code, such as following a function marked as not returning.