<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Morgan Ma</title>
    <description>The latest articles on DEV Community by Morgan Ma (@datacpp_3670).</description>
    <link>https://dev.to/datacpp_3670</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4063654%2Fa6a76f1b-0f06-4574-85d8-4edd1ce3af7e.png</url>
      <title>DEV Community: Morgan Ma</title>
      <link>https://dev.to/datacpp_3670</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/datacpp_3670"/>
    <language>en</language>
    <item>
      <title>Use a Free Server to Catch an AI-Written Race</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Mon, 31 Aug 2026 12:13:35 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/use-a-free-server-to-catch-an-ai-written-race-300b</link>
      <guid>https://dev.to/datacpp_3670/use-a-free-server-to-catch-an-ai-written-race-300b</guid>
      <description>&lt;p&gt;Some bugs exist only on another machine. Your laptop is silent. Production crashes. Half the time the culprit is a data race. AI-generated code makes this worse. It writes threads confidently. It forgets the locks. A free server plus a sanitizer can find these bugs. I will show you a short workflow using MonkeyCode's free tokens and free server.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reproducer
&lt;/h2&gt;

&lt;p&gt;Consider this tiny C++ program. Four threads push into one &lt;code&gt;std::vector&lt;/code&gt;. That operation is not thread-safe. It is undefined behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;thread&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="kr"&gt;thread&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;emplace_back&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;threads&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile it locally. It may print 40000. It may crash. The behavior depends on timing, CPU, and allocator state. That is the nature of UB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why AI Code Introduces Races
&lt;/h2&gt;

&lt;p&gt;Large language models are trained on patterns. Threading patterns often omit synchronization. They look correct. They compile clean. The race appears only in production. This is why you need a second environment. Sound familiar?&lt;/p&gt;

&lt;h2&gt;
  
  
  The Free Server and Free Model
&lt;/h2&gt;

&lt;p&gt;MonkeyCode is an open-source AI coding assistant. It offers 10 million free tokens. It also includes a free remote server. Use the model to generate test tools. Use the server to run them. No cloud bill arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1 — Generate a Sanitizer Build
&lt;/h2&gt;

&lt;p&gt;Ask the free model to provide a ThreadSanitizer command. You get something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-pthread&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;thread &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O1&lt;/span&gt; race.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; race
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ThreadSanitizer (TSan) is a runtime checker. It tracks every memory access. It reports conflicting threads and source lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 — Put the Code on the Free Server
&lt;/h2&gt;

&lt;p&gt;Upload &lt;code&gt;race.cpp&lt;/code&gt; to the free server. You can use SSH. You can also use a browser terminal. Both work. Then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-pthread&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;thread &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O1&lt;/span&gt; race.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; race &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; ./race
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3 — Read the Warning
&lt;/h2&gt;

&lt;p&gt;TSan prints a data race report. Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WARNING: ThreadSanitizer: data race (pid=12345)
  Write of size 8 at 0x7f... by thread T2:
    #0 main::$_0::operator() race.cpp:18 (race+0x...)

  Previous write of size 8 at 0x7f... by thread T1:
    #0 main::$_0::operator() race.cpp:18 (race+0x...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The report shows two stacks. Each stack points to the same line in your source. That line is the unprotected &lt;code&gt;push_back&lt;/code&gt;. Root cause confirmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4 — Fix the Race
&lt;/h2&gt;

&lt;p&gt;Add a mutex around the shared vector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;mutex&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// inside the lambda&lt;/span&gt;
&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rebuild. Run TSan again. No warning. The program also produces 40000 every time. Note: &lt;code&gt;std::atomic&lt;/code&gt; works for simple counters. It does not make &lt;code&gt;std::vector&lt;/code&gt; thread-safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Review Trap
&lt;/h2&gt;

&lt;p&gt;Imagine a code review. An AI wrote a thread pool. It looks fine. The reviewer approves it. Then production crashes once. Nobody can reproduce it. This is a familiar story. The missing step is a runtime check on a different architecture. This workflow fills that gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision Table
&lt;/h2&gt;

&lt;p&gt;Use this free-server workflow when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production crashes are intermittent.&lt;/li&gt;
&lt;li&gt;Local runs always pass.&lt;/li&gt;
&lt;li&gt;You suspect threading errors.&lt;/li&gt;
&lt;li&gt;You cannot access the production box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Skip it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already have a useful core dump.&lt;/li&gt;
&lt;li&gt;The crash consistently happens on the first run.&lt;/li&gt;
&lt;li&gt;You need exact production data and traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A free server is not a mirror of production.&lt;/li&gt;
&lt;li&gt;TSan significantly slows execution.&lt;/li&gt;
&lt;li&gt;TSan may report false positives with custom atomics.&lt;/li&gt;
&lt;li&gt;MonkeyCode's free tier may change. Check its official repo for current limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;The environment is part of the bug. A second machine is often enough to expose it. You do not need to buy hardware. A free server and a sanitizer will do. Let the AI write the helper. Let TSan find the truth. Why buy a server for one race? Try this flow the next time you debug a mystery crash.&lt;/p&gt;

</description>
      <category>debugging</category>
      <category>cpp</category>
      <category>ai</category>
      <category>testing</category>
    </item>
    <item>
      <title>Free Models, a Free Server, and a Reference That Outlived Its Function</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Sun, 30 Aug 2026 11:15:09 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/free-models-a-free-server-and-a-reference-that-outlived-its-function-2084</link>
      <guid>https://dev.to/datacpp_3670/free-models-a-free-server-and-a-reference-that-outlived-its-function-2084</guid>
      <description>&lt;p&gt;A dangling reference is easy to miss on your laptop and hard to ignore on a container that behaves differently. Free AI tools can generate the first bug and then help you find it, if you know how to verify their output.&lt;/p&gt;

&lt;p&gt;This article walks through a real failure: an AI-generated C++ function returned a reference to a local variable. Local tests passed. Then the same code crashed on a remote free server. The fix came from a combination of free model iteration, a free server environment, and the sanitizers you already have installed.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Function That Looked Fine
&lt;/h2&gt;

&lt;p&gt;The task was simple: read a list of words and return the longest one. I asked a free model for an implementation. Here is the first version it produced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;longestWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;longest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mistake is invisible unless you notice that &lt;code&gt;longest&lt;/code&gt; is a local object. Returning a const reference to it leaves a handle to destroyed memory. The compiler stayed quiet, and the tests stayed green.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Local Mirage
&lt;/h2&gt;

&lt;p&gt;Building with warnings produced nothing useful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt; longest.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; longest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GCC does not flag every return-local-address case when the returned type is a reference. I also looped the binary ten thousand times. Every run exited cleanly. Undefined behavior is like that: it works until the stack layout shifts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Asking the Free Model for a Second Opinion
&lt;/h2&gt;

&lt;p&gt;Instead of staring at the code, I fed the function back into a free model on MonkeyCode and asked: "Where is the lifetime bug?" The model spotted the returning reference almost immediately and proposed a value return.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;longestWord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;words&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;longest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;longest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A second pair of eyes helps when the first pair is tired. Still, trusting an answer without running it defeats the purpose. The next step was to test the corrected version in a real environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a Free Server Changed Everything
&lt;/h2&gt;

&lt;p&gt;MonkeyCode's free server option provides a small Linux container for experimentation. It is not a production cluster, but it is different enough from a development laptop: different library versions, stricter memory limits, and a less forgiving stack layout. That difference is exactly what exposes latent undefined behavior.&lt;/p&gt;

&lt;p&gt;I uploaded the original broken version and built it with debug symbols.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O2&lt;/span&gt; longest.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; longest
./longest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Segmentation fault on the first run. Reproduced in seconds. On the free server, the dangling reference pointed at memory that was already reclaimed by another allocation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sanitizers Pointed at the Real Cause
&lt;/h2&gt;

