<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[At the speed of code]]></title><description><![CDATA[Rambling about programming]]></description><link>https://fastware.dev</link><image><url>https://fastware.dev/img/substack.png</url><title>At the speed of code</title><link>https://fastware.dev</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 11:31:28 GMT</lastBuildDate><atom:link href="https://fastware.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Amaury Séchet]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[deadalnix@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[deadalnix@substack.com]]></itunes:email><itunes:name><![CDATA[Amaury Séchet]]></itunes:name></itunes:owner><itunes:author><![CDATA[Amaury Séchet]]></itunes:author><googleplay:owner><![CDATA[deadalnix@substack.com]]></googleplay:owner><googleplay:email><![CDATA[deadalnix@substack.com]]></googleplay:email><googleplay:author><![CDATA[Amaury Séchet]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Koan of Closure]]></title><description><![CDATA[Today I want to share a small Koan from a mailing list (archive) that' I&#8217;m afraid may one day disappear from the internet.]]></description><link>https://fastware.dev/p/the-koan-of-closure</link><guid isPermaLink="false">https://fastware.dev/p/the-koan-of-closure</guid><dc:creator><![CDATA[Amaury Séchet]]></dc:creator><pubDate>Sat, 17 Aug 2024 21:05:26 GMT</pubDate><content:encoded><![CDATA[<p>Today I want to share a small <a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html">Koan from a mailing list</a> (<a href="https://archive.ph/NUciy">archive</a>) that' I&#8217;m afraid may one day disappear from the internet.</p><blockquote><p>The venerable master Qc Na was walking with his student, Anton. Hoping to prompt the master into a discussion, Anton said "Master, I have heard that objects are a very good thing - is this true?" Qc Na looked pityingly at his student and replied, "Foolish pupil - objects are merely a poor man's closures."</p><p>Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.</p><p> On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.</p></blockquote><p>Anton van Straaten, 4 Jun 2003</p>]]></content:encoded></item><item><title><![CDATA[Intercept system library calls on linux]]></title><description><![CDATA[Hijack pthread_create for fun and profit]]></description><link>https://fastware.dev/p/intercept-system-library-calls-on-linux</link><guid isPermaLink="false">https://fastware.dev/p/intercept-system-library-calls-on-linux</guid><dc:creator><![CDATA[Amaury Séchet]]></dc:creator><pubDate>Sun, 31 Dec 2023 22:58:05 GMT</pubDate><content:encoded><![CDATA[<p>I recently worked on a garbage collector that, in order to function properly, needs to be aware of all the application&#8217;s threads. However, unlike managed environments where the virtual machine is aware of all threads, this scenario occurs in a system context where new threads can be initiated from anywhere, including those linked in 3rd party libraries.</p><p>Consequently, I had no choice but to intercept <code>pthread_create</code> to incorporate logic for registering the thread in the garbage collector (GC). Achieving this in a satisfactory manner was a lengthy quest, so I would like to share the end result here. Furthermore, the solution is not specific to <code>pthread_create</code> and can be applied to intercept most system library calls, such as <code>malloc</code> and <code>free</code>.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fastware.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading At the speed of code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>The calls we aim to intercept originate from shared objects supplied by the system, such as <code>libpthread.so</code> or <code>libc.so</code>. Since the function we intend to intercept lacks an implementation in our program, we can provide one, and it will take precedence over the system's implementation. This is fantastic news, but a significant problem remains: we still need to forward the call to the system's <code>pthread_create</code> so that a new thread will indeed be created.</p><p>To achieve this, we manually resolve the <code>pthread_create</code> function using <code>dlsym</code>. To ensure we do not resolve the same method again and again, we use the <code>RTLD_NEXT</code> functionality, which ensures the lookup only happens in subsequent objects.</p><pre><code>#include &lt;dlfcn.h&gt;
#include &lt;pthread.h&gt;
#include &lt;stdio.h&gt;

#define RTLD_DEFAULT ((void*)0)
#define RTLD_NEXT ((void*)-1ll)

typedef int (*pthread_create_type)(pthread_t* thread,
                                   const pthread_attr_t* attr,
                                   void* (*start_routine)(void*), void* arg);

