<?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: beTheNoob</title>
    <description>The latest articles on DEV Community by beTheNoob (@bethenoob).</description>
    <link>https://dev.to/bethenoob</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%2F3707529%2Fec1809ad-f9b0-409b-96b6-4b58aeaafc29.png</url>
      <title>DEV Community: beTheNoob</title>
      <link>https://dev.to/bethenoob</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bethenoob"/>
    <language>en</language>
    <item>
      <title>I Ported cJSON to Rust, and My Own Test Suite Lied to My Face</title>
      <dc:creator>beTheNoob</dc:creator>
      <pubDate>Fri, 07 Aug 2026 06:22:02 +0000</pubDate>
      <link>https://dev.to/bethenoob/i-ported-cjson-to-rust-and-my-own-test-suite-lied-to-my-face-534o</link>
      <guid>https://dev.to/bethenoob/i-ported-cjson-to-rust-and-my-own-test-suite-lied-to-my-face-534o</guid>
      <description>&lt;p&gt;I did a dumb thing on purpose: took a real, 8-year-old, still-in-production C library — &lt;a href="https://github.com/DaveGamble/cJSON" rel="noopener noreferrer"&gt;cJSON&lt;/a&gt; — and rewrote it in Rust. Not "inspired by." A &lt;em&gt;port&lt;/em&gt;. Same test suite, same weird edge cases, same bugs if I wasn't careful.&lt;/p&gt;

&lt;p&gt;This was for &lt;strong&gt;Port Mortem&lt;/strong&gt;, a hackathon whose entire personality is "prove it, don't just say it." You take the &lt;em&gt;original&lt;/em&gt; test suite — hashed at kickoff so you can't sneak-edit it later — and make it pass against your rewrite, untouched. One edited test file = automatic zero. No vibes-based grading.&lt;/p&gt;

&lt;p&gt;So here's the honest version: four real bugs, one unsafe block I genuinely couldn't remove, and a benchmark where C beat me and I'm not hiding it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's cJSON and why bother
&lt;/h2&gt;

&lt;p&gt;A small, zero-dependency C library that parses/prints JSON, ~2,500 lines, used everywhere from embedded firmware to random C tools. It manages its own tree with raw pointers and hand-rolls its own growable print buffer — exactly the kind of code where "just rewrite it safely" sounds easy until you try. Bonus: it has a real, disclosed CVE, &lt;strong&gt;CVE-2025-57052 (CVSS 9.8)&lt;/strong&gt; — so I wasn't just porting code, I was porting a bug on purpose, then un-porting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Original C headers get SHA-256 hashed at kickoff, never touched again. My Rust compiles to the exact same C ABI, so the original C test suite (Unity framework) links straight against my Rust binary with no idea it's not talking to C. One wrinkle: 13 of 20 original test files call cJSON's &lt;em&gt;internal&lt;/em&gt; (non-public) functions directly — I handled that with a thin C shim (not hashed/pinned) that just forwards to the real ported logic. Not a mock, same logic, just re-exposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bug #1: CI said "100% passed." It ran 1 out of 22 tests.
&lt;/h2&gt;

&lt;p&gt;The most embarrassing one, and the one I'm proudest of catching. CI printed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100% tests passed, 0 tests failed out of 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Out of &lt;strong&gt;1&lt;/strong&gt;. Not 22. cJSON gates its whole real test suite behind a CMake flag:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cmake"&gt;&lt;code&gt;&lt;span class="c1"&gt;# adapter/CMakeLists.txt — this line was missing&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;ENABLE_CJSON_TEST ON&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Upstream's own build sets this automatically; my from-scratch CMake file didn't. So the &lt;code&gt;if(ENABLE_CJSON_TEST)&lt;/code&gt; block silently defined zero real tests, and &lt;code&gt;ctest&lt;/code&gt; was truthfully reporting 100% of &lt;em&gt;one leftover test&lt;/em&gt;. I only caught it by not trusting the green checkmark and running the build locally myself. One line fixed it — and immediately surfaced 2 more bugs (a missing preamble in my test shim, and &lt;code&gt;cJSON_ParseWithOpts&lt;/code&gt; silently dropping its error-position output on failure) that had been hiding behind the disabled suite the whole time.&lt;/p&gt;


&lt;h2&gt;
  
  
  Bug #2: my fuzzer found a bug in under a minute
