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

推荐订阅源

C
Cisco Blogs
Cyberwarzone
Cyberwarzone
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
SecWiki News
SecWiki News
Martin Fowler
Martin Fowler
T
Tor Project blog
N
Netflix TechBlog - Medium
C
Cybersecurity and Infrastructure Security Agency CISA
V
Vulnerabilities – Threatpost
V
Visual Studio Blog
GbyAI
GbyAI
PCI Perspectives
PCI Perspectives
D
DataBreaches.Net
Jina AI
Jina AI
H
Heimdal Security Blog
云风的 BLOG
云风的 BLOG
P
Privacy International News Feed
A
About on SuperTechFans
J
Java Code Geeks
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
N
News | PayPal Newsroom
有赞技术团队
有赞技术团队
MyScale Blog
MyScale Blog
博客园 - 司徒正美
C
Check Point Blog
T
Threat Research - Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
宝玉的分享
宝玉的分享
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
P
Proofpoint News Feed
Blog — PlanetScale
Blog — PlanetScale
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
The Last Watchdog
The Last Watchdog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
I
InfoQ
阮一峰的网络日志
阮一峰的网络日志
Cisco Talos Blog
Cisco Talos Blog
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
Recent Commits to openclaw:main
Recent Commits to openclaw:main
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
Docker
博客园 - Franky
Security Archives - TechRepublic
Security Archives - TechRepublic

The Old New Thing

Speculating on how the buggy control panel extension truncated a value that it had right in front of it - The Old New Thing The case of the invalid function pointer when shutting down the display control panel - The Old New Thing Microspeak: Double-click and drill down - The Old New Thing Why don't we just make the entire stack out of guard pages? - The Old New Thing I've decoded a #pragma detect_mismatch error and fixed the mismatch, but I still get the error - The Old New Thing The other kind of control flow guard check: The combined validate and call - The Old New Thing How did Windows 95 decide that a setup program ran? - The Old New Thing I opened a file with FILE_FLAG_DELETE_ON_CLOSE, but now I changed my mind - The Old New Thing How did we conclude that CcNamespace.dll was the ringleader of a group of DLLs that unloaded prematurely? - The Old New Thing The case of the thread executing from an unloaded third-party DLL - The Old New Thing It rather involved being on the other side of this airtight hatchway: Changing administrative settings - The Old New Thing 2026 mid-year link clearance - The Old New Thing A compatibility note on the abuse of Windows window class extra bytes - The Old New Thing The evolution of window and class extra bytes in Windows - The Old New Thing The case of the DLL that was not present in memory despite not being formally unloaded, part 2 - The Old New Thing Raymond's hot take on Hainanese chicken - The Old New Thing The case of the DLL that was not present in memory despite not being formally unloaded, part 1 - The Old New Thing Cancellation of Windows Runtime activities is asynchronous - The Old New Thing Microspeak elaborated: Isn't escrow just a release candidate by another name? - The Old New Thing In memory of the man who put red and green squiggles under words - The Old New Thing What does it mean when the bottom bit of my HMODULE is set? - The Old New Thing Why doesn't Get­Last­Input­Info() return info for the user I'm impersonating? - The Old New Thing Windows stack limit checking retrospective, follow-up - The Old New Thing Retrofitting the WM_COPY­DATA message onto Windows 3.1 - The Old New Thing The time the x86 emulator team found code so bad that they fixed it during emulation - The Old New Thing How can I schedule work on a thread pool with low latency? Understanding the rationale behind a rule when trying to circumvent it What’s the opposite of Clip­Cursor that lets me exclude the cursor from a region? The Microsoft Company Party where everybody played name tag swap Rotation revisited: Shuffling more than three blocks, and other small notes The back cover of C++: The Programming Language also raises questions not answered by the front cover Rotation revisited: Avoiding having to calculate the gcd when doing cycle decomposition Rotation revisited: Cycle decomposition in clang’s libcxx Rotation revisited: A shocking discovery about gcc’s unidirectional rotation algorithm Rotation revisited: Another unidirectional algorithm The placeholder name for the Windows 8 experience was “modern” Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 3 Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 2 Sharing the result of a single Windows Runtime IAsyncOperation among multiple coroutines, part 1 If C# and JavaScript lets me await a Windows Runtime asynchronous operation more than once, why not C++/WinRT? A hypothetical redesign of System.Diagnostics.Process to avoid confusion over properties that are valid only when you are the one who called Start Why do you say that a COM STA thread must pump messages if I see sample code creating STA threads and not pumping messages? How do I use Win32 structures from the Windows Runtime? What is the history of the ERROR_ARENA_TRASHED error code? The classic TreeView control lets me sort by name or by lParam, but why not both? Just shows that nobody cares about debugging the parity flag any more The case of the Create­File­Mapping that always reported ERROR_ALREADY_EXISTS
The case of the mysterious changes to integers when there shouldn't have been any code generation effect - The Old New Thing
Raymond Chen · 2026-07-10 · via The Old New Thing

A colleague made some code changes that should not have had any effect on the generated binary. Specifically, they migrated from the NDIS_STRING_CONST macro to the more type-safe RTL_CONSTANT_STRING macro. The two macros produce the same results at the end of the day, so the expectation was that this would not result in any change to the binary.

But they found a change to the binary.

Specifically, four functions changed, and what is particularly strange is that none of them involved the macro changes. Three of the functions are in one source file, and the fourth is in a source file that wasn’t even touched!

The changes looked like this:

Before After
contoso!EvtWdfWidgetContextCleanup
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [rsp+20h], rcx
mov r9d, 62Bh
mov r8d, 52467443h
mov rcx, [contoso!WdfDriverGlobals]
mov rdx, rbx
mov rax, [rax+670h]
call __guard_dispatch_call
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [rsp+20h], rcx
mov r9d, 62Ah
mov r8d, 52467443h
mov rcx, [contoso!WdfDriverGlobals]
mov rdx, rbx
mov rax, [rax+670h]
call __guard_dispatch_call
contoso!Function2
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [rsp+20h], rcx
mov r9d, 616h
mov rcx, [contoso!WdfDriverGlobals]
mov r8d, 52467443h
mov rdx, rdi
mov rax, [rax+668h]
call __guard_dispatch_call
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [rsp+20h], rcx
mov r9d, 615h
mov rcx, [contoso!WdfDriverGlobals]
mov r8d, 52467443h
mov rdx, rdi
mov rax, [rax+668h]
call __guard_dispatch_call
contoso!Function3
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [r11-20h], rcx
xor r8d, r8d
mov rcx, [contoso!WdfDriverGlobals]
mov r9d, 35Dh
mov rax, [rax+0DB0h]
call __guard_dispatch_call
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov [r11-20h], rcx
xor r8d, r8d
mov rcx, [contoso!WdfDriverGlobals]
mov r9d, 35Ch
mov rax, [rax+0DB0h]
call __guard_dispatch_call
contoso!Function4
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov rdx, [rbp+8]
mov r9d, 377h
mov [rsp+20h], rcx
mov r8d, 49507443h
mov rcx, [contoso!WdfDriverGlobals]
mov rax, [rax+0DB8h]
call __guard_dispatch_call
mov rax, [contoso!WdfFunctions_01031]
lea rcx, [??_C@__0DK@MPBCIIPN@...]
mov rdx, [rbp+8]
mov r9d, 376h
mov [rsp+20h], rcx
mov r8d, 49507443h
mov rcx, [contoso!WdfDriverGlobals]
mov rax, [rax+0DB8h]
call __guard_dispatch_call

In all of the cases, the change is that a single integer changed to a value one smaller.

My colleague asked an LLM to explain this change, and it suggested that the changes were related to control flow guard metadata. Does this make sense?

It didn’t make sense to me, on two points. First, for the guard dispatch call, the only parameter to control flow guard is the rax register, which is the function being checked. All the other registers contain the parameters to the called function. Since the changes are to the r9d register, they are not related to control flow guard.

Second, the control flow guard metadata is not stored in code. It’s stored as a data block inside the binary.

So what are we seeing?

I took a look a EvtWdfWidgetContextCleanup.

void EvtWdfWidgetContextCleanup(_In_ WDFOBJECT Object)
{
    auto widgetContext = GetContextFromWidgetHandle(Object);
    if (widgetContext->NeedsDereference)
    {
        widgetContext->NeedsDereference = FALSE;
        WdfObjectDereferenceWithTag(Object, CONTOSO_WIDGET_TAG);
    }
}

The compiler points to the WdfObjectDereferenceWithTag as the location of the change. And we see that it is defined as a macro:

#define WdfObjectDereferenceWithTag(Handle, Tag) \
        WdfObjectDereferenceActual(Handle, Tag, __LINE__, __FILE__)

which is itself an inline function:

_IRQL_requires_max_(DISPATCH_LEVEL)
VOID
FORCEINLINE
WdfObjectReferenceActual(
    _In_
    WDFOBJECT Handle,
    _In_opt_
    PVOID Tag,
    _In_
    LONG Line,
    _In_z_
    PCCH File
    )
{
    ((PFN_WDFOBJECTREFERENCEACTUAL) WdfFunctions[WdfObjectReferenceActualTableIndex])
        (WdfDriverGlobals, Handle, Tag, Line, File);
}

The last little detail is that WdfFunctions is a macro that expands to WdfFunctions_01031. The WDF header files give each version a unique name so that mismatched versions lead to a linker error rather than undefined behavior at runtime.

Now we can see how this code maps to the compiler output.

    mov rax, [contoso!WdfFunctions_01031]   ; WdfFunctions
    lea rcx, [??_C@__0DK@MPBCIIPN@...]      ; Address of something
    mov [rsp+20h], rcx                      ; is the File parameter
    mov r9d, 62Bh                           ; Line parameter
    mov r8d, 52467443h                      ; Tag parameter
    mov rcx, [contoso!WdfDriverGlobals]     ; hard-coded parameter
    mov rdx, rbx                            ; Handle parameter
    mov rax, [rax+670h]                     ; Load the function pointer
    call __guard_dispatch_call              ; Validate and call¹

So the value that changed is the line number.

I went back to the pull request and observed that the pull requested deleted a line from the source file.

#include <strsafe.h>
#include "stringutils.h"

Part of the pull request included deleting the no-longer-needed header because it contained a private definition of the NDIS_STRING_CONST macro, which the code no longer uses.

Deleting a line from the source file causes all the line numbers to shift by one!

So what they were seeing was just a change to the line numbers. No change in functionality.

If they really wanted to make this a “no binary effect” change, they could replace the #include "stringutils.h with a comment or just leave it as a blank line.

Or they could just accept that line numbers can change when you change lines.

Bonus chatter: But wait, I said that three of the changes were in one file, the one with the deleted line, but a fourth was in a file that didn’t change at all. What’s that about?

The fourth function contained a call to a function in the modified file, and link-time code generation decided to inline that call. The changed line number propagated into the inline function and resulted in a code generation change in a file that wasn’t even affected by the pull request.

¹ Recall that in the validate-and-call pattern, the function pointer is passed in the rax register, and everthing else is set up as if you were calling the function yourself.

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.