{"id":107848,"date":"2023-02-20T07:00:00","date_gmt":"2023-02-20T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=107848"},"modified":"2023-02-19T17:20:08","modified_gmt":"2023-02-20T01:20:08","slug":"20230220-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230220-00\/?p=107848","title":{"rendered":"The case of the mysterious &quot;out of bounds&quot; error from <CODE>CreateUri<\/CODE> and <CODE>memmove<\/CODE>"},"content":{"rendered":"<p>A customer was trying to understand why their program was crashing with an <code>E_BOUNDS<\/code> error in what appears to be a call to <code>CreateUri<\/code>.<\/p>\n<pre style=\"font-size: 80%;\">combase!RoOriginateErrorW+0x50\r\nwincorlib!Platform::Details::ReCreateFromException+0x40\r\ncontoso!`__abi_translateCurrentException'::`1'::catch$0+0x10\r\ncontoso!memmove+0x217f4\r\ncontoso!Windows::Foundation::IUriRuntimeClassFactory::CreateUri+0x44\r\ncontoso!Contoso::DashboardView::DashboardView_obj1_Bindings::Update_ViewModel_Layout_Groups+0x50\r\ncontoso!Contoso::DashboardView::DashboardView_obj1_Bindings::Update_ViewModel_Layout+0xe4\r\ncontoso!Contoso::DashboardView::DashboardView_obj1_Bindings::PropertyChanged+0x1134\r\ncontoso!XamlBindingInfo::XamlBindingTrackingBase::PropertyChanged+0x30\r\n<\/pre>\n<p>From the stack, it looks like <code>memmove<\/code> threw a <code>E_BOUNDS<\/code> C++\/CX exception, which doesn&#8217;t make sense. Even more mysteriously, the <code>memmove<\/code> was called from <code>CreateUri<\/code>, but their DashboardView doesn&#8217;t manipulate URIs in any obvious way. It&#8217;s just a stack trace of nonsense.<\/p>\n<p>Let&#8217;s try to unwind the nonsense.<\/p>\n<p>As for the mysterious <code>memmove<\/code>, notice that the offset is <code>0x217f4<\/code>. It&#8217;s unlikely that the <code>memmove<\/code> function is over 100KB in size. Let&#8217;s see what&#8217;s really going on there. This is just some code that has probably been shunted into a rarely-used code page far, far away from the rest of the code, and the nearest symbol to it happens to be <code>memmove<\/code>.<\/p>\n<pre>    xor     ecx,ecx\r\n    call    contoso!__abi_translateCurrentException\r\n    int     3       ; memmove+0x217f4\r\n<\/pre>\n<p>Yup, this is an exception rethrow. Since exceptions are rare, profile-guided optimization puts all the exception-handling nonsense into faraway pages so that they don&#8217;t consume valuable space in the hot code pages.<\/p>\n<p>So why is CreateUri throwing an &#8220;out of bounds&#8221; exception?<\/p>\n<p>Well, are you sure it&#8217;s really <code>CreateUri<\/code>?<\/p>\n<p>I looked a frame higher on the stack. &#8220;Why is data binding calling <code>CreateUri<\/code>?&#8221;<\/p>\n<p>The data binding code is autogenerated by the XAML compiler; it&#8217;s not checked into the source tree. Instead of trying to figure out how to build their project (so I can extract the autogenerated file), maybe I can infer what&#8217;s going on from the source.<\/p>\n<p>One basic assumption that you make about code in general is that people who write code are doing the best they can, rather than being sadists. This means that function names will generally be descriptive of what they do, variable names will generally be descriptive of what they represent, and so on. So when I see a class called <code>DashboardView_obj1_Bindings<\/code>, I&#8217;m going to assume that this class is for dealing with the bindings of some object in DashboardView, and since it has a method called <code>Update_<wbr \/>ViewModel_<wbr \/>Layout_<wbr \/>Groups<\/code>, it probably has something to do with updating the binding of something whose names involve the words <code>ViewModel<\/code>, <code>Layout<\/code>, and <code>Groups<\/code>.<\/p>\n<p>I looked at <code>DashboardView.xaml<\/code> and searched for the word <code>ViewModel<\/code> in elements that appeared to be involved with binding.<\/p>\n<pre>&lt;ContentControl\r\n    Grid.Row=\"0\"\r\n    x:Name=\"TogglesGroup\"\r\n    IsTabStop=\"False\"\r\n    Width=\"360\"\r\n    Content=\"{x:Bind ViewModel.Layout.Groups[0], Mode=OneWay}\"\r\n    ContentTemplateSelector=\"{StaticResource DashboardGroupTemplateSelector}\"\/&gt;\r\n<\/pre>\n<p>Now, this wasn&#8217;t the first use of <code>x:Bind<\/code> in the XAML markup, so that doesn&#8217;t line up with <code>obj1<\/code>, but the other parts do line up (the <code>Layout<\/code> and <code>Groups<\/code>), so I chalked this up to &#8220;Maybe the XAML compiler generates bindings in some order other than the order they appear in the markup.&#8221;<\/p>\n<p>How could this binding raise an &#8220;out of bounds&#8221; exception? Well, there&#8217;s a subscript operation, so maybe the <code>Groups<\/code> collection is empty.<\/p>\n<p>I looked at the <code>Update_<wbr \/>ViewModel_<wbr \/>Layout_<wbr \/>Groups<\/code> method to see if that theory lined up.<\/p>\n<pre>Update_ViewModel_Layout_Groups:\r\n    test    rdx,rdx\r\n    je      ...\r\n    mov     qword ptr [rsp+8],rbx\r\n    mov     qword ptr [rsp+18h],rbp\r\n\r\n    push    rsi\r\n    push    rdi\r\n    push    r14\r\n    sub     rsp,20h\r\n    mov     rbp,rdx\r\n    mov     rsi,rcx\r\n    test    r8d,0C0000001h\r\n    je      ...\r\n\r\n    xor     edx,edx\r\n    mov     rcx,rbp\r\n    call    contoso!Windows::Foundation::IUriRuntimeClassFactory::CreateUri\r\n<\/pre>\n<p>The function starts with a shrink-wrapped early-out if the first parameter is zero. (This is a C++ method, so <code>rcx<\/code> contains <code>this<\/code> and <code>rdx<\/code> contains the first formal parameter.) I don&#8217;t know how binding works, but presumably this is just a binding thing.<\/p>\n<p>If the parameter is nonzero, then we build a proper stack frame, test some bits in the third parameter, and if they&#8217;re set, we call, um, <code>Create\u00adUri<\/code> with <code>nullptr<\/code>? That makes no sense. The XAML isn&#8217;t asking for a URI, and why is this code trying to create a URI from an empty string?<\/p>\n<p>But then you realize that you&#8217;ve been faked out by COMDAT folding. The <code>this<\/code> parameter for the call to <code>Create\u00adUri<\/code> is supposed to be the <code>IUri\u00adRuntime\u00adClass\u00adFactory<\/code>, but that&#8217;s not what we&#8217;re passing; we&#8217;re passing the first formal parameter.<\/p>\n<p>Really, this is a call to <code>IVector::GetAt<\/code>, and the parameter is zero, indicating that we want the object at index zero. The functions <code>IVector::GetAt<\/code> and <code>Create\u00adUri<\/code> were folded because they happen to be byte-for-byte identical. They are both &#8220;Call the method at index 6 in the vtable with one parameter.&#8221; For <code>IUri\u00adRuntime\u00adClass\u00adFactory<\/code>, that method is <code>Create\u00adUri<\/code> and the parameter is a string. For <code>IVector<\/code> that method is <code>Get\u00adAt<\/code> and the parameter is an index.<\/p>\n<p>With this explanation, the customer realized that they did have an outstanding bug that said, &#8220;If our settings file is corrupted, we end up with no groups,&#8221; and this bug is likely an alternate manifestation of that bug.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unfolding some COMDATs.<\/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-107848","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Unfolding some COMDATs.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107848","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=107848"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/107848\/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=107848"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=107848"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=107848"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}