&lt;/h2&gt;

&lt;p&gt;Port Mortem wants a &lt;em&gt;differential fuzzer&lt;/em&gt; — same input, both builds, diff the output. Mine found &lt;strong&gt;192,619 divergences&lt;/strong&gt; on its first real run, all from string-printing unicode escapes:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// port/src/print.rs — print_string_ptr()&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// C's `for` loop increments the pointer once per iteration on top of&lt;/span&gt;
    &lt;span class="c1"&gt;// this branch's own advance. My manual Rust loop has no implicit&lt;/span&gt;
    &lt;span class="c1"&gt;// increment, so it must add that missing +1 explicitly: add(5), not 4.&lt;/span&gt;
    &lt;span class="nn"&gt;libc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="nb"&gt;c_char&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="s"&gt;"u%04x"&lt;/span&gt;&lt;span class="nf"&gt;.as_ptr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;c_int&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;out&lt;/span&gt;&lt;span class="nf"&gt;.add&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The C &lt;code&gt;for&lt;/code&gt; loop's increment clause was quietly adding one extra byte of advance every iteration — a language feature I forgot to account for by hand. One-line fix, zero divergences after. Best proof I have that differential fuzzing actually works: it caught a subtle off-by-one that unit tests never would've hit.&lt;/p&gt;


&lt;h2&gt;
  
  
  The unsafe block I couldn't get rid of
&lt;/h2&gt;

&lt;p&gt;Grepping the port shows 155 hits of "unsafe." Scary out of context, so here's the real breakdown:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What it actually is&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;unsafe extern "C" fn&lt;/code&gt; — public FFI entry points&lt;/td&gt;
&lt;td&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;unsafe fn&lt;/code&gt; — internal helper signatures&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Actual &lt;code&gt;unsafe { }&lt;/code&gt; blocks inside safe code&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;SAFETY:&lt;/code&gt; comments explaining why&lt;/td&gt;
&lt;td&gt;121&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;89 of 91 public functions are &lt;code&gt;unsafe extern "C" fn&lt;/code&gt; — not laziness, structurally required, since every one takes a raw pointer from C that Rust's compiler can't verify. Marking them &lt;code&gt;safe fn&lt;/code&gt; wouldn't remove the risk, just mislabel it. The number that actually reflects my code quality is the &lt;strong&gt;1&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// port/src/hooks.rs&lt;/span&gt;
&lt;span class="c1"&gt;// SAFETY: reads the `static mut global_hooks` — matches the original's&lt;/span&gt;
&lt;span class="c1"&gt;// own thread-safety characteristics (none), required for compatibility.&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;snapshot&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HookSnapshot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;global_hooks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;HookSnapshot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;allocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.allocate&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;libc&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="n"&gt;deallocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.deallocate&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;libc&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;reallocate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="py"&gt;.reallocate&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;cJSON lets any C caller globally swap the allocator via &lt;code&gt;cJSON_InitHooks&lt;/code&gt;, with zero synchronization — that's just how the original works, and tests depend on it. The borrow checker can't reason about a C caller mutating a global from a function it can't see, so this one spot is explicitly marked and explained. Everything else — parsing, tree walks, JSON Pointer logic, string escaping — is plain safe Rust behind that one FFI wall.&lt;/p&gt;
&lt;h2&gt;
  
  
  The CVE, ported on purpose
&lt;/h2&gt;

&lt;p&gt;CVE-2025-57052 (CVSS 9.8): resolving a JSON Pointer like &lt;code&gt;/1A&lt;/code&gt; as an array index, the original C loop kept re-checking the &lt;em&gt;first&lt;/em&gt; character instead of advancing — so &lt;code&gt;"1A"&lt;/code&gt; got folded into a valid index and returned a real element for what should've been rejected.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// port/src/utils.rs — fixed&lt;/span&gt;
&lt;span class="c1"&gt;// Original checked pointer[0] (always the first byte) here forever.&lt;/span&gt;
&lt;span class="c1"&gt;// We check pointer[position] — the byte actually being consumed.&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="sc"&gt;b'0'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="sc"&gt;b'9'&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;parsed_index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parsed_index&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="o"&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;pointer&lt;/span&gt;&lt;span class="nf"&gt;.add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="sc"&gt;b'0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;position&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;I kept the original buggy C build as a permanent fuzzing oracle to prove the fix, not just claim it — real output from &lt;code&gt;fuzz/log.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pointer: "/1A" (malformed)
  C-original(v1.7.18) -&amp;gt; accepted (bug: folded '1A' into index 27), returned element 127
  Rust-port -&amp;gt; rejected (NULL, CVE-2025-57052 fix)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The benchmark that mildly hurt my feelings