&lt;p&gt;The crash told me something was wrong but not where. AddressSanitizer gave the location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address &lt;span class="nt"&gt;-fno-omit-frame-pointer&lt;/span&gt; longest.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; longest_asan
./longest_asan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output named the exact stack frame:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: AddressSanitizer: stack-use-after-scope
    #0 ... longestWord ... longest.cpp:8
    #1 ... main ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;UBSan confirmed it independently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;undefined longest.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; longest_ubsan
./longest_ubsan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two sanitizers, one verdict: the function returned a reference to a destroyed local.&lt;/p&gt;

&lt;p&gt;The corrected version passed on the free server under both sanitizers. A clean run is not proof of absence, but combined with the lifetime fix, it was enough to move forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Repeatable Workflow on a Budget
&lt;/h2&gt;

&lt;p&gt;The whole exercise cost almost nothing in tokens and no server fees. Here is the routine that caught the bug.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Have a free model generate or review the code, but never treat the answer as verified.&lt;/li&gt;
&lt;li&gt;Build with &lt;code&gt;-g -fsanitize=address -fno-omit-frame-pointer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run on a fresh environment, ideally the free server, not only on the local shell.&lt;/li&gt;
&lt;li&gt;If a crash appears, let the sanitizer name the frame.&lt;/li&gt;
&lt;li&gt;Fix the root cause and rerun both ASan and UBSan.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That cycle turns a free token allowance into a meaningful quality gate. The cost is small; the lesson is durable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where This Falls Short
&lt;/h2&gt;

&lt;p&gt;Sanitizers only see the code paths you execute. If the test suite never calls the risky function, the bug stays hidden. The free server is also a minimal container, not a replica of your production fleet. Differences in glibc versions, kernel hardening, or concurrency patterns can still introduce surprises.&lt;/p&gt;

&lt;p&gt;The free model is not an oracle either. It found this bug because the pattern is common. For subtle logic errors or performance traps, you still need careful reading and profiling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Skip This Approach
&lt;/h2&gt;

&lt;p&gt;If you only write interpreted languages, ASan and UBSan are the wrong tools. Use &lt;code&gt;valgrind&lt;/code&gt; or language-native debuggers instead. If you never review AI-generated code, sanitizers provide a false sense of safety. They are a net, not a babysitter. And if your project already has a full CI matrix with multiple architectures, a single free server adds little beyond convenience.&lt;/p&gt;

&lt;p&gt;For a solo developer or a small team on a tight budget, the combination of free model access and a free server creates a practical testing loop. The bug in this article would have survived local testing for weeks. It died on the first remote run.&lt;/p&gt;

&lt;p&gt;Try free models for generation, but verify every lifetime decision with a real environment. Dangling references do not care how much you paid for the advice.&lt;/p&gt;

&lt;p&gt;If you want to reproduce the crash yourself, grab the broken version above, point it at a free server, and run ASan. The evidence will speak for itself.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>ai</category>
      <category>testing</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Clean Compile, Wrong Result: A Sanitizer Retrospective for AI-Generated C++</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Sat, 29 Aug 2026 10:23:21 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/clean-compile-wrong-result-a-sanitizer-retrospective-for-ai-generated-c-18b9</link>
      <guid>https://dev.to/datacpp_3670/clean-compile-wrong-result-a-sanitizer-retrospective-for-ai-generated-c-18b9</guid>
      <description>&lt;p&gt;The AI coding boom created a new bottleneck. Not writing code. Reviewing it. Everyone is a reviewer now. Nobody knows what to check. &lt;/p&gt;

&lt;p&gt;Here's the dirty secret: most AI-generated code is semantically wrong in subtle ways. The compiler won't tell you. Unit tests won't tell you. Only a sanitizer will.&lt;/p&gt;

&lt;p&gt;This post walks through a synthetic but realistic example. You'll see a function that compiles clean, passes naive tests, and still returns garbage. You'll learn a reusable sanitizer loop to catch such bugs. And you can run the whole loop on MonkeyCode's free server option.&lt;/p&gt;

&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;

&lt;h2&gt;
  
  
  The symptom
&lt;/h2&gt;

&lt;p&gt;A function computes the average of two integers. It compiles. It passes the simple test. It returns nonsense for numbers near &lt;code&gt;INT_MAX&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;average&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You've seen this pattern. It appears in tutorials. It appears in old stack overflow answers. It is wrong.&lt;/p&gt;

&lt;p&gt;Signed integer overflow is undefined behavior. C++ promises nothing after that. The compiler may assume it never happens. Then it optimizes based on that lie.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproducing the failure
&lt;/h2&gt;

&lt;p&gt;Here's a minimal test program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;average&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2147483647&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2147483647&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;average&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile with &lt;code&gt;-O2&lt;/code&gt;. Run it. What do you see?&lt;/p&gt;

&lt;p&gt;On most platforms you get &lt;code&gt;-1&lt;/code&gt;. The addition wraps around to &lt;code&gt;-2&lt;/code&gt;. Then &lt;code&gt;-2 / 2&lt;/code&gt; is &lt;code&gt;-1&lt;/code&gt;. The expected answer is &lt;code&gt;2147483647&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Why did unit tests miss it? They used small numbers. The failure only appears at the boundary. Classic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The root cause
&lt;/h2&gt;

&lt;p&gt;The root cause is not "bad code". It's the assumption that addition always works. In C++, integer overflow is a minefield.&lt;/p&gt;

&lt;p&gt;The safe fix is &lt;code&gt;std::midpoint&lt;/code&gt;, added in C++20 for exactly this reason.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;numeric&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;average&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;midpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;std::midpoint&lt;/code&gt; handles overflow and negative numbers correctly. No undefined behavior anywhere.&lt;/p&gt;

&lt;p&gt;But here's the real question: would you trust that fix? Would your AI assistant even suggest it? Verification beats trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reusable debugging loop
&lt;/h2&gt;

&lt;p&gt;Sanitizers are the mechanical witness your code review needs. Here's the process I recommend for every AI-generated numeric snippet.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Compile with UBSan
&lt;/h3&gt;

&lt;p&gt;UndefinedBehaviorSanitizer catches overflow, null dereferences, and misaligned access.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;undefined &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O1&lt;/span&gt; main.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; main_ubsan
./main_ubsan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the buggy code you get a clear diagnostic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact values may vary by compiler. The message is still decisive: undefined behavior happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add AddressSanitizer
&lt;/h3&gt;

&lt;p&gt;Memory bugs are a different family. Use &lt;code&gt;-fsanitize=address&lt;/code&gt; too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address,undefined &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-O1&lt;/span&gt; main.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; main_san
&lt;span class="nv"&gt;ASAN_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;detect_leaks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ./main_san
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both sanitizers work in the same binary. They catch different bug classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Test multiple optimization levels
&lt;/h3&gt;

&lt;p&gt;Undefined behavior often appears only at &lt;code&gt;-O2&lt;/code&gt; or &lt;code&gt;-O3&lt;/code&gt;. The optimizer can legally do wild things with UB. So test every level.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for &lt;/span&gt;opt &lt;span class="k"&gt;in &lt;/span&gt;0 1 2 3&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;g++ &lt;span class="nt"&gt;-O&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;undefined &lt;span class="nt"&gt;-g&lt;/span&gt; main.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; main_&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Optimization level &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:"&lt;/span&gt;
    ./main_&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;opt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"  -&amp;gt; Failed"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes the program passes at &lt;code&gt;-O0&lt;/code&gt; and fails at &lt;code&gt;-O2&lt;/code&gt;. That inconsistency is a huge clue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters for AI-generated code
&lt;/h2&gt;

&lt;p&gt;You didn't write that code. You don't know its hidden assumptions. The AI might have mixed two idioms. It might have dropped a cast. It might have assumed two's complement without saying so.&lt;/p&gt;

