{"id":106215,"date":"2022-02-03T07:00:00","date_gmt":"2022-02-03T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=106215"},"modified":"2023-08-30T10:58:42","modified_gmt":"2023-08-30T17:58:42","slug":"20220203-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20220203-00\/?p=106215","title":{"rendered":"A closer look at the stack guard page"},"content":{"rendered":"<p>In a discussion of <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20060927-07\/?p=29563\"> why <code>Is\u00adBad\u00adXxx\u00adPtr<\/code> should really be called <code>Crash\u00adProgram\u00adRandomly<\/code><\/a>, I gave a brief description of the stack guard page:<\/p>\n<blockquote class=\"q\"><p>The dynamic growth of the stack is performed via guard pages: Just past the last valid page on the stack is a guard page. When the stack grows into the guard page, a guard page exception is raised, which the default exception handler handles by committing a new stack page and setting the <i>next<\/i> page to be a guard page.<\/p><\/blockquote>\n<p>Let&#8217;s break this down a bit more.<\/p>\n<p>Here&#8217;s a thread&#8217;s stack after the thread has been running for a little while. As is customary in memory diagrams, higher addresses are at the top, which means that the stack grows downward (toward lower addresses).<\/p>\n<div id=\"p20220203_style\">\u00a0<\/div>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td style=\"animation: 1s ease-in-out infinite alternate wobble;\">\u2190 Stack pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffffb5; color: black;\">guard page<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The regular committed pages encompass all of the stack memory that the program has used so far. It may not be using all of it right now: Any memory beyond the <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190111-00\/?p=100685\"> red zone<\/a> is off limits to the application. When the stack pointer recedes from its high water mark, the pages left behind are not decommitted.<\/p>\n<p>The page just past the stack pointer&#8217;s high water mark is a special type of committed page known as a guard page. A guard page is a page which raises a <code>STATUS_<wbr \/>GUARD_<wbr \/>PAGE_<wbr \/>VIOLATION<\/code> exception the first time it is accessed.<\/p>\n<p>Suppose that the stack pointer moves into the guard page, indicating that the thread has increased its stack requirements by one additional page.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffffb5; color: black;\">guard page<\/td>\n<td>\u2190 Stack pointer<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The moment the thread accesses memory from the guard page, the system converts it to a regular committed page (removing the <code>PAGE_<wbr \/>GUARD<\/code> flag) and raises a <code>STATUS_<wbr \/>GUARD_<wbr \/>PAGE_<wbr \/>VIOLATION<\/code> exception. The default exception handler deals with the exception by looking to see if the address lies in the current stack&#8217;s guard page region. If so, then it upgrades the next reserved page to a guard page, and then resumes execution:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td align=\"center\">Before<\/td>\n<td>&nbsp;<\/td>\n<td align=\"center\">During<\/td>\n<td>&nbsp;<\/td>\n<td align=\"center\">After<\/td>\n<\/tr>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-left: none;\" rowspan=\"5\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffffb5; color: black;\">guard page<\/td>\n<td>\u2190 Stack pointer \u2192<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>\u2190 Stack pointer \u2192<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffffb5; color: black;\">guard page<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Clearing the <code>PAGE_<wbr \/>GUARD<\/code> flag on an access to a guard page means that once you access it, it stops being a guard page. This means that guard pages raise the guard page exception only on first access. If you fail to take action on a guard page exception, the system ignores it, and you lost your one chance to do something.<\/p>\n<p>This is why our code to <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200609-00\/?p=103847\"> detect stack overflows<\/a> makes sure to call <code>_resetstkoflw()<\/code> if it decides to recover. Resetting the stack overflow state consists of turning the <code>PAGE_<wbr \/>GUARD<\/code> flag back on for the guard page, restoring the page to its former glory as a guard page so it can do its job of detecting stack growth.<\/p>\n<p>This is how things go when everything is working right. But things don&#8217;t always work right.<\/p>\n<p>If one thread accesses another thread&#8217;s guard page, perhaps due to a buffer overflow, or just an uninitialized pointer variable that happens to point there, that too will trigger the guard page exception. That exception is raised by the thread that did the accessing, which is not the thread that owns the stack. The default exception handler sees that the guard page exception is not for the current thread&#8217;s stack, so it ignores it.\u00b9<\/p>\n<p>Congratulations, your stack is now corrupted, because the guard page is gone:<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td style=\"animation: 1s ease-in-out infinite alternate wobble;\">\u2190 Stack pointer<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>(oops)<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Things proceed normally for a while, until the thread&#8217;s stack needs to grow into what used to be the guard page.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>\u2190 Stack pointer (oops)<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Normally, this would trigger a guard page exception, and the system would do the usual thing of upgrading the next reserved page to a new guard page. However, that page is no longer a guard page, so execution just continues normally with no action taken.<\/p>\n<p>Things still proceed as if everything were perfectly normal, but the consequences of your misdeeds finally catch up to you when the stack pointer crosses into a <i>second<\/i> new page, the first <i>reserved<\/i> page.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td style=\"vertical-align: middle; width: 1em; border: solid 1px currentcolor; border-right: none;\" rowspan=\"4\"><span style=\"writing-mode: vertical-lr; -ms-writing-mode: tb-rl; transform: rotate(180deg);\">valid stack<\/span><\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #caffd8; color: black;\">committed<\/td>\n<td>(oops)<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<td>\u2190 Stack pointer (double oops)<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 1ex;\">\u00a0<\/td>\n<td style=\"border: solid 1px currentcolor; height: 3em; background-color: #ffb5b5; color: black;\">reserved<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This is also not a guard page, so no special stack expansion kicks in. You just get a stack overflow exception and die.<\/p>\n<p>Such is the sad life of invalid memory access. You can corrupt your own process in a subtle way that doesn&#8217;t show up until much, much later.<\/p>\n<p>Next time, we&#8217;ll investigate a stack overflow problem and learn how to detect whether this guard page corruption has occurred.<\/p>\n<p>\u00b9 In theory, the default exception handler could search through all the threads in the process and see if the address resides in a guard page of <i>any<\/i> thread, but it doesn&#8217;t. One reason is that this would require cross-thread coordination with the thread whose guard page you accidentally accessed, as well as any other thread that also might be accessing that guard page at the same time. But the bigger reason is probably that the entire situation is a bug in the program anyway, and there&#8217;s no point going out of your way to slow down the system in order to deal with things that programs shouldn&#8217;t be doing anyway.<\/p>\n<p>\n<script>\n(function() {\n  \/\/ break up \"style\" to prevent wordpress from injecting random junk\n  document.getElementById(\"p20220203_style\").innerHTML = `<s` + `tyle>\n@keyframes wobble {\n    from { transform: translateY(0); }\n    to { transform: translateY(-6em); }\n}\n<\/s` + `tyle>`;\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>It is there to detect stack growth, but only if the stack grows into it.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-106215","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It is there to detect stack growth, but only if the stack grows into it.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=106215"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/106215\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=106215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=106215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=106215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}