&lt;/h2&gt;

&lt;p&gt;Same 500-record, ~50KB JSON workload, 2,000 iterations, real percentiles (not just an average):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;p50 latency&lt;/td&gt;
&lt;td&gt;0.895 ms&lt;/td&gt;
&lt;td&gt;0.767 ms&lt;/td&gt;
&lt;td&gt;Rust, ~14% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99 latency&lt;/td&gt;
&lt;td&gt;2.575 ms&lt;/td&gt;
&lt;td&gt;2.044 ms&lt;/td&gt;
&lt;td&gt;Rust, ~21% faster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Throughput&lt;/td&gt;
&lt;td&gt;892 ops/s&lt;/td&gt;
&lt;td&gt;1,037 ops/s&lt;/td&gt;
&lt;td&gt;Rust, ~16% more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Max latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6.90 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;7.44 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;C&lt;/strong&gt;, by a hair&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Peak RSS&lt;/td&gt;
&lt;td&gt;2,656 KB&lt;/td&gt;
&lt;td&gt;2,656 KB&lt;/td&gt;
&lt;td&gt;tie&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rust wins where it matters most — median, p99, throughput, identical memory. But C beat me on max latency, and I'm leaving that row in the table instead of quietly cropping it out. One-off outlier on a shared machine, not a trend — but "honest numbers over confident claims" is the whole point of this track.&lt;/p&gt;


&lt;h2&gt;
  
  
  Watch it live
&lt;/h2&gt;