&lt;p&gt;Human code review alone is not enough. Subtle UB slips past even experienced eyes. Sanitizers turn "maybe it's broken" into "here is the exact line".&lt;/p&gt;

&lt;p&gt;No persuasion. No arguments. Just a runtime error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the loop on MonkeyCode's free server
&lt;/h2&gt;

&lt;p&gt;MonkeyCode is an open-source project with a free tier. It offers free model access and a free server option.&lt;/p&gt;

&lt;p&gt;That combination is interesting for this workflow. You paste your AI-generated snippet into a fresh environment. You run the sanitizer loop. You get a verdict. There is no local setup debt and no cost barrier.&lt;/p&gt;

&lt;p&gt;The free model can also suggest edge-case tests. But don't trust its suggestions blindly. The sanitizer doesn't care about tone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;Sanitizers are not magic. They only detect what they instrument. They miss pure logic errors like "wrong formula, no overflow". They miss performance regressions. They add runtime overhead.&lt;/p&gt;

&lt;p&gt;Don't ship sanitizer binaries. Run them in CI or in a disposable sandbox. Keep your production builds clean and fast.&lt;/p&gt;

&lt;p&gt;Also, &lt;code&gt;std::midpoint&lt;/code&gt; is not a universal fix. Floating-point code has its own dragons. But you will catch the obvious UB.&lt;/p&gt;

&lt;h2&gt;
  
  
  Should you adopt this?
&lt;/h2&gt;

&lt;p&gt;If you write C++ by hand, yes. If you rely on AI assistants for numeric code, absolutely yes. If your program processes user-controlled input, double yes.&lt;/p&gt;

&lt;p&gt;The cost is a few seconds of compile time. The benefit is catching a bug that would have cost you hours later.&lt;/p&gt;

&lt;p&gt;Start with one function. Run the sanitizer loop. Fix every warning until clean. Then expand to the whole file.&lt;/p&gt;

&lt;h2&gt;
  
  
  The parting thought
&lt;/h2&gt;

&lt;p&gt;AI won't replace developers. But AI will keep generating bugs that look like correct code. The only defense is a boring, repeatable verification path.&lt;/p&gt;

&lt;p&gt;Compile clean? Fine. Tests pass? Fine. Show me a clean sanitizer report. That's the standard we need.&lt;/p&gt;

&lt;p&gt;Try MonkeyCode's free tier for your next C++ experiment. The server is free. The token grant is generous. The bugs it catches can be priceless.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>debugging</category>
      <category>ai</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>The 3% Drop That Only Showed Up on a Clean Server: A Debugging Retrospective</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Fri, 28 Aug 2026 03:51:57 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/the-3-drop-that-only-showed-up-on-a-clean-server-a-debugging-retrospective-1g3c</link>
      <guid>https://dev.to/datacpp_3670/the-3-drop-that-only-showed-up-on-a-clean-server-a-debugging-retrospective-1g3c</guid>
      <description>&lt;p&gt;My forwarder lost 3% of its messages. My laptop reported zero. CI reported zero. Staging lost thousands every hour.&lt;/p&gt;

&lt;p&gt;I blamed the network. I blamed the VM. I blamed everything except my read loop.&lt;/p&gt;

&lt;p&gt;This is the retrospective: one wrong assumption, three counters, a twelve-line fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Symptom
&lt;/h2&gt;

&lt;p&gt;The service was a small TCP forwarder. Accept a connection, read text lines, forward them. Nothing exotic.&lt;/p&gt;

&lt;p&gt;Staging showed the loss: 97,004 lines in, 94,183 lines out. No errors. No exceptions. Just missing messages.&lt;/p&gt;

&lt;p&gt;Replays on my laptop always passed. 100,000 lines in, 100,000 lines out.&lt;/p&gt;

&lt;p&gt;That mismatch is the first clue. I was not testing what production actually did.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When a bug only lives in one environment, do you fix the environment first? Or the assumption your tests never stressed?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1: Reproduce Outside Your Laptop
&lt;/h2&gt;

&lt;p&gt;Before touching code, I changed only the machine. Same binary, same load script, same counters.&lt;/p&gt;

&lt;p&gt;I started a fresh server from the free server option of MonkeyCode, an open source AI coding project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The loss reappeared. 100,000 lines in, 97,128 lines out. The environment changed the probability, not the existence of the bug.&lt;/p&gt;

&lt;p&gt;A second machine is a microscope for timing bugs. A fresh one has no history and no bias.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Count, Don't Log
&lt;/h2&gt;

&lt;p&gt;Logs tell stories. Counters add up. I placed a counter at every layer.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Client counts lines sent.&lt;/li&gt;
&lt;li&gt;Server counts newlines parsed.&lt;/li&gt;
&lt;li&gt;Server counts replies written.&lt;/li&gt;
&lt;li&gt;Client counts replies received.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Run once, compare four numbers. The gap between them names the losing layer.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Counter gap&lt;/th&gt;
&lt;th&gt;Suspect&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;parsed &amp;lt; sent&lt;/td&gt;
&lt;td&gt;read loop or buffer size&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;replies &amp;lt; parsed&lt;/td&gt;
&lt;td&gt;reply logic (this bug)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;received &amp;lt; replies&lt;/td&gt;
&lt;td&gt;client read logic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The clean-server run was loud: sent 100,000, parsed 100,000, replies 99,987, received 99,987.&lt;/p&gt;

&lt;p&gt;The server parsed everything. It just did not reply enough. That gap is the fingerprint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The Reproducer
&lt;/h2&gt;

&lt;p&gt;Smallest code that fails. One socket, one buffer, no frameworks.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;load.py&lt;/code&gt; - burst mode, no waiting between sends:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# load.py - burst mode. No waiting between sends.
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;

&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100_000&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_connection&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;127.0.0.1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;settimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;acks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PING&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;acks&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;65536&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="n"&gt;acks&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;b&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;TimeoutError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sent=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; acks=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;acks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; lost=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;acks&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;bad_server.cpp&lt;/code&gt; - one reply per read, not per line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// bad_server.cpp - one reply per read, not per line.&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;listen_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOL_SOCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SO_REUSEADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INADDR_ANY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;replies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;nullptr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(;;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ok&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// one reply per read, not per line&lt;/span&gt;
      &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"parsed=%ld replies=%ld&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;replies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look at the reply line. One read can return many lines.&lt;/p&gt;

&lt;p&gt;TCP is a byte stream, not a message queue. &lt;code&gt;read()&lt;/code&gt; has no idea what a PING is. The kernel may merge ten messages into one segment, and one read consumes all ten.&lt;/p&gt;

&lt;p&gt;My polite local test sent one PING, waited for the ack, sent the next. One message per segment. The bug stayed asleep.&lt;/p&gt;

&lt;p&gt;The staging load was a burst. Thousands of messages per second, batching inside the kernel. One read swallowed a hundred lines, the server answered once.&lt;/p&gt;

&lt;p&gt;Test shape decides which bugs survive. Polite tests hide pipelining bugs. Burst tests expose them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Fix the Boundary, Not the Byte
&lt;/h2&gt;

&lt;p&gt;The small fix replies per newline instead of per read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ok&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The robust fix also survives a line split across two reads. That is the other half of the same bug family.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;ssize_t&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kt"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;npos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;erase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ok&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the fix, both environments produced identical numbers. sent == parsed == replied == received.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Would Do Differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Change one variable at a time. In the first hour I changed the binary, the server, and the load. Wasteful.&lt;/li&gt;
&lt;li&gt;Write the burst test first. The polite test validated my hope, not the system.&lt;/li&gt;
&lt;li&gt;Audit syscall contracts with a second pair of eyes. I asked MonkeyCode's free model access to review the read loop. It flagged the one-reply-per-read pattern and pointed me to &lt;code&gt;man 2 read&lt;/code&gt;. The man page says: "read() attempts to read up to count bytes." It never promises one message. Verify that claim at &lt;a href="https://man7.org/linux/man-pages/man2/read.2.html" rel="noopener noreferrer"&gt;man7.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This workflow targets timing and batching bugs. Data bugs need property-based tests, not a second machine.&lt;/p&gt;

