{"id":102840,"date":"2019-09-05T07:00:00","date_gmt":"2019-09-05T14:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=102840"},"modified":"2019-09-04T19:24:05","modified_gmt":"2019-09-05T02:24:05","slug":"20190905-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190905-00\/?p=102840","title":{"rendered":"Making the <CODE>COM_<\/CODE><CODE>INTERFACE_<\/CODE><CODE>ENTRY<\/CODE> macro better at detecting misuse"},"content":{"rendered":"<p><a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20190904-00\/?p=102837\"> Last time<\/a>, we studied a crash involving improper use of the <code>COM_<\/code><code>INTERFACE_<\/code><code>ENTRY<\/code> macro. Can we make it better at detecting misuse at compile time?<\/p>\n<p>We want to make sure that <code>IWidget\u00adProvider\u00adInfo<\/code> derives directly from <code>IUnknown<\/code>, so that, given the declaration<\/p>\n<pre>IWidgetProviderInfo* p;\r\n<\/pre>\n<p>we can guarantee that <code>IWidget\u00adProvider\u00adInfo<\/code> is convertible to <code>IUnknown<\/code> and that<\/p>\n<pre>reinterpret_cast&lt;IUnknown*&gt;(p) == static_cast&lt;IUnknown*&gt;(p)\r\n<\/pre>\n<p>Otherwise, somebody could try this:<\/p>\n<pre>struct Strange { ... };\r\ninterface IWidgetProvider : Strange, IUnknown\r\n{\r\n  ...\r\n};\r\n<\/pre>\n<p>The <code>IWidget\u00adProvider<\/code> can be converted to a <code>IUnknown<\/code>, but it will probably also need to be adjusted by <code>sizeof(Strange)<\/code>.\u00b9<\/p>\n<p>ATL already has a macro for calculating the amount by which the two parts of the above comparison differ. It uses it for deciding how much to adjust the pointer to get to the desired interface:<\/p>\n<pre>#define offsetofclass(base, derived) \\\r\n    ((DWORD_PTR)(static_cast&lt;base*&gt;((derived*)_ATL_PACKING)) \\\r\n                                             -_ATL_PACKING)\r\n<\/pre>\n<p>So we just need to assert that the value is (1)\u00a0calculable, and (2)\u00a0zero.<\/p>\n<p>The original definition of <code>COM_<\/code><code>INTERFACE_<\/code><code>ENTRY<\/code> is<\/p>\n<pre>#define COM_INTERFACE_ENTRY(x)\\\r\n    {&amp;IID_##x, \\\r\n    offsetofclass(x, _ComMapClass), \\\r\n    _ATL_SIMPLEMAPENTRY},\r\n<\/pre>\n<p>We can make this minor adjustment to ensure that converting from <code>x<\/code> to <code>IUnknown<\/code> is both possible and a nop:<\/p>\n<pre>#define COM_INTERFACE_ENTRY(x)\\\r\n    {&amp;IID_##x, \\\r\n    offsetofclass(x, _ComMapClass)<span style=\"color: blue;\">\/!offsetofclass(IUnknown, x)<\/span>, \\\r\n    _ATL_SIMPLEMAPENTRY},\r\n<\/pre>\n<p>If <code>x<\/code> cannot be converted to <code>IUnknown<\/code>, then the <code>offsetofclass<\/code> will encounter a compile-time error because the <code>static_cast<\/code> from <code>x*<\/code> to <code>IUnknown*<\/code> is not possible.<\/p>\n<p>If the conversion is possible but requires a pointer adjustment, then the <code>offsetof<\/code> will produce a nonzero value. Negating it with <code>!<\/code> will produce <code>0<\/code>, and dividing by it will trigger a divide-by-zero compile-time error.<\/p>\n<p>If the conversion is possible and does not require a pointer adjustment (which is the case we want to permit), then the <code>offsetof<\/code> will result in the value <code>0<\/code>. Negating it with <code>!<\/code> will produce <code>1<\/code>, and dividing by <code>1<\/code> has no effect.<\/p>\n<p>You can apply this same fix to the other <code>COM_<\/code><code>INTERFACE_<\/code><code>ENTRY<\/code> macros, and to any other macro that assumes that its type parameter is derived from <code>IUnknown<\/code>.<\/p>\n<p>\u00b9 Types that are not <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/data_members#Standard_layout\"> standard layout<\/a> are not required to place the first named base class at offset zero relative to the derived class, so this is something worth checking even if you think everything is set up correctly.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Playing around with compile-time errors.<\/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-102840","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Playing around with compile-time errors.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102840","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=102840"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/102840\/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=102840"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=102840"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=102840"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}