int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
                   void* (*start_routine)(void*), void* arg) {
    printf("pthread_create intercepted!");

    pthread_create_type real_pthread_create =
        (pthread_create_type) dlsym(RTLD_NEXT, "pthread_create");
    return real_pthread_create(thread, attr, start_routine, arg);
}</code></pre><p>This solution still has a couple of problems. First it does resolve the symbol every time, which can be costly. We could cache the result of the resolution and check the cache before resolving, but we can do better. We are doing an indirect call no matter what, so we might as well take advantage of this and create a trampoline function, that resolves and then update the indirect call directly. While we are at it, we can add some error handling code when the real <code>pthread_create</code> fails to resolve.</p><pre><code>#include &lt;dlfcn.h&gt;
#include &lt;pthread.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

typedef int (*pthread_create_type)(pthread_t* thread,
                                   const pthread_attr_t* attr,
                                   void* (*start_routine)(void*), void* arg);

static int resolve_pthread_create(pthread_t* thread,
                                  const pthread_attr_t* attr,
                                  void* (*start_routine)(void*), void* arg);
static pthread_create_type pthread_create_trampoline = resolve_pthread_create;

static int resolve_pthread_create(pthread_t* thread,
                                  const pthread_attr_t* attr,
                                  void* (*start_routine)(void*), void* arg) {
    pthread_create_type real_pthread_create =
        (pthread_create_type) dlsym(RTLD_NEXT, "pthread_create");
    if (!real_pthread_create) {
        printf("Failed to locate pthread_create!");
        exit(1);
    }

    pthread_create_trampoline = real_pthread_create;
    return real_pthread_create(thread, attr, start_routine, arg);
}

int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
                   void* (*start_routine)(void*), void* arg) {
    printf("pthread_create intercepted!");
    return pthread_create_trampoline (thread, attr, start_routine, arg);
}</code></pre><p>This is good, and we could stop there, however, there one more major problem: sanitizers. Sanitizers such as asan, tsan, ubsan and so on leverage a similar technique to intercept system library calls. If we stop there, we&#8217;d be unable to use them, which would be a major problem. Thanksfully, they also provide a way to work around this: we can resolve <code>__interceptor_function_we_want_to_intercept</code> instead of the function itself. Detailed explainations can be found in the <a href="https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/interception/interception.h">intercept library&#8217;s source</a>.</p><p>Introducing this two stage resolution, we have something that does pretty much everything we want.</p><pre><code>
typedef int (*pthread_create_type)(pthread_t* thread,
                                   const pthread_attr_t* attr,
                                   void* (*start_routine)(void*), void* arg);

static int resolve_pthread_create(pthread_t* thread,
                                  const pthread_attr_t* attr,
                                  void* (*start_routine)(void*), void* arg);
static pthread_create_type pthread_create_trampoline = resolve_pthread_create;

static int resolve_pthread_create(pthread_t* thread,
                                  const pthread_attr_t* attr,
                                  void* (*start_routine)(void*), void* arg) {
    pthread_create_type real_pthread_create = (pthread_create_type)
        dlsym(RTLD_DEFAULT, "__interceptor_pthread_create");
    if (real_pthread_create) {
        goto Forward;
    }

    real_pthread_create =
        (pthread_create_type) dlsym(RTLD_NEXT, "pthread_create");
    if (!real_pthread_create) {
        printf("Failed to locate pthread_create!");
        exit(1);
    }

Forward:
    pthread_create_trampoline = real_pthread_create;
    return real_pthread_create(thread, attr, start_routine, arg);
}