&lt;p&gt;Free servers are run-to-failure tools, not persistent hosts. Do not store state there, do not run compliance workloads, and do not benchmark the server itself. Use one for a clean slate and one reproduction.&lt;/p&gt;

&lt;p&gt;The fix changed reply counts, not throughput. Measure both after touching a read loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Your local test is not your load test. Your laptop is not your server. One read is not one message.&lt;/p&gt;

&lt;p&gt;Start your next local-only bug with a burst client and a second machine. Then count at every layer.&lt;/p&gt;

&lt;p&gt;The counters know the truth. Listen to them.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>debugging</category>
      <category>tcp</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Fix That Passed Review and Crashed in Release</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Wed, 26 Aug 2026 11:18:02 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/the-fix-that-passed-review-and-crashed-in-release-j1b</link>
      <guid>https://dev.to/datacpp_3670/the-fix-that-passed-review-and-crashed-in-release-j1b</guid>
      <description>&lt;p&gt;The fix passed review. It still crashed in release. The reviewer was never tested.&lt;/p&gt;

&lt;p&gt;The reviewer was me. And an AI model. We both approved the same wrong patch.&lt;/p&gt;

&lt;p&gt;This is the retrospective. Symptom, root cause, fix. Plus the debugging loop that actually caught it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Symptom
&lt;/h2&gt;

&lt;p&gt;A small C++ worker pool returned garbage. Not always. Only with &lt;code&gt;-O2&lt;/code&gt;. Only after a few thousand tasks.&lt;/p&gt;

&lt;p&gt;That is the classic undefined behavior profile. The code looks innocent. The compiler does something legal. Your program does something insane.&lt;/p&gt;

&lt;p&gt;Here is the minimal shape of the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;future&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Debug build? Fine. Release build? Random numbers. Sometimes a segfault. Sometimes silence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Suspect
&lt;/h2&gt;

&lt;p&gt;My first instinct: data race. The queue is shared. Threads are racing. Add a mutex.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;lock_guard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;mutex&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The patch compiled. The patch passed review. The garbage stayed.&lt;/p&gt;

&lt;p&gt;Why did it look right? Because the symptom matched the story. Intermittent. Load-dependent. Multi-threaded. Every checkbox said "race."&lt;/p&gt;

&lt;p&gt;Checkboxes lie. Symptoms are not causes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AI's Second Opinion
&lt;/h2&gt;

&lt;p&gt;I asked a free model on MonkeyCode's free server to review the same snippet. MonkeyCode is an open-source AI coding tool. Its current free tier includes model access, a server option, and ten million tokens. (Disclosure: This article was prepared as part of MonkeyCode's product outreach.)&lt;/p&gt;

&lt;p&gt;The model agreed with me. "Add synchronization," it said. Same wrong answer, delivered faster.&lt;/p&gt;

&lt;p&gt;That is the moment I stopped trusting reviews. My own included. The AI's included.&lt;/p&gt;

&lt;p&gt;A review is an opinion. A test is evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Turn: Reproduce on a Clean Box
&lt;/h2&gt;

&lt;p&gt;I moved the reproducer to a disposable environment. The free server worked for this. Clean tools, clean state, no "works on my machine."&lt;/p&gt;

&lt;p&gt;Then I minimized. I stripped the worker pool down to the loop above. It still failed.&lt;/p&gt;

&lt;p&gt;Then I ran sanitizers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address,undefined repro.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; repro
./repro
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Reading the Sanitizer Output
&lt;/h2&gt;

&lt;p&gt;The output named the exact line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: AddressSanitizer: stack-use-after-scope
    #0 in main::$_0::operator()() const repro.cpp:9
    #1 in std::__invoke_impl ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;stack-use-after-scope&lt;/code&gt;. The lambda captured &lt;code&gt;local&lt;/code&gt; by reference. The local died at the end of each loop iteration. The async task ran after that. Dangling reference. Undefined behavior.&lt;/p&gt;

&lt;p&gt;The mutex changed locking. The bug was a lifetime.&lt;/p&gt;

&lt;p&gt;Two different layers. Two different fixes. Only one of them mattered.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Fix
&lt;/h2&gt;

&lt;p&gt;Capture by value. One word changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;launch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;local&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address,undefined repro.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; repro
./repro
&lt;span class="c"&gt;# 11, 21, 31, 41 — stable across 10,000 runs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sanitizer clean. Release build clean. The reproducer became a regression test.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Reusable Debugging Loop
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Reproduce on a clean box. Your laptop has too much state.&lt;/li&gt;
&lt;li&gt;Minimize until the code fits one screen. Small code fails loudly.&lt;/li&gt;
&lt;li&gt;Run ASan and UBSan before you blame threads. Lifetime bugs masquerade as races.&lt;/li&gt;
&lt;li&gt;Ask the AI for a second opinion. Then test that opinion like any other.&lt;/li&gt;
&lt;li&gt;Check lifetimes before you add locks. Locks fix contention, not dangling references.&lt;/li&gt;
&lt;li&gt;Keep the reproducer. It is your regression test.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This approach needs a compiler with sanitizer support. Embedded toolchains often lack it. No sanitizers, no shortcut.&lt;/p&gt;

&lt;p&gt;It also needs a reproducible bug. Heisenbugs under TSan need a different loop. So do races inside third-party binaries you cannot rebuild.&lt;/p&gt;

&lt;p&gt;And the free server is for disposable experiments. Not production workloads. Not sensitive data. Treat it like a scratch box, not a datacenter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;AI turned developers into reviewers. But who reviews the reviewer? Run the experiment. That is the review.&lt;/p&gt;

&lt;p&gt;Next time a patch passes review, run it on a clean box first. The free server is a decent place to start. Ten million tokens and one free server are enough for an honest reproducer.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>debugging</category>
      <category>ai</category>
      <category>testing</category>
    </item>
    <item>
      <title>Free Tokens, Paid Verification: A Cost-Per-Compile Gauntlet for MonkeyCode's Free Tier</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Tue, 25 Aug 2026 05:04:00 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/free-tokens-paid-verification-a-cost-per-compile-gauntlet-for-monkeycodes-free-tier-2m22</link>
      <guid>https://dev.to/datacpp_3670/free-tokens-paid-verification-a-cost-per-compile-gauntlet-for-monkeycodes-free-tier-2m22</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endraw'&lt;/p&gt;
</description>
      <category>c</category>
      <category>ai</category>
      <category>testing</category>
      <category>llm</category>
    </item>
    <item>
      <title>The Coverage Loop: Turning Free AI Tokens into Verified C++ Tests</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Sun, 23 Aug 2026 17:11:55 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/the-coverage-loop-turning-free-ai-tokens-into-verified-c-tests-1jh5</link>
      <guid>https://dev.to/datacpp_3670/the-coverage-loop-turning-free-ai-tokens-into-verified-c-tests-1jh5</guid>
      <description>&lt;p&gt;Unit tests are boring. Coverage is not optional.&lt;br&gt;
I asked a free AI model to write my tests. It failed. Then I built a feedback loop.&lt;br&gt;
Here is the result: a reproducible pipeline that turns free tokens into measured coverage.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why Generated Tests Miss Everything
&lt;/h2&gt;

&lt;p&gt;Models guess. They do not know your intent.&lt;br&gt;
A test that compiles is not a test that asserts. A test that asserts is not a test that covers.&lt;br&gt;
The fix is not a better prompt. The fix is a measurement loop.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Experiment
&lt;/h2&gt;