&lt;p&gt;Full Docker build, all 22 tests, live differential fuzz including the CVE case, no cuts on the parts that matter.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/-ROQhIIsLWY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;
&lt;h2&gt;
  
  
  All the numbers, in one place
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;22/22&lt;/strong&gt; original Unity tests pass, byte-for-byte unmodified, hash-verified&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;70M+&lt;/strong&gt; differential fuzz comparisons in a 60s run, &lt;strong&gt;0 unexpected divergences&lt;/strong&gt; (exact count varies by machine — it's a time budget, not an iteration count; two real runs hit 77.9M and 115.9M, both clean)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; real internal &lt;code&gt;unsafe {}&lt;/code&gt; block in ~4,000 lines&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; real CVE (CVSS 9.8), fixed and faithfully reproduced for proof, not just asserted&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4&lt;/strong&gt; real bugs found and fixed — including one about how confidently I thought I'd already verified this thing&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Go poke at it yourself
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/DhruvP2205" rel="noopener noreferrer"&gt;
        DhruvP2205
      &lt;/a&gt; / &lt;a href="https://github.com/DhruvP2205/cjson-rust-port" rel="noopener noreferrer"&gt;
        cjson-rust-port
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🦀 C→Rust port of DaveGamble/cJSON — 🧪 22/22 original tests unmodified, 🐛 70M+ fuzz comparisons/0 divergences, 🎯 CVE-2025-57052 fixed. 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🔀 cJSON ⇄ 🦀 Rust&lt;/h1&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Port Mortem 2026 · Track A (C → Rust)&lt;/h3&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;A byte-for-byte faithful, memory-safe Rust port of a real, popular C library —&lt;/em&gt;
&lt;em&gt;proven against the original's own unmodified test suite, not a rewritten one.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-track-criteria-checklist" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/6137caac1e2c9d8922bc597fa415be2209f92ab541fe964903a6ccbdcbc8ac46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d3232253246323225323070617373696e672d627269676874677265656e3f7374796c653d666f722d7468652d6261646765266c6f676f3d636865636b6d617278266c6f676f436f6c6f723d7768697465" alt="Tests"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-fuzz--benchmark-evidence" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f4d435071247581912b01c3c6f86436f8c8f183afb9f96ef29d63572f917ff81/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f66757a7a2d30253230646976657267656e63657325323025324625323037304d2532422d627269676874677265656e3f7374796c653d666f722d7468652d6261646765266c6f676f3d6669726573686970266c6f676f436f6c6f723d7768697465" alt="Fuzz"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-why-cjson" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/1c6a9bd46a2f5ff63f97ea70b8ae2222d62b33271c2afb57db301efa72d6efbc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4356452d2d323032352d2d35373035322d66697865642d6f72616e67653f7374796c653d666f722d7468652d6261646765266c6f676f3d736869656c6473646f74696f266c6f676f436f6c6f723d7768697465" alt="CVE"&gt;&lt;/a&gt; &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-license" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/7b032738aeb4a8dd7ec78c4402e078ca8c196b0e528c117bbd78088c9a036988/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75653f7374796c653d666f722d7468652d6261646765" alt="License"&gt;&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?v=-ROQhIIsLWY" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/c6312ea796af160435853e286b8bf78e7e5c2d32f1e67afdb362826853ac34d2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f64656d6f2d766964656f2d4646303030303f7374796c653d666f722d7468652d6261646765266c6f676f3d796f7574756265266c6f676f436f6c6f723d7768697465" alt="Demo Video"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/61bf5c828a3b545fad6251b32c564dd9f65ea13554f93a295a756b1cc671a3d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f527573742d3030303030303f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/61bf5c828a3b545fad6251b32c564dd9f65ea13554f93a295a756b1cc671a3d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f527573742d3030303030303f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465" alt="Rust"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/da826194dacce950cb70ff6e5d897531cc761517795c1e687479fb6121a30e46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f432d3030353939433f7374796c653d666c61742d737175617265266c6f676f3d63266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/da826194dacce950cb70ff6e5d897531cc761517795c1e687479fb6121a30e46/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f432d3030353939433f7374796c653d666c61742d737175617265266c6f676f3d63266c6f676f436f6c6f723d7768697465" alt="C"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/49436deb02ed796af8d0358d930cd37cc93ed0104a00b5d196d39d39ba04c443/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f434d616b652d3036344638433f7374796c653d666c61742d737175617265266c6f676f3d636d616b65266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/49436deb02ed796af8d0358d930cd37cc93ed0104a00b5d196d39d39ba04c443/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f434d616b652d3036344638433f7374796c653d666c61742d737175617265266c6f676f3d636d616b65266c6f676f436f6c6f723d7768697465" alt="CMake"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/60eb2b57aa706fb9f82149695e18d28a1a47450cc80e3a74b15060f4d47c18d0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f636b65722d3234393645443f7374796c653d666c61742d737175617265266c6f676f3d646f636b6572266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/60eb2b57aa706fb9f82149695e18d28a1a47450cc80e3a74b15060f4d47c18d0/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f636b65722d3234393645443f7374796c653d666c61742d737175617265266c6f676f3d646f636b6572266c6f676f436f6c6f723d7768697465" alt="Docker"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/adee56051ecd820e37c1849de2b1b6a5140ee01e1eca716183c31ab70c1635c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476974487562253230416374696f6e732d3230383846463f7374796c653d666c61742d737175617265266c6f676f3d676974687562616374696f6e73266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/adee56051ecd820e37c1849de2b1b6a5140ee01e1eca716183c31ab70c1635c3/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f476974487562253230416374696f6e732d3230383846463f7374796c653d666c61742d737175617265266c6f676f3d676974687562616374696f6e73266c6f676f436f6c6f723d7768697465" alt="GitHub Actions"&gt;&lt;/a&gt; &lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3df355069631fba98c9f38c9381b4f0453dd1d026dbdb599376e5970213c7343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d7a65726f2d6465613538343f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465"&gt;&lt;img src="https://camo.githubusercontent.com/3df355069631fba98c9f38c9381b4f0453dd1d026dbdb599376e5970213c7343/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646570656e64656e636965732d7a65726f2d6465613538343f7374796c653d666c61742d737175617265266c6f676f3d72757374266c6f676f436f6c6f723d7768697465" alt="No external crates"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-alert markdown-alert-tip"&gt;
&lt;p class="markdown-alert-title"&gt;Tip&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rewrite real code. Prove the port works.&lt;/strong&gt; No new tests written against the new implementation — the &lt;em&gt;original's own&lt;/em&gt; unmodified Unity suite runs straight against the Rust build.&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🧭 Contents&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;🎥 &lt;a href="https://www.youtube.com/watch?v=-ROQhIIsLWY" rel="nofollow noopener noreferrer"&gt;Demo video&lt;/a&gt;
📊 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-at-a-glance" rel="noopener noreferrer"&gt;At a glance&lt;/a&gt;
🤔 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-why-cjson" rel="noopener noreferrer"&gt;Why cJSON&lt;/a&gt;
🔬 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-how-this-port-actually-proves-equivalence" rel="noopener noreferrer"&gt;How this port proves equivalence&lt;/a&gt;
🚀 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-build--run" rel="noopener noreferrer"&gt;Build &amp;amp; run&lt;/a&gt;
🧑‍💻 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-try-it-yourself" rel="noopener noreferrer"&gt;Try it yourself&lt;/a&gt;
📁 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-repository-layout" rel="noopener noreferrer"&gt;Repository layout&lt;/a&gt;
✅ &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-track-criteria-checklist" rel="noopener noreferrer"&gt;Track criteria&lt;/a&gt;
🧪 &lt;a href="https://github.com/DhruvP2205/cjson-rust-port#-fuzz--benchmark-evidence" rel="noopener noreferrer"&gt;Fuzz &amp;amp; benchmark evidence&lt;/a&gt;&lt;/p&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📊 At a glance&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;


&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;📦 &lt;strong&gt;Source project&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/DaveGamble/cJSON" rel="noopener noreferrer"&gt;&lt;code&gt;DaveGamble/cJSON&lt;/code&gt;&lt;/a&gt; @ &lt;code&gt;v1.7.18&lt;/code&gt; (MIT)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🦀 &lt;strong&gt;Ported&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;~4,600 LOC — &lt;code&gt;cJSON.c&lt;/code&gt; + &lt;code&gt;cJSON_Utils.c&lt;/code&gt; → Rust, &lt;strong&gt;zero external crates&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🧪 &lt;strong&gt;Test suite&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;Original Unity suite, &lt;strong&gt;unmodified&lt;/strong&gt;, hash-pinned, linked against the Rust build&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;✅ &lt;strong&gt;Test result&lt;/strong&gt;
&lt;/td&gt;
&lt;td&gt;🟢 &lt;code&gt;22 / 22&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/DhruvP2205/cjson-rust-port" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;Every number above is a committed file in the repo — fuzz logs, benchmark JSON, and &lt;code&gt;DECISIONS.md&lt;/code&gt; (20 sections of reasoning, zero jokes, all receipts).&lt;/p&gt;

&lt;p&gt;This was my Track A (C → Rust) submission for &lt;strong&gt;Port Mortem 2026&lt;/strong&gt;. If you're doing a language port for anything — hackathon, work, fun — my one piece of advice is the whole post in one line: don't trust the green checkmark, run it yourself, count the tests, and if something doesn't add up, go find out why before you ship it.&lt;/p&gt;

&lt;p&gt;Thanks for reading. 🦀&lt;/p&gt;

</description>
      <category>rust</category>
      <category>c</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>The Twelve-Factor App: 5 Surprising Truths About Modern Software</title>
      <dc:creator>beTheNoob</dc:creator>
      <pubDate>Mon, 12 Jan 2026 20:09:44 +0000</pubDate>
      <link>https://dev.to/bethenoob/the-twelve-factor-app-5-surprising-truths-about-modern-software-55le</link>
      <guid>https://dev.to/bethenoob/the-twelve-factor-app-5-surprising-truths-about-modern-software-55le</guid>
      <description>&lt;p&gt;Developers today face a common set of challenges: building applications that are portable, scalable, and maintainable across a variety of environments, from on-premises servers to cloud platforms like GCP, AWS, and Azure. To address these issues, developers at Heroku created the "Twelve-Factor App" methodology—a set of guiding principles for architecting robust, modern applications.&lt;/p&gt;

&lt;p&gt;This article explores five of the most impactful and potentially counter-intuitive principles from this methodology. Understanding these factors can fundamentally change how you build and deploy software, leading to more resilient and scalable systems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4f5w3vw0u2joulq0oip.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4f5w3vw0u2joulq0oip.png" alt="12 Factors" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Your Processes Must Be Stateless (and Sticky Sessions Are a Trap)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A core tenet of the Twelve-Factor methodology is that application processes should be "stateless and share-nothing." This means that no single process should hold onto data that is required by another process for a subsequent request.&lt;/p&gt;

&lt;p&gt;Consider a simple login session. If your application is running across three server instances, a user might log in and have their session information stored on the first instance. If their next request is routed to a different instance by the load balancer, the second instance, having no memory of the user's session, treats them as an unauthenticated visitor, forcing them to log in again.&lt;/p&gt;

&lt;p&gt;A common but incorrect fix for this is using "sticky sessions," which configure the load balancer to always route a specific user back to the same instance. This is a direct violation of the Twelve-Factor methodology. The architecturally sound solution is to externalize any persistent data, like user session information, into a stateful backing service. By using a database or a caching service like Redis, any process on any instance can access the session data. This decoupling of state from process is the key to true horizontal scalability; it allows any number of identical processes to handle any user request, enabling the system to scale out effortlessly in response to load.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Logs Aren't Files, They're Event Streams&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The traditional approach to logging involves an application writing its output to a local file, such as logFile.txt. In a modern, containerized world, this practice is deeply flawed. When a container is destroyed, whether during scaling, deployment, or a crash, its local filesystem is wiped out, and any logs stored there are lost forever.&lt;/p&gt;

&lt;p&gt;A Twelve-Factor app never concerns itself with the routing or storage of its logs. Instead, it treats logs as an event stream, writing all log output to standard output. The execution environment, not the application, is responsible for capturing this stream. This transforms logs from a passive debugging file into a rich, queryable source of real-time business intelligence. The execution environment can now route these streams to powerful, centralized platforms like the ELK Stack (Elasticsearch, Logstash, Kibana) or Splunk for aggregation, analysis, and alerting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. One Project Can Mean Multiple Codebases&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first factor, "Codebase," emphasizes tracking all code in a version control system like Git to facilitate collaboration. However, it introduces a rule that might seem counter-intuitive: if a single project consists of multiple distinct application services—such as a payment service, an order processing service, and a web app—sharing a single codebase is a violation of the methodology.&lt;/p&gt;

&lt;p&gt;The correct architecture dictates that each of these distinct services should be separated into its own individual codebase. Each codebase should have its own separate deployments for each environment, such as development, staging, and production. This principle aligns perfectly with modern microservice architectures. It enforces architectural boundaries, allowing the payment service team to deploy updates multiple times a day without any risk of disrupting or being blocked by work on the order processing service.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Your App Must Be Ready to Be Shut Down at Any Moment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The "Disposability" factor states that an application's processes must be designed to be started or stopped instantly. This capability is essential for achieving rapid elastic scaling, fast deployments, and overall system resilience.&lt;/p&gt;

&lt;p&gt;To facilitate this, a Twelve-Factor app must support graceful shutdowns. When a process manager (like Docker) issues a stop command, it first sends a SIGTERM signal. This signal tells the application to finish its current request and shut down cleanly within a given grace period. If the process does not terminate in time, the manager sends a SIGKILL signal to forcefully terminate it. An application must be built to handle these signals properly to ensure clean shutdowns without data loss or corruption. This disposability is not just a best practice; it is a prerequisite for modern cloud-native platforms like Kubernetes, which rely on the ability to terminate and replace processes at will to perform rolling updates, manage load, and maintain system health.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Stop Saying "It Works on My Machine" with Dev/Prod Parity&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The classic developer excuse, "It works on my machine," is a symptom of a deeper architectural problem: environmental drift. The concept of "Dev/Prod Parity" is designed for continuous deployment and aims to keep the gap between development and production environments as small as possible, providing a disciplined cure for that drift. To achieve this parity, the methodology prescribes several key practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Consistent Backing Services: Developers should resist the urge to use different backing services between development and production (e.g., using a lightweight local database in dev but a robust one in prod).&lt;/li&gt;
&lt;li&gt;Identical Tooling: The tools used to build, test, and run the application should remain the same across all environments.&lt;/li&gt;
&lt;li&gt;Developer Involvement: Developers should be involved in the deployment process to bridge the gap between writing code and seeing it run in production.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;While some of these principles may seem strict or require rethinking traditional development habits, they provide a proven roadmap for building modern applications. By embracing concepts like statelessness, event stream logging, and dev/prod parity, you can create systems that are highly resilient, scalable, and portable across any infrastructure.&lt;/p&gt;

&lt;p&gt;As you look at your own projects, which of these factors presents the biggest opportunity for improvement?&lt;/p&gt;

</description>
      <category>twelvefactorapp</category>
      <category>systemdesign</category>
      <category>devops</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
