WoofWare.PawPrint,一款确定性的 .NET 运行时
WoofWare.PawPrint, a Deterministic .NET Runtime

原始链接: https://www.patrickstevens.co.uk/posts/2026-06-04-announcing-woofware-pawprint/

WoofWare 发布了 **PawPrint**,这是一个专为高精度调试而设计的早期确定性 .NET 运行时。通过解释中间语言(IL)并对原生基础类库(BCL)代码进行填充(shimming),PawPrint 能够利用概率并发测试实现对线程调度的细粒度控制。这使得开发者能够可靠地重现并识别通常难以捕获的复杂竞争条件、死锁和异常。 该运行时采用了独特的溯源追踪架构,每个指针和算术运算结果都会保留其来源元数据,为未来的“时光回溯调试”(time-travel debugging)功能提供了坚实的基础。 尽管目前项目尚未完全成熟——大部分 BCL 原生代码仍需手动建模——但 PawPrint 已能成功处理 `Task.Run`、反射和同步原语等核心功能。该项目在实现 ECMA-335 规范时,通过利用大语言模型(Claude Opus、GPT-5.5)得到了显著加速,但作者强调人工架构审查依然至关重要。开发者指出,完全自动化复杂的架构决策(如内存溯源处理)往往会导致技术债务,这进一步强调了在专业系统编程中专家指导的必要性。PawPrint 现已发布至 NuGet,供有兴趣体验确定性执行环境的用户使用。

``` Hacker News 最新 | 过往 | 评论 | 提问 | 展示 | 招聘 | 提交 登录 WoofWare.PawPrint,一个确定性的 .NET 运行时 (patrickstevens.co.uk) 17 点,由 Smaug123 发布于 2 小时前 | 隐藏 | 过往 | 收藏 | 1 条评论 帮助 Smaug123 2 小时前 [–] 算是一个充满热情的项目。我敢肯定,如果你尝试使用它,它会惨败,但它确实已经能做一些很酷的事情了!回复 指南 | 常见问题 | 列表 | API | 安全 | 法律 | 申请 YC | 联系 搜索: ```
相关文章

原文

Announcing WoofWare.PawPrint, a deterministic .NET runtime

I just released an early version of WoofWare.PawPrint to NuGet.

PawPrint is a deterministic .NET runtime - think CHESS. It runs the BCL of .NET 10. It interprets IL, shimming out only the BCL’s JIT intrinsics and native code: there are no shortcuts.

Enough is implemented that it can do:

  • Console.Writeline
  • async void Main(string[] args) {...}
  • Task.Run
  • A whole load of reflection
  • Many of the low-level synchronisation primitives like Monitor

It uses a variant of Probabilistic Concurrency Testing when scheduling threads, in an attempt to maximise the exploration of “interesting” thread orderings.

How I decided it was ready

I’ve taken six standard race conditions and tested that we can deterministically identify them. More concretely, inspired by Deadlock Empire, these tests are of the form “demonstrate that some interleaving of threads results in some known bad condition happening” (like a deadlock or an exception being thrown). Every test I tried, the test harness found the bug immediately, often taking only a couple of trial seeds.

What it’s not ready for

Well, I expect that if you use it, it will blow up almost immediately. The BCL contains very large amounts of native code, and it must be explicitly modelled in PawPrint for it to execute. An upcoming piece of work will be to allow the user to plug in their own implementations so that they aren’t blocked on the built-in incompleteness.

Overall design

PawPrint is ultimately intended to allow time-travel debugging and control over history. To that end, it maintains an extremely rich internal model of the IL machine. Everything is provenance-tracked; every pointer knows what object/field/method/whatever it’s pointing to, and every byte array knows whether it’s e.g. “a projection of object Foo into raw bytes” vs “just a bunch of bytes the user gave me”. All arithmetic results know whether they are “a sum of raw integers” or “a difference of pointers within the same array” or whatever.

The use of LLMs

Original design is my own, and I started writing it by hand. Sonnet 4.6 came out at some point during this process, and I started using it for reference information about .NET. I also used Gemini 2 Pro to perform fuzzy search through the ECMA-335 spec.

Then in 2026 I got the same LLM psychosis everyone else has, and used Claude Opus 4.6/7 and GPT-5.5 to “complete” it. This was a massive accelerator, and I believe it shaved literally years off the project, at the cost of making the code Claude-shaped in the small.

This project is particularly LLM-suited because there is a reference implementation (.NET 10 itself) and a spec (ECMA-335).

Errors the bots made

Sadly it was still necessary for me to maintain architectural direction during this project. There was only one place where I completely abdicated a complex architectural decision to GPT-5.5 because I was too lazy to decide myself, and that was a disaster which I ended up completely rewriting by hand.

That decision was about the handling of the fact that native code and some unsafe casts require genuine byte arrays to compute a result, and there’s a bunch of Unsafe.As calls in the BCL which make make it hard to avoid laundering provenance-tracked pointers through flat bytes. I religiously track provenance in PawPrint.

GPT-5.5 chose to represent arrays as being located in specific locations in memory, by assigning them fake addresses in a certain range. This got more and more unwieldy over time, and arithmetic operations on them became annoying because we lost their provenance as soon as we decided there was a genuine integer representing their location. Eventually I tore that out and replaced those integers with synthetic “I am the address of heap object Foo” markers; arithmetic on such objects will generally crash PawPrint, but that’s fine because the resulting integer values are generally undefined by .NET anyway. (There is specific support for performing arithmetic on pointers known to be within the same array.)

联系我们 contact @ memedata.com