&lt;p&gt;MonkeyCode is an open-source AI coding tool. It offers free model access and a free server option.&lt;br&gt;
Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;br&gt;
I used its free tier for this experiment. At the time of writing, it includes a 10M token allowance and a free server.&lt;/p&gt;

&lt;p&gt;The target: a small C++ string utility.&lt;br&gt;
The goal: reach 90% line coverage with generated tests.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Loop
&lt;/h2&gt;

&lt;p&gt;Five steps. Each one is small.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send the header to the model. Ask for tests.&lt;/li&gt;
&lt;li&gt;Compile and run the tests.&lt;/li&gt;
&lt;li&gt;Run gcov. Get the coverage number.&lt;/li&gt;
&lt;li&gt;Feed the missing lines back to the model.&lt;/li&gt;
&lt;li&gt;Repeat until coverage plateaus.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the core script. It is simplified but runnable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;coverage_loop.py - generate C++ tests, measure coverage, iterate.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;BASE_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https://your-provider/v1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
&lt;span class="n"&gt;MODEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;free-model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Write a C++ test file for this header:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Current tests miss these lines: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="si"&gt;}{&lt;/span&gt;&lt;span class="nf"&gt;chr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;Add tests to cover them.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;BASE_URL&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                         &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
                         &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temperature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;choices&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;g++&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-std=c++17&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--coverage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-o&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;./tests&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;check&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;gcov&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-b&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;splitlines&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Lines executed&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;missing_lines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;12-15, 28-30&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;string_utils.h&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;hint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;lines &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;missing_lines&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
        &lt;span class="n"&gt;test_code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_tests&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test_string_utils.cpp&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_tests&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CalledProcessError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;compilation failed, retrying&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;iteration &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;coverage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;coverage&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;BASE_URL&lt;/code&gt;, &lt;code&gt;API_KEY&lt;/code&gt;, and &lt;code&gt;MODEL&lt;/code&gt; to your provider's values. Drop your header and source in the same directory. Run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python coverage_loop.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example Run
&lt;/h2&gt;

&lt;p&gt;One run produced this pattern. Your numbers will differ.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Iteration&lt;/th&gt;
&lt;th&gt;Coverage&lt;/th&gt;
&lt;th&gt;What changed&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;42%&lt;/td&gt;
&lt;td&gt;Tests compiled, missed edge cases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;71%&lt;/td&gt;
&lt;td&gt;Added empty-string tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;88%&lt;/td&gt;
&lt;td&gt;Added null-byte handling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;td&gt;Plateau, stopped&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The loop works. The model found obvious edge cases. Empty strings. Negative numbers.&lt;br&gt;
It missed stateful behavior. Two calls in sequence. That is where gcov saved me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the Loop Breaks
&lt;/h2&gt;

&lt;p&gt;Free servers rate-limit. I added retry logic. It still stuttered.&lt;br&gt;
The model generated uncompilable tests. I skipped them. That wastes tokens.&lt;br&gt;
Coverage is not correctness. A test can cover a line and assert nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Skip This
&lt;/h2&gt;

&lt;p&gt;Safety-critical code. Do not trust generated tests.&lt;br&gt;
Legacy code with hidden dependencies. The model will guess wrong.&lt;br&gt;
Teams without a CI runner. The loop needs automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Takeaway
&lt;/h2&gt;

&lt;p&gt;Free AI is not a test engineer. It is a test generator with a feedback loop.&lt;br&gt;
The loop turns tokens into coverage. Coverage tells you where to spend the next token.&lt;br&gt;
That is the real trick. Not more prompts. Better signals.&lt;br&gt;
Fork the script. Run it on your worst file. Tell me what breaks.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>testing</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Twenty Prompts, One Compiler: A Free AI Server's Failure Matrix</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Sat, 22 Aug 2026 15:03:58 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/twenty-prompts-one-compiler-a-free-ai-servers-failure-matrix-1973</link>
      <guid>https://dev.to/datacpp_3670/twenty-prompts-one-compiler-a-free-ai-servers-failure-matrix-1973</guid>
      <description>&lt;p&gt;Liquid syntax error: Unknown tag 'endraw'&lt;/p&gt;
</description>
      <category>ai</category>
      <category>cpp</category>
      <category>testing</category>
      <category>benchmark</category>
    </item>
    <item>
      <title>Free AI Servers Fail Quietly: A Reproducible Test for MonkeyCode's Free Tier</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Fri, 21 Aug 2026 13:25:35 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/free-ai-servers-fail-quietly-a-reproducible-test-for-monkeycodes-free-tier-112g</link>
      <guid>https://dev.to/datacpp_3670/free-ai-servers-fail-quietly-a-reproducible-test-for-monkeycodes-free-tier-112g</guid>
      <description>&lt;p&gt;Free AI servers fail quietly. Not with loud errors. With latency spikes and silent truncation. A 'free' badge tells you nothing about either. I needed numbers. So I built a reproducible test.&lt;/p&gt;

&lt;p&gt;One script. Five measurements. No vendor dashboard. This post gives you the harness, the failure modes, and the decision rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I stopped trusting free-tier badges
&lt;/h2&gt;

&lt;p&gt;The AI label debate is everywhere this week. Everyone argues about what counts as 'AI-assisted.' Almost nobody measures what the server actually delivers.&lt;/p&gt;

&lt;p&gt;That's backwards. A badge is a claim. A test is evidence. I trust evidence.&lt;/p&gt;

&lt;p&gt;Same discipline as my previous clean-room posts. Isolate the variable. Measure it. Report the numbers. No dashboard screenshots. No vibes.&lt;/p&gt;

&lt;p&gt;Why does this matter? Because your editor waits on the server. Every request becomes a network call. If the server is cold, your flow dies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm evaluating
&lt;/h2&gt;

&lt;p&gt;MonkeyCode is an open-source AI coding project. It offers free model access and a free server option. The current free allowance is 10 million tokens, as of this writing (August 2026).&lt;/p&gt;

&lt;p&gt;Quotas change. Servers move. That's exactly why you need a harness, not a screenshot.&lt;/p&gt;

&lt;p&gt;Important distinction: I'm not benchmarking model quality. I'm benchmarking the delivery system. Can the free server get tokens to you fast enough? Does it truncate? Those are availability questions. They come before quality questions.&lt;/p&gt;

&lt;p&gt;The free server is the interesting part. A free model is useless if the transport is flaky. So I tested the transport.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five signals
&lt;/h2&gt;

&lt;p&gt;Each signal catches a different failure mode.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cold-start latency&lt;/strong&gt; — first response after 60 seconds idle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-to-first-token&lt;/strong&gt; — how fast the stream starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Throughput&lt;/strong&gt; — tokens per second after the first token.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Truncation rate&lt;/strong&gt; — how often &lt;code&gt;finish_reason&lt;/code&gt; is &lt;code&gt;length&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task success&lt;/strong&gt; — did the output actually solve the prompt?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why five and not fifty? Because each signal maps to a decision. Latency tells you about the transport. Truncation tells you about context handling. Success tells you about the model.&lt;/p&gt;

&lt;p&gt;Five numbers. That's the whole experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The harness
&lt;/h2&gt;

&lt;p&gt;One Python file. It uses the OpenAI SDK with environment variables. Point it at your own endpoint.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;base_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MONKEYCODE_BASE_URL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;api_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MONKEYCODE_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;TASKS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Write a C++ function that parses a CSV line with quoted fields.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Explain RAII in three sentences.&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Refactor this to use unique_ptr: `T* p = new T();`&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MONKEYCODE_MODEL&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;first_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stop&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;first_token&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;first_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
        &lt;span class="n"&gt;delta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;delta&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;finish_reason&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;choices&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;finish_reason&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;perf_counter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;first_token_s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;total_s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;approx_tokens&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;finish&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TASKS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Task &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;run_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This assumes an OpenAI-compatible endpoint. That's the common pattern for coding assistants. If MonkeyCode documents a different SDK, swap the client and keep the measurements.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to run it
&lt;/h2&gt;

&lt;p&gt;Install the SDK first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;openai
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MONKEYCODE_BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'https://your-endpoint'&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MONKEYCODE_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-key'&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MONKEYCODE_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'your-model'&lt;/span&gt;
python harness.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then test the cold start.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;60
python harness.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compare the two runs. That gap is your cold-start penalty.&lt;/p&gt;

&lt;p&gt;Run each task three times. Take the median. Median beats average for noisy servers.&lt;/p&gt;

&lt;p&gt;Run it on a disposable cloud box. Clean environment, no background noise. Same reason I debug C++ crashes on throwaway machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scoring task success
&lt;/h2&gt;

&lt;p&gt;Each task needs a pass/fail check. Not a vibe check.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;CSV parser&lt;/strong&gt; — does it compile? Does it handle quoted commas?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAII explanation&lt;/strong&gt; — does it mention destructors? Does it mention ownership?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;unique_ptr refactor&lt;/strong&gt; — does it compile? Does it remove the raw &lt;code&gt;delete&lt;/code&gt;?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Score one point per check. Two out of three means the task passed. Write the checks before you run the test. Otherwise you'll rationalize bad output.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading the results
&lt;/h2&gt;

&lt;p&gt;Here are the thresholds I use. Your numbers will differ. That's the point.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;Good&lt;/th&gt;
&lt;th&gt;Warning&lt;/th&gt;
&lt;th&gt;Broken&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold start&lt;/td&gt;
&lt;td&gt;&amp;lt; 5s&lt;/td&gt;
&lt;td&gt;5–30s&lt;/td&gt;
&lt;td&gt;&amp;gt; 30s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First token&lt;/td&gt;
&lt;td&gt;&amp;lt; 2s&lt;/td&gt;
&lt;td&gt;2–10s&lt;/td&gt;
&lt;td&gt;&amp;gt; 10s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;&amp;gt; 30 tok/s&lt;/td&gt;
&lt;td&gt;10–30 tok/s&lt;/td&gt;
&lt;td&gt;&amp;lt; 10 tok/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Truncation&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;&amp;lt; 20%&lt;/td&gt;
&lt;td&gt;&amp;gt; 20%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task success&lt;/td&gt;
&lt;td&gt;&amp;gt; 90%&lt;/td&gt;
&lt;td&gt;70–90%&lt;/td&gt;
&lt;td&gt;&amp;lt; 70%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One rule dominates: truncation. A truncated answer looks complete. It isn't. If &lt;code&gt;finish&lt;/code&gt; says &lt;code&gt;length&lt;/code&gt;, the task failed.&lt;/p&gt;

&lt;p&gt;Interpretation example. If cold start is 25 seconds but first token is 1 second, the server is fine once warm. The problem is idle recycling. If truncation shows up on task three, your prompt is too long for the context window. Split the task.&lt;/p&gt;

&lt;p&gt;Don't chase perfect numbers. Chase stable ones. A server that gives 2 seconds every time beats one that gives 0.5 sometimes and 20 other times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the free tier breaks
&lt;/h2&gt;

&lt;p&gt;Free servers share resources. Expect contention during peak hours. Expect cold starts after idle. Expect truncation on long prompts.&lt;/p&gt;

&lt;p&gt;The failure modes, ranked by danger:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Silent truncation&lt;/strong&gt; — output stops at the limit. Looks complete. Isn't.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cold-start spikes&lt;/strong&gt; — first request after idle eats 30+ seconds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate limiting&lt;/strong&gt; — burst of requests triggers backoff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Budget burn&lt;/strong&gt; — long contexts drain the allowance fast.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Peak hours matter. My rule: test at 9am and 9pm. If the numbers swing wildly, plan batch jobs for off-peak.&lt;/p&gt;

&lt;p&gt;The 10M token allowance sounds huge. It is, for small tasks. But one long-context request can burn thousands of tokens. A batch of fifty can burn a week's budget. Treat it like real money.&lt;/p&gt;

&lt;p&gt;The worst failure is silent. The server hits the limit, stops, and returns a clean-looking response. My harness catches that. Manual testing probably won't.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision rules
&lt;/h2&gt;

&lt;p&gt;Use the free tier for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Boilerplate generation.&lt;/li&gt;
&lt;li&gt;Explaining unfamiliar code.&lt;/li&gt;
&lt;li&gt;Small single-file refactors.&lt;/li&gt;
&lt;li&gt;Learning and prototyping.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Skip it for:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Production code reviews.&lt;/li&gt;
&lt;li&gt;Long-context analysis.&lt;/li&gt;
&lt;li&gt;Batch processing at scale.&lt;/li&gt;
&lt;li&gt;Anything with a hard SLA.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The line is simple. If a failure costs you five minutes, the free tier is fine. If it costs you a deadline, it isn't.&lt;/p&gt;

&lt;p&gt;The free server is a dev-loop tool. Treat it like one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;If you need guaranteed latency, skip free tiers entirely. If your prompts routinely exceed the context window, measure before you commit. If you're shipping a product on an API, pay for an SLA.&lt;/p&gt;

&lt;p&gt;This harness has limits too. It tests one client, not concurrency. It doesn't cover multi-user load or regional routing. Those need a separate experiment.&lt;/p&gt;

&lt;h2&gt;
  
  
  The takeaway
&lt;/h2&gt;

&lt;p&gt;Free tiers are not bad. They're just unmeasured. Run the harness. Record the numbers. Then decide.&lt;/p&gt;

&lt;p&gt;If you want to try it, MonkeyCode's free model access and free server are open right now. Grab the harness above. Judge it yourself.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>testing</category>
      <category>opensource</category>
    </item>
    <item>
      <title>A Clean-Room Evaluation Loop for a Newly Released Model Like Minimax H3</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Fri, 14 Aug 2026 11:13:20 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/a-clean-room-evaluation-loop-for-a-newly-released-model-like-minimax-h3-385d</link>
      <guid>https://dev.to/datacpp_3670/a-clean-room-evaluation-loop-for-a-newly-released-model-like-minimax-h3-385d</guid>
      <description>&lt;p&gt;When a model such as Minimax H3 starts appearing in feeds, the immediate pressure is to paste credentials into a production-shaped notebook and start prompting. A more useful first move is to place the new model behind a small, inspectable evaluation loop on a disposable box. This article shows a reproducible harness for that loop. It treats the model as an HTTP service, keeps credentials out of the source tree, and records status, latency, and response shape for a fixed set of cases.&lt;/p&gt;

&lt;p&gt;The operator-supplied availability claims used here are that MonkeyCode offers free model access and a free server option. &lt;strong&gt;Disclosure: This article was prepared as part of MonkeyCode's product outreach.&lt;/strong&gt; The harness does not depend on MonkeyCode; it needs only an HTTP endpoint, a model identifier, and a bearer token.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the harness proves
&lt;/h2&gt;

&lt;p&gt;The harness proves three narrow things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the endpoint is reachable from a clean environment,&lt;/li&gt;
&lt;li&gt;a chat-style request returns a response within a timeout,&lt;/li&gt;
&lt;li&gt;the response shape is stable enough for a small set of deterministic prompts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It does not prove model quality, factual accuracy, safety, or production readiness. Those require separate evaluation data and review.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Provision a minimal box
&lt;/h2&gt;

&lt;p&gt;Use a fresh virtual machine or container. The commands below assume Debian or Ubuntu.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; build-essential libcurl4-openssl-dev jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A clean image matters because it removes leftover proxy settings, local models, and shell history from the comparison.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Keep secrets out of the code
&lt;/h2&gt;

&lt;p&gt;Create an environment file that is not committed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; .env &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
export EVAL_ENDPOINT="https://example.invalid/v1/chat/completions"
export EVAL_MODEL="model-identifier-provided-by-host"
export EVAL_API_KEY="replace-me"
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the free server exposes an OpenAI-style chat-completions route, set &lt;code&gt;EVAL_ENDPOINT&lt;/code&gt; to the full URL. If its API uses a different request shape, adjust the request builder in Step 3.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Add a request builder with curl and jq
&lt;/h2&gt;

&lt;p&gt;Save the following as &lt;code&gt;eval_harness.sh&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-euo&lt;/span&gt; pipefail

&lt;span class="nv"&gt;prompt_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;:?usage:&lt;span class="p"&gt; eval_harness prompt.txt&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EVAL_ENDPOINT&lt;/span&gt;:?set&lt;span class="p"&gt; EVAL_ENDPOINT&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EVAL_MODEL&lt;/span&gt;:?set&lt;span class="p"&gt; EVAL_MODEL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EVAL_API_KEY&lt;/span&gt;:?set&lt;span class="p"&gt; EVAL_API_KEY&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

jq &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; model &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--arg&lt;/span&gt; content &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$prompt_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s1"&gt;'{model:$model,messages:[{role:"user",content:$content}]}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; request.json

curl &lt;span class="nt"&gt;-sS&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; response.json &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'status=%{http_code} elapsed_s=%{time_total}\n'&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; @request.json &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$endpoint&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; transport.log

&lt;span class="nb"&gt;cat &lt;/span&gt;transport.log
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'--- response ---'&lt;/span&gt;
&lt;span class="nb"&gt;cat &lt;/span&gt;response.json
&lt;span class="nb"&gt;echo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make it executable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x eval_harness.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request body is assembled with &lt;code&gt;jq -n --arg&lt;/code&gt; so the prompt is JSON-escaped instead of being pasted into a string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Add a small C++ post-processor
&lt;/h2&gt;

&lt;p&gt;The shell harness prints &lt;code&gt;elapsed_s=&amp;lt;value&amp;gt;&lt;/code&gt;. A small C++ helper can extract that field from captured logs without depending on &lt;code&gt;awk&lt;/code&gt; or &lt;code&gt;grep&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cerr&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s"&gt;"usage: parse_elapsed result.log&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ifstream&lt;/span&gt; &lt;span class="nf"&gt;in&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;getline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rfind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"elapsed_s="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;cout&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sc"&gt;'\n'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;g++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-Wall&lt;/span&gt; &lt;span class="nt"&gt;-Wextra&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; parse_elapsed parse_elapsed.cpp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Run a fixed four-case plan
&lt;/h2&gt;

&lt;p&gt;Prompts are deliberately small and deterministic so a failure is easier to classify.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; echo_case.txt &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
Reply with exactly:
pong
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; code_case.txt &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
Write a C++ function that reads text from stdin and prints the reversed line order.
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; json_case.txt &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;'
Return exactly one JSON object with keys tool and version. No prose.
&lt;/span&gt;&lt;span class="no"&gt;EOF

&lt;/span&gt;&lt;span class="nb"&gt;yes&lt;/span&gt; &lt;span class="s2"&gt;"The quick brown fox jumps over the lazy dog."&lt;/span&gt; | &lt;span class="nb"&gt;head&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; 600 &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; long_case.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run each case and keep every artifact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;for case&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;code json long&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  ./eval_harness.sh &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;case&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_case.txt"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;"result_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;case&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.log"&lt;/span&gt; 2&amp;gt;&amp;amp;1 &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
  cp &lt;/span&gt;response.json &lt;span class="s2"&gt;"response_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;case&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.json"&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true
&lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Case&lt;/th&gt;
&lt;th&gt;What to check&lt;/th&gt;
&lt;th&gt;Pass&lt;/th&gt;
&lt;th&gt;Common failure signal&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;echo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Body contains &lt;code&gt;pong&lt;/code&gt; and no extra prose&lt;/td&gt;
&lt;td&gt;Deterministic reply&lt;/td&gt;
&lt;td&gt;Model ignores instruction or endpoint truncates output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Code block is present and plausibly compiles&lt;/td&gt;
&lt;td&gt;Extractable code&lt;/td&gt;
&lt;td&gt;Model returns prose only or misses closing fence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Body parses with &lt;code&gt;jq&lt;/code&gt; as one object&lt;/td&gt;
&lt;td&gt;Valid JSON&lt;/td&gt;
&lt;td&gt;Extra prose or escaped JSON&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;long&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP 200 within the timeout and non-empty body&lt;/td&gt;
&lt;td&gt;Stable shape&lt;/td&gt;
&lt;td&gt;Context rejection or timeout&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Check the JSON case with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;jq &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'.choices[0].message.content'&lt;/span&gt; response_json.json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"response field present"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Compare against a local baseline when possible
&lt;/h2&gt;

&lt;p&gt;The same prompts can run against a local model to separate provider behavior from model behavior.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Local model&lt;/th&gt;
&lt;th&gt;Free HTTP endpoint&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Setup cost&lt;/td&gt;
&lt;td&gt;Model download, CPU/RAM limits&lt;/td&gt;
&lt;td&gt;Endpoint and token only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reproducibility&lt;/td&gt;
&lt;td&gt;High if hardware is recorded&lt;/td&gt;
&lt;td&gt;High if endpoint and model identifier are recorded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data control&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Best use&lt;/td&gt;
&lt;td&gt;Offline, private, or repeated runs&lt;/td&gt;
&lt;td&gt;Quick availability and shape checks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This table compares categories only. It does not assert specific MonkeyCode quotas, hardware, duration, or performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;The operator-supplied claims are limited to free model access and a free server option. This article does not assert model names, quotas, hardware, duration, performance, or permanence. The request builder assumes an OpenAI-style chat-completions payload; other APIs need a small modification in the &lt;code&gt;jq&lt;/code&gt; construction and headers.&lt;/p&gt;

&lt;p&gt;The four-case plan is a smoke test. It does not rank models, measure accuracy, or test failure modes such as refusal, factual errors, or unsafe output. A model can pass all four cases and still be the wrong tool for a production task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who should not use this approach
&lt;/h2&gt;

&lt;p&gt;Use a separate method when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;latency percentiles under load are the decision,&lt;/li&gt;
&lt;li&gt;data residency or legal review is required,&lt;/li&gt;
&lt;li&gt;the endpoint must meet a production SLA,&lt;/li&gt;
&lt;li&gt;the task requires a rigorous model-evaluation benchmark.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The open-source spirit is the reusable part
&lt;/h2&gt;

&lt;p&gt;A free endpoint is convenient, but the more durable open-source value is the harness itself. Keeping the runner to one shell script, one small C++ parser, and one environment file lets another developer repeat the same four cases against a different model without trusting the first conclusion. That reproducibility, not a product badge, is the useful part of the open-source habit.&lt;/p&gt;

&lt;p&gt;The same harness can be pointed at the free server by changing one environment variable. The value remains if the free option disappears because the test plan and code do not depend on a single vendor.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>ai</category>
      <category>tutorial</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why Your C++ Crash Skips Your Laptop: A Clean-Room Debugging Loop on a Disposable Box</title>
      <dc:creator>Morgan Ma</dc:creator>
      <pubDate>Mon, 10 Aug 2026 08:20:13 +0000</pubDate>
      <link>https://dev.to/datacpp_3670/why-your-c-crash-skips-your-laptop-a-clean-room-debugging-loop-on-a-disposable-box-35p2</link>
      <guid>https://dev.to/datacpp_3670/why-your-c-crash-skips-your-laptop-a-clean-room-debugging-loop-on-a-disposable-box-35p2</guid>
      <description>&lt;p&gt;Our CI pipeline failed last Tuesday with a segfault that nobody on the team could reproduce locally. Three developers, three different machines, zero crashes. The binary only fell over on the Linux runner, in release mode, after the cache was warm. That class of failure — environment-dependent memory corruption — is exactly why I stopped debugging C++ crashes on my own hardware and moved the whole loop onto a fresh, discardable server.&lt;/p&gt;

&lt;p&gt;Below is the playbook I now follow: a small program that misbehaves silently on one machine and loudly on another, a short guide for matching sanitizers to symptoms, and the exact loop I run. I'll also cover how I use an AI assistant with free model access during diagnosis, and the places where I refuse to let it drive.&lt;/p&gt;

&lt;h2&gt;
  
  
  A program that lies to you on your dev machine
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;crashme.cpp&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdio&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;make_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;            &lt;span class="c1"&gt;// handing back a pointer into a dead stack frame&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                  &lt;span class="c1"&gt;// caller keeps using the pointer afterward&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;make_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;41&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"counter = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// reading reclaimed stack memory&lt;/span&gt;

    &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;static_cast&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;malloc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;               &lt;span class="c1"&gt;// freeing the same allocation twice&lt;/span&gt;

    &lt;span class="n"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"survived"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Compile it on a typical desktop with default flags and there's a decent chance it prints &lt;code&gt;counter = 42&lt;/code&gt; followed by &lt;code&gt;survived&lt;/code&gt; and exits cleanly. Two genuine undefined-behavior bugs, no complaint. Ship that confidence to production and the crash arrives later, in a worse place, with a paying customer attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  The case for a clean room
&lt;/h2&gt;

&lt;p&gt;Allocator behavior, compiler defaults, glibc version, optimization level — all of these shift whether a memory bug surfaces. Your workstation is not CI, and CI is not production. The practical answer is to debug inside an environment you build from scratch for each investigation and throw away afterward, configured to mirror the failing target.&lt;/p&gt;

&lt;p&gt;For this kind of throwaway environment I've been using a free server instance from MonkeyCode, spun up when a bug report lands and deleted when the fix is merged. Disclosure: This article was prepared as part of MonkeyCode's product outreach. Nothing in the workflow depends on that specific provider — a local container, a spare VM, or any budget VPS behaves the same. What matters is that the environment starts empty and costs you nothing to reset, so "reproduce from zero" becomes reflex rather than a favor you owe your infrastructure team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Match the instrument to the symptom
&lt;/h2&gt;

&lt;p&gt;The most common mistake I see is reaching for the same tool regardless of the failure. A quick mapping saves hours:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you're observing&lt;/th&gt;
&lt;th&gt;Reach for&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Writes past an allocation, stale pointer use&lt;/td&gt;
&lt;td&gt;AddressSanitizer&lt;/td&gt;
&lt;td&gt;Pinpoints the exact line with allocation history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Garbage values that change between runs&lt;/td&gt;
&lt;td&gt;MemorySanitizer&lt;/td&gt;
&lt;td&gt;Catches uninitialized reads ASan ignores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intermittent crash under concurrency&lt;/td&gt;
&lt;td&gt;ThreadSanitizer&lt;/td&gt;
&lt;td&gt;Detects races via happens-before analysis&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Third-party binary you cannot recompile&lt;/td&gt;
&lt;td&gt;Valgrind&lt;/td&gt;
&lt;td&gt;Works on the existing binary, at a heavy slowdown&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A core file and nothing else&lt;/td&gt;
&lt;td&gt;gdb&lt;/td&gt;
&lt;td&gt;Post-mortem is the only option left&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One caveat that bites people: you cannot combine sanitizers in a single build, so plan for several compile-and-run passes when the symptom is ambiguous.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loop, start to finish
&lt;/h2&gt;

&lt;p&gt;On the fresh box:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Pin the compiler so today's run is comparable to next week's&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; clang gdb

&lt;span class="c"&gt;# Keep optimization enabled. Bugs that evaporate at -O0 are real,&lt;/span&gt;
&lt;span class="c"&gt;# and debugging a binary that differs from the failing one wastes time.&lt;/span&gt;
clang++ &lt;span class="nt"&gt;-std&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;c++17 &lt;span class="nt"&gt;-O2&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="nt"&gt;-fsanitize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address,undefined &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-fsanitize-recover&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;address crashme.cpp &lt;span class="nt"&gt;-o&lt;/span&gt; crashme_asan

&lt;span class="c"&gt;# Execute and keep the report&lt;/span&gt;
&lt;span class="nv"&gt;ASAN_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;detect_stack_use_after_return&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 ./crashme_asan 2&amp;gt;&amp;amp;1 | &lt;span class="nb"&gt;tee &lt;/span&gt;report.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Against &lt;code&gt;crashme.cpp&lt;/code&gt;, this flags the returned-stack-pointer read inside &lt;code&gt;main&lt;/code&gt; and the double free from &lt;code&gt;release&lt;/code&gt;, each with the stack trace of the original allocation. From an empty server to a complete diagnosis, the whole thing takes minutes, and most of that is package installation.&lt;/p&gt;

&lt;p&gt;The fixes themselves are straightforward: &lt;code&gt;make_counter&lt;/code&gt; should take ownership seriously — return by value, a &lt;code&gt;std::unique_ptr&amp;lt;int&amp;gt;&lt;/code&gt;, or write into a caller-supplied reference — and &lt;code&gt;release&lt;/code&gt; should null out the caller's pointer (or better, take a &lt;code&gt;std::unique_ptr&lt;/code&gt; so the double free becomes unrepresentable).&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the AI assistant actually helps
&lt;/h2&gt;

&lt;p&gt;As disclosed above, this article is part of MonkeyCode's product outreach, and I used its free model access for two narrow tasks in this loop:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Translating sanitizer output into a hypothesis.&lt;/strong&gt; I paste the ASan trace alongside the implicated function and ask the model to rank plausible causes. It reliably converts &lt;code&gt;stack-use-after-return in make_counter&lt;/code&gt; into plain language faster than a junior teammate can. What it cannot do is judge which repair is safe for your codebase's ownership conventions — that call stays human.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sketching the regression test.&lt;/strong&gt; After the root cause is confirmed, I ask for a test that reproduces the failure pre-fix and goes green post-fix. Then I read every line before it enters the repo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notice what the model is doing here: reading and drafting. Verification remains mechanical — rerun the sanitizer, watch it go quiet, and only then trust the patch. The instrument is the authority; the assistant is a fast second pair of eyes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this breaks down
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Instrumentation perturbs the binary. Sanitizers rearrange memory layout, and a bug can relocate or disappear under observation. When that happens you're back to Valgrind or post-mortem debugging.&lt;/li&gt;
&lt;li&gt;Free server tiers come with no guarantees about quota, uptime, or hardware specs. Treat them as scratch space, never as something your release pipeline depends on.&lt;/li&gt;
&lt;li&gt;Never feed proprietary source or production secrets into a third-party AI tool without explicit clearance from your security policy. A redacted minimal reproducer — like the one above — is usually all the model needs anyway.&lt;/li&gt;
&lt;li&gt;AI-proposed memory fixes often patch the crash site instead of the root cause. Accepting one without a sanitizer re-run is how bugs get closed and reopened.&lt;/li&gt;
&lt;li&gt;Kernel modules, bare-metal targets, and latency-critical paths where instrumentation is impossible need a different playbook entirely.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The transferable habit isn't any single flag or tool — it's refusing to debug memory corruption in an environment you can't fully control. Rebuild the failing context on a disposable machine, instrument for the symptom you actually have, and let AI handle the reading and drafting while the sanitizer decides what's true. If you'd like a zero-cost way to try this without touching your own infrastructure, MonkeyCode's free server and model access is one option — though a local Docker image gives you the same reproducibility guarantees.&lt;/p&gt;

&lt;p&gt;When a crash refuses to reproduce anywhere except production, what's your first move? I'd genuinely like to compare notes with other C++ developers on how they triage environment-specific failures.&lt;/p&gt;

</description>
      <category>cpp</category>
      <category>debugging</category>
      <category>programming</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
