{"id":111306,"date":"2025-06-25T07:00:00","date_gmt":"2025-06-25T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111306"},"modified":"2025-06-25T07:33:27","modified_gmt":"2025-06-25T14:33:27","slug":"20250625-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250625-00\/?p=111306","title":{"rendered":"Why do I get errors about some weird symbol called ?main@@YAHP$01E$AAV?$Array@PE$AAVString@Platform&#8230;, part 1"},"content":{"rendered":"<p>A colleague was writing a fuzz test and ran into a build error.<\/p>\n<pre style=\"white-space: pre-wrap;\">vccorlib.lib(climain.obj) : error LNK2019: unresolved external symbol \"?main@@YAHP$01E$AAV?$Array@<wbr \/>PE$AAVString@<wbr \/>Platform@@<wbr \/>$00@Platform@@@Z\" (?main@@YAHP$01E$AAV?$Array@<wbr \/>PE$AAVString@<wbr \/>Platform@@<wbr \/>$00@Platform@@@Z) referenced in function \"int __cdecl _main(void)\" (?_main@@YAHXZ)\r\n<\/pre>\n<p>What does this mean?<\/p>\n<p>My colleague was writing a fuzz test in C++, but noted that other parts of the component are written in C++\/CX.<\/p>\n<p>I could have guessed that C++\/CX was involved because the missing symbol says that it&#8217;s a function named <code>main<\/code> which takes parameters that involve things named <code>Array<\/code>, <code>String<\/code>, and <code>Platform<\/code>.<\/p>\n<p><a title=\"Walkthrough: Compiling a C++\/CX Program on the Command Line\" href=\"https:\/\/learn.microsoft.com\/cpp\/build\/walkthrough-compiling-a-cpp-cx-program-on-the-command-line?view=msvc-170\"> The signature for the <code>main<\/code> function in a C++\/CX program<\/a> is<\/p>\n<pre>int main(Platform::Array&lt;Platform::String^&gt;^ args)\r\n<\/pre>\n<p>so that seems to match up with the words we picked out of the decorated name.<\/p>\n<p>(Amusingly, C++\/CX is such a black sheep that the linker&#8217;s decorated name decoder can&#8217;t even decode C++\/CX names.)<\/p>\n<p>The usage of this particular fuzz test library is similar to LLVM&#8217;s <a href=\"https:\/\/llvm.org\/docs\/LibFuzzer.html\">libFuzzer<\/a>: You define a fuzzing entrypoint that takes a memory block, and the library provides a <code>main<\/code> function that calls your function repeatedly with different blocks of memory.<\/p>\n<p>We pulled in the Visual Studio team to help figure out why the wrong <code>main<\/code> function was being requested.<\/p>\n<p>They suggested linking with the <code>\/verbose<\/code> to get more insight into how the linker is working.<\/p>\n<pre>      Found mainCRTStartup\r\n        Loaded libcmt.lib(exe_main.obj)\r\n\r\n      Found main\r\n        Referenced in LIBCMT.lib(exe_main.obj)\r\n        Loaded vccorlib.lib(main.obj)\r\n\r\n      Found \"int __cdecl _main(void)\" (?_main@@YAHXZ)\r\n        Referenced in vccorlib.lib(main.obj)\r\n        Loaded vccorlib.lib(climain.obj)\r\n\r\nvccorlib.lib(climain.obj) : error LNK2019: unresolved external symbol \"?main@@YAHP$01E$AAV?$Array@<wbr \/>PE$AAVString@<wbr \/>Platform@@<wbr \/>$00@Platform@@@Z\" (?main@@YAHP$01E$AAV?$Array@<wbr \/>PE$AAVString@<wbr \/>Platform@@<wbr \/>$00@Platform@@@Z) referenced in function \"int __cdecl _main(void)\" (?_main@@YAHXZ)\r\n<\/pre>\n<p>The error message says that <code>vccorlib.lib<\/code>&#8216;s <code>climain.obj<\/code> has a reference to the weird version of <code>main<\/code>. Working backward through the verbose output, we see that <code>vccorlib.lib(climain.obj)<\/code> was in turn added to the binary because it satisfied a search for <code>int __cdecl _main(void)<\/code> that was requested by <code>vccorlib.lib(main.obj)<\/code>.<\/p>\n<p>The <code>vccorlib.lib(main.obj)<\/code> was added to the binary because it satisfied a request for <code>main<\/code> from <code>libcmt.lib(exe_main.obj)<\/code>.<\/p>\n<p>And <code>libcmt.lib(exe_main.obj)<\/code>. was added to the binary because it satisfied a request for <code>mainCRTStartup<\/code>, which was presumably requested by the linker because this was linked as a console program.<\/p>\n<p>The problem is that the <code>main<\/code> function was found in <code>vccorlib.lib<\/code> rather than in the fuzzer library.<\/p>\n<p>The final piece of the puzzle is <a title=\"LINK input files\" href=\"https:\/\/learn.microsoft.com\/cpp\/build\/reference\/link-input-files?view=msvc-170\"> the linker documentation on the finer points of how it resolves symbols<\/a>:<\/p>\n<blockquote class=\"q\"><p>Object files on the command line are processed in the order they appear on the command line. Libraries are searched in command line order as well, with the following caveat: Symbols that are unresolved when bringing in an object file from a library are searched for in that library first, and then the following libraries from the command line and <tt>\/DEFAULTLIB<\/tt> (Specify default library) directives, and then to any libraries at the beginning of the command line.<\/p><\/blockquote>\n<p>Okay, now we can piece the story together by working forward.<\/p>\n<p>The linker starts by looking for <code>mainCRTStartup<\/code>, and that leads to the <code>main<\/code>, which in turn leads to the wrong <code>int __cdecl _main()<\/code>. We get the wrong one due to the &#8220;symbols that are unresolved when bringing in an object file from a library&#8221; rule: The linker got <code>main<\/code> from <code>vccorlib.lib<\/code>, so the search for <code>_main<\/code> begins at <code>vccorlib.lib<\/code>, and that&#8217;s why it finds the one in <code>vccorlib.lib(climain.obj)<\/code> instead of the one in the fuzzer library.<\/p>\n<p>Now that we understand what happened, we can produce a minimal reproducible example.<\/p>\n<pre style=\"white-space: pre-wrap;\">&gt;lib.cpp echo void fuzzme(); int __cdecl main(int, char**) { fuzzme(); return 42; }\r\ncl \/c lib.cpp\r\nlib \/out:lib.lib lib.obj\r\n<\/pre>\n<p>This first step creates a library which provides a definition of <code>main<\/code>. This is the minimal version of the fuzzer library.<\/p>\n<pre style=\"white-space: pre-wrap;\">&gt;fuzzer.cpp echo void fuzzme() {}\r\ncl \/c fuzzer.cpp\r\n<\/pre>\n<p>The next step creates the fuzzer client that the fuzzer library calls.<\/p>\n<p>And then we can try to link it and see what happens.<\/p>\n<pre style=\"white-space: pre-wrap;\">link \/out:fuzzer.exe \/subsystem:console fuzzer.obj lib.lib\r\n\r\nrem succeeds!\r\n<\/pre>\n<p>Hm, our attempt to create a minimal reproduction failed. There must be something we are missing.<\/p>\n<p>We&#8217;ll continue the investigation next time.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to the world of C++\/CX. Is &#8220;welcome&#8221; the right word?<\/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-111306","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Welcome to the world of C++\/CX. Is &#8220;welcome&#8221; the right word?<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111306","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=111306"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111306\/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=111306"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111306"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111306"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}