int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
                   void* (*start_routine)(void*), void* arg) {
    printf("pthread_create intercepted!");
    return pthread_create_trampoline(thread, attr, start_routine, arg);
}</code></pre><p>While this snippet of code is rather short and easy to understand, most of this is undocumented and it took a fair amount of research to figure it out.<br><br>If this is interesting or useful to you, let me know.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fastware.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading At the speed of code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[The real problem Unity needs to solve]]></title><description><![CDATA[A lesson in efficient engineering]]></description><link>https://fastware.dev/p/the-real-problem-unity-needs-to-solve</link><guid isPermaLink="false">https://fastware.dev/p/the-real-problem-unity-needs-to-solve</guid><dc:creator><![CDATA[Amaury Séchet]]></dc:creator><pubDate>Thu, 14 Sep 2023 21:18:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!z6Zk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Unity's recent <a href="https://twitter.com/unity/status/1701650081403842851">announcement about implementing a per-install charge</a> has stirred controversy among game developers for several reasons. Firstly, developers are already burdened with annual licensing fees ranging from <a href="https://unity.com/fr/pricing">&#8364;1,877 to &#8364;4,554 per seat</a> for using the Unity platform. Secondly, they are concerned about the lack of control over when and where users choose to install their software, as they neither have the capability nor the desire to engage in extensive user surveillance, potentially forcing them into the realm of mass monitoring.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z6Zk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z6Zk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 424w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 848w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 1272w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z6Zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png" width="673" height="353" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:353,&quot;width&quot;:673,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19533,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z6Zk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 424w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 848w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 1272w, https://substackcdn.com/image/fetch/$s_!z6Zk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F289bd9e9-35b8-49f0-9bc3-92ee9b0f20b4_673x353.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Unity stock price: number doesn&#8217;t go up.</figcaption></figure></div><p>This announcement follows Unity's initial public offering in 2019, which disappointed investors due to its poor performance. To address this issue, Unity's management is exploring new revenue streams, leading to the introduction of this new pricing model. While it's unquestionably important for Unity's engineers to be fairly compensated for their work, especially considering the platform's success in the game industry, the question arises: does Unity truly face a revenue problem? To assess this, let's conduct a quick comparison of Unity's pricing with that of other software commonly used in the game industry. For instance, Maya costs &#8364;2,226 per year, the full Adobe suite is priced at &#8364;1,841.76/year, and notably, an Unreal Engine license is $1,500 per year. In light of these figures, it's evident that Unity is not significantly underpriced; if anything, it falls within the higher range for products of this kind.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fastware.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading At the speed of code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>In oder to understand what the actual problem is, I invite you, dear reader, to compare the following two pictures:</p><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e09820c5-4ca0-4e91-9f2d-961811c147c6_815x732.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81165113-c89e-4f6d-b3a5-1e9220425b24_640x400.png&quot;}],&quot;caption&quot;:&quot;&quot;,&quot;alt&quot;:&quot;&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/371fd506-f527-461c-a28b-848dc391c15d_1456x720.png&quot;}},&quot;isEditorNode&quot;:true}"></div><p>On one hand, we witness the continuous expansion of Unity's workforce year by year. On the other hand, consider the credits screen of Quake, which lists a mere 18 individuals. It's essential to recognize that these individuals were not only responsible for creating a game but also for developing an entire game engine, along with a programming language known as <a href="https://en.wikipedia.org/wiki/QuakeC">QuakeC</a> and its interpreter and toolchain.</p><p>How can such a stark disparity even occur? While Unity's tasks are undeniably more complex than Quake's - there are higher expectations from a game engine, given the advancements in the industry - let's be frank: does Unity genuinely accomplish 428 times more than Quake? The answer is an unequivocal no. In fact, the Unity engine was already highly successful in the game industry in 2019, with only about one-third of its current workforce.</p><p>Unity has a real software engineering productivity problem on its hands. In fact, this is not limited to Unity, most of the software industry productivity is abysmally low. Yet, on a regular basis, we see small teams outperform companies which are orders of magnitude their sizes. Consider the following, examples:</p><ul><li><p>Instagram, 13 employees at acquisition.</p></li><li><p>Whatsapp, 55 employees at acquisition.</p></li><li><p>Notion was built on a team of 10 people.</p></li><li><p>SuperHuman has 103 empoyee as of today.</p></li><li><p>Godot has a core of 10 contributors, and about 100 occasional contributors.</p></li></ul><p>All these products have millions of users, and they're far from trivial. So, what's the deal? The truth is, software engineering doesn't have to be needlessly inefficient, and there are well-established strategies to improve it. The problem is that many software engineers have never worked in such a fast paced environment and lack experience in setting it up. To make matters worse, management often obstructs the necessary steps to implement these strategies. Consequently, the industry tends to blindly follow "best practices," which, more often than not, stifle productivity.</p><p>In this blog, I will delve into these strategies. Meanwhile, I strongly suggest that Unity consider returning its workforce to its 2019, or even 2013, levels. At that time, the company was successfully delivering a product that the industry embraced, demonstrating that it's feasible to be crushing with that workforce size. This will entail making numerous tough decisions, encompassing aspects like human resources, technical adjustments, and strategic shifts. It leads us to our initial lesson: too often, we let the situation deteriorate due to cowardice.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://fastware.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading At the speed of code! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>