Trading a 4x performance penalty for memory safety effectively turns C into a slower version of the high-level languages it was meant to outperform. While the security gains are real, the overhead makes it an academic curiosity rather than a practical tool for systems programming.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
Memory Safe C | Standup #33Added:
You guys ready to talk today? Today's a pretty good topic. Are you guys ready for today?
I'm ready. Okay, yeah. I I mean I'm not ready.
We're going to start anyway.
Uh anyways, I sorry. Uh today we are talking about PhilC, the memory safe C.
Is it useful? Is it good? Is it the future of C?
Uh as always, we have with us Teage, creator of a C-based memory course on boot.dev, where you get to go over how a language What was that? Good point. Yes, great point.
>> don't interrupt me saying that I'm like in the middle of a really strong intro.
All right, anyways. As always, we have with us Teage DB, creator of a C-based memory course on boot.dev, where you go over how to create a garbage collector.
And Casey Muratori, legendary C Chad game programmer. Check out computerenhanced.com for his amazing courses and lecture. And we also have a special guest with us today, low-level uh security extraordinaire and also seed at uh C and Asm Chad. Check out lowlevel.academy for amazing courses and all your low-level needs. Now, Hey, no problem, buddy. Uh so now, let's talk a little bit about PhilC.
>> to say a comment and it didn't break the intro. I'm the last one. Suck it, nerd.
Like He said it cleanly. He said it cleanly. He got it in there, Teage. It was like part of the flow. I apologize.
talking, Teage. And you just are like, "Hey, that's a great point." I didn't even think about how that would be relevant to this today.
>> [laughter] >> So, I was surprised. Go ahead, Prime.
>> Anyways, uh just for everybody to understand a little bit about PhilC, here's some basic C code along with a special standard Phil uh up at the top that's brought in that allows a special kind of printing character called the capital P. And in there, it'll actually print out, "Hey, look at this. This pointer actually has three values in it." You, the C developer, will only see just, you know, the integer. But underneath the hood, there's actually some extra information stored. And this actually shows its lower and its upper bound. You can see that we allocated 16 bytes. And of course, there's 16 bytes uh difference between the lower and the upper. That is fantastic. And with that, it allows for some special behavior. So, here we go. We malloc 16 bytes again. I try I attempt to access byte 42, or technically the 30 the the 42nd index into here, which would be out of bounds.
And PhilC says, "Ha ha ha ha ha. I've thwarted such an easy and very obvious thing." Now, some of the things about PhilC that makes it a little bit unique and probably is going to make a lot of people mad is it's actually garbage collected. That's right. It's a C that is garbage collected. So, if you look underneath the hood, even if you call free, it does not technically free it.
It marks it as being freed. And then later on, the asynchronous multi-threaded behind-the-scenes garbage collector will go and free that memory.
So, it's a very This is not your grandfather's C, okay? This is This is modern C. And which means Good one, Teage.
I'm just saying he made one. It's fine.
It's okay. Keep going. They have garbage collection in C for a while, but yeah, that's okay. Yeah, I know, but it's not That's not like your standard operation in C. People don't think C, "Oh, yeah, that garbage collected language." Like that's not the first thought that comes into people's heads. Whereas this is garbage collection at all times. Yeah, standard standard C does not have a garbage collector. Like if you're right, you're you're talking about some additional thing when you talk about C garbage collection, right? Yes, yes, yes. Whereas this is going to be like your standard experience is actually garbage collected. Now, obviously, PhilC does come with a lot of uh performance penalties and run-time checking. Like when I did that little check into P42, it obviously did a run-time check on that. When you attempt to run it, it crashes your program successfully.
Uh and so that is a Yes, Teage? I was wondering, do we have any bouncing balls to show the performance penalty [laughter] for a charts? Cuz I feel like I can I As you said performance penalties, I literally wanted to slap myself in the face that I did not bring a bouncing ball chart to benchmark this for Casey. I'm so angry. I'm so angry.
>> [laughter] >> As you can see from this diagram, Right. Very scientific. That's why I There are some performance penalties.
It's like, "No, actually, I can't see from that diagram cuz the diagram sucks.
That's why I can't see it from that diagram."
That's pretty funny. Look at all these engineers sitting at their neat little desks. [music] It takes dirty work to keep a code base clean. Every day, sickos are out there committing unreviewed code. And when that happens, [music] linters won't save you. You need someone like me. Let's go!
Freeze, you free scumbag. Who you calling scumbag? What's this slop you're trying to push? Unnecessary comments?
Global state? Nested ternaries? Uh my bad. I didn't even read the code yet.
You disgust me. Step away from the keyboard.
>> Just let me explain. Is that a mouse?
HE'S MERGING A PROD. YOU HAVE THE RIGHT TO REMAIN SILENT. Anything you push to GitHub Cannon will be used against you.
You have the right to a debugger, but if you cannot afford one, a public stack trace will [music] be made available to you.
And one more code criminal off the streets [music] and where they belong, HR.
>> [snorts] >> Look, I didn't I know I didn't review any of the code, but I was going to have Code Rabbit review it from the start. With one-click fixes and style enforcement, I don't need Merge Cop.
I would never merge unreviewed code, but a first pass with Code Rabbit always makes things go faster. Actually, you can try it, too, at coderabbit.ai.
Next week on Merge Cop. The diff-lers out there, and I'm going to be the one to deprecate them.
So, uh to kind of put kind of wrap it all up so everybody understands how PhilC works, the run-time uh impact of PhilC is going to be somewhere between 1.2 to 4x is what I have seen. And then you will see comments on the internet that say something along the lines of, "What's 20% these days? Nobody cares if you lose 20% performance." Which I know that Casey will probably lose some sort of sleep or hair over with that kind of comments on the internet. Wait, how did we get from 1 to 4x uh and and go from that to 20%? Well, because 1.2 would be, you know, 20%. But then the 4x >> mean that if you just took just the minimum as assuming that you were going to going to get the minimum for some reason without evidence. Okay, sure. Can I say There is another performance penalty. Can I Can we talk about that really quickly as well? Before we get into that, I just have to say that I have to I just have to I'm I'm going to be a little bit on the rust side today, so I came prepared.
I know.
Perfect. Okay.
>> [laughter] >> Hey guys, it's Rust Teage checking in today. Um the other problem is that there's a serious memory additional performance constraint here in the sense that it's going to allocate a lot more memory for lots of different kinds of programs. So, I just wanted to make sure that that's clear.
It's not a zero-cost abstraction. Okay, it's not a zero cost. So, Prime, you may continue.
Actually, Teage is very, very correct.
It is not, in fact, a zero-cost abstraction. Uh anyway, so I just wanted to talk about this because the thing that really sparked all of this was that sudo RS is kind of this new brand of sudo. It's the new sudo on the block.
And And Ubuntu is saying, "Hey, we're using it." But all the comments are like, "Why? What's Why are you doing Like it seems to be a at least it appears I don't know if it's actually true in real life, but in Twitter life, it appears to be a largely negative experience. And so with that in mind, some people are saying, "Well, why don't you just use PhilC? Uh PhilC, the performance of sudo is negligible, and you can get 90, you know, 90% of the safety without having to deal with Rust and rewriting and rediscovering all the bugs." And so that's why we have with us uh Casey and um and low-level learning. Teage is just here for fun. And so therefore, uh I think it'd be fun to start probably with uh with the security side, just because I think that that is probably the most poignant or at least the most reasonable place to start when it comes to a memory safe C. Uh Ed, uh if you'd like to kick off any any talks about that, I have a lot of questions about it, but any initial statements?
Yeah, I mean, so I guess to kind of kick this conversation off, right? What What is spawning this? Uh if you guys aren't aware, sudo, you know, well-known, well-loved program uh that tends to be the um target of a lot of vulnerability research because it is one of the most widely available, widely used setuid binaries, right? It's binary that runs as root, and you use it to run things either as root or somebody else. Uh and so a memory corruption vulnerability in sudo obviously violates a pretty a pretty hefty, pretty scary security boundary. Um and so as a result, there's a push to uh rewrite a lot of bin utils, one of them being sudo, in Rust, right?
Kind of a a cool idea. Uh this also, for some reason, kicked off an effort to like rewrite all of the core utils in Rust to include like echo, cat, sed, which is a whole other conversation. Um but unfortunately, despite it being written in Rust, shocking, I know, I think there were two CVEs that came out recently um in the RS implementation of of sudo. Uh so it kind of begs this bigger question. I think, you know, we talked about this in the previous episode that I was on with Casey. Um You know, all because you write it in Rust doesn't mean that you're going to get the exact same behavior. Uh and if you can't confirm by a some set of testing that you have, you know, not regressed at all in your functionality, uh then you're potentially introducing new vulnerabilities to the code through logic errors. And that's I think exactly what we saw with sudo RS. Um so instead of rewriting everything in dollar sign new lang, and I'm sure we're going to iterate on new lang every 20 years, uh why not drop in a new compiler that has sanitizers, that has uh intermediate representation checks to put in on an arbitrary pointer the vector size, right? And that's what PhilC does. I have not used PhilC personally. I'm kind of curious, Prime, uh how it went for you. But overall, I think PhilC's PhilC is a great idea. Um there are some compat issues. You have to be compatible with the LLVM toolchain to make it work, which is kind of an issue for some uh some pieces of software. But generally, great idea. I love the concept. So, that's kind of my uh my first take.
Casey, what about you?
I'm I'm on the same page. Essentially, like rewriting something in Rust to me is usually a pretty bad idea because the problem is that you're really Rust can only guarantee you a couple security things that it's specifically designed to do, but all of the other ways you can have bugs are still there. So, it doesn't really handle all of like your logic errors or things like that that could result in your program doing something potentially catastrophic, especially in the case of like a core utility like sudo. And so, really like I would never have like I would be like, "Don't do that." Like like we know that there are memory, you know, safety problems in the languages these were written in, but they've been kind of beaten out over the years, and we can keep looking for them and so on.
>> [clears throat] >> And so, rewriting something in Rust like that is just very dangerous and I think ill-advised. So, something like Phil C is kind of a very nice middle ground, I would say, which is that like we hey, we can preserve the logic integrity of this thing that has now been battle-tested so that we're pretty sure that we've found a lot of the logic errors that I'm sure were in there originally that we've now kind of gotten out over the years as people found them.
But, now you can also get this added layer of memory checking just to make sure that memory things we haven't found yet, maybe this will protect against those.
And then you're really just down to like, "Okay, are there bugs in Phil C itself, right?" And you know, maybe those take a little while to suss out too. Like maybe there are some edge cases that um you know, uh will be found. But, until then, it's like that seems like a much better that would be true of Rust as well, right?
Like there's no difference between Rust and Phil C in that sense. You can always have bugs in the implementation of the memory safety.
So, it really does seem like a much more sensible approach uh if you're just talking about our goal here is to make sure that we're providing the safest possible version of something like sudo.
Yeah.
Okay, so I mean, those are all kind of like they they feel like intellectual arguments more than actual like practical arguments. Do you think there's an actual practical argument to saying that Phil C is going to be something that is that is like fully usable? Like Casey, could you use Phil C in a game or would you even ever consider using something like Phil C in a game engine {slash} game?
Well, I mean, you'd have to have some reason why you felt like what it's offering you is important. So, you know, there are some ways in which you could imagine this being important.
For example, if you have a lot of user-generated content in a game where potential bad actors might be trying to use that ability to upload content to create sort of security exploits, right? Some You can imagine something like Roblox or Fortnite or whatever where they're kind of constantly trying to increase the amount to which their users can contribute new games, new modes of play, whatever.
You could imagine something like that where there are cases where you're very scared about things like memory protection and stuff like that. And so, I could see maybe some arguments in certain specific scenarios where you're like, "We really need this. So, we're going to take this isolated part of the engine and maybe we will use something like Phil C. We'll accept the performance hit, but we just really need this We need as all the security we can get."
But, for the for the majority where you're talking about just running a game in an isolated context on someone's machine, it's unclear what you really need this for, right? For for the average game development, it's not really And and I don't I mean, the the person who created Phil C works at Epic.
Right? They they are they are working on I think they work on Verse, the the Epic like Epic's Fortnite programming language thing.
Um And and so, like, you know, that I I would imagine most of like an Unreal Engine or something like that wouldn't really adopt something like Phil C, but you could see some specific cases where that might be important. And for example, Verse, which is their language That would be a case where he he probably is employing some of these techniques there. I don't I don't have any inside knowledge of that, and I don't work on that, but So, that'd be my take on it. Is it you'd have to be in an area where you really cared about it cuz otherwise, I'm not really sure what what you would need it for. Does that make sense?
Yes. That's it. I I think that does make sense. Uh I I mean, where where my big misunderstanding probably just comes from is that I don't understand I I was trying to read some of the things with the differences between like ASan and UBSan and how that how Phil C actually can circumvent some of those problems. But at the end of the day, TJ brought up really good points because he's he's being the resident Rust dev. There are things that Phil C just can't do. And they even they even shouted out, which is like file handles.
They are something that we can't that can't be represented in the same kind of context.
Well, here. I'll give I'll give the example First off, that's probably the longest a Rust user's ever gone without speaking, so I just would like that to go into the record as a moment for allowing other people to speak.
Um I do have Rust running in production right now.
Uh that is something that also most Rust users have never done. So, I would put myself [laughter] ahead of almost every Rust user in the entire world.
>> guy. Listen. [clears throat] >> Yeah. So, just throwing it out there as uh two things that make me very qualified to talk about this. But I do want to Can I I need to say one thing though. You also did the zero-to-I-use-Rust-by-the-way at the same standard rate as any Rust dev who starts speaking within the first like 5 seconds, you mentioned the fact that you you used Rust, by the way.
By the way.
I don't I thought I wasn't allowed to run Rust C unless I did that. I still need to run Rust C sometimes, so I don't understand. So, okay, anyways. Um the So, this is on a on a >> [laughter] >> serious note instead of memeing about Rust users.
Um the This is not a reason that I would rewrite a program. So, this is like a different class of thing. So, if we're if we want to start, we I would we can maybe talk more about like the rewrite situation first and then talk about, you know, like if you were starting off a new project, which one you might want to choose and pros and cons because the thing that I think a lot of people are missing and and I and Casey, you guys both alluded to this at the beginning. I maybe have to take my Rust hat off for this to say something nice about Phil C.
Um is like you can't just rewrite everything. It actually doesn't work. Like we don't have enough time or resources or a bunch of other things. Even just like if you think you can bug for bug remake it exactly right and handle every case, it's just not realistic to make that happen. Like even like I think probably I could run Neovim, you know, at like even at Phil C's current worst case 4x slower, and Neovim would still feel fast and good for me. Right? You know what I'm saying?
Like even if it was four four times slower. And that's assuming and I'm I see as well, we've got Puzzlenator in the chat who is the creator of Phil C, by the way.
Like Phil C is going to I think get faster than what it is right now, as tends to happen for people who actually care about software and making excellent things.
Um so, it's like I could run Neovim, and then I I would not be able to be exploited by certain cases of memory safety or bugs, right? Cuz I'm sometimes running slightly untrusted things in Neovim. I'm running someone else's code.
Running like via plugin or other things like that. So, it's not realistic to just say like, "Neovim, just rewrite in Rust. That's just do it. It'll be easy." That's insane behavior. That's a that's a not a realistic scenario. So, that's the thing. For some reason, I feel like a bunch of Rust people are just like talking past it of like what you could just have a safer world today. In fact, Graydon Hoare, creator of Rust, said, "More memory-safe programs is better for all of humanity."
Right? In talking about Phil C. So, anyways.
Yeah. I this may kind of be jumping backwards in the conversation a little bit there, but Prime, I kind of heard you I think sort of raised the question. You you said like, "I have questions about like what's the difference between like address sanitizer and using something like Phil C, right?" Yeah.
>> And I thought maybe that might be something that's worth like talking about a little bit. Yes. Yes. I Because I've I've ASan'd a few times in my life.
I'm no I'm no ASan expert. And so, I just know that it has caught I've done silly things with standard vector in the old C++ world where they're just like, "Yo, you're doing stupid things." And I was like, "Oh, that is a stupid thing."
Like I just didn't know I was doing.
Right. So, so just to be clear, um the idea behind things like Phil C and also just there's like kind of a broader security idea here actually than just Phil C, which is that ARM chips like or the ARM specification, I should say, and certain vendors supply actual hardware support for the kinds of things that Phil C does. It's not exactly the same as for there There are Phil C does things beyond what this hardware would be doing for you, and we can talk about that a little bit.
X64 spec also has now introduced this, although I guess I haven't really followed closely enough whether anyone's shipped any of it yet, but like there is a specification for it, right? And so, I'm assuming that like Xeons and, you know, Epic processors down the line will have this for servers or something, right?
I haven't followed out the update.
Um but Apple M-series chips now, for example, do implement this ARM this particular ARM extension.
Anyway, these things are not designed to analyze your program when you're developing it and tell you whether they found security vulnerabilities. They're designed to actually just stop the program anytime it's running when it would have done something bad. So, the idea here is to make sure that something that address sanitizer maybe wouldn't catch because when you were running the program, you never exercise the code path that happens to do this thing or whatever else, you know, like the static analysis part can't catch things or what you know, whatever you were using this is designed to basically say, "Look, the actual runtime model of this thing literally can't do these bugs."
When they would have happened, the program simply halts. It's basically just a thing that says, "When you would have written to a piece of memory that was actually a different piece than this pointer was supposed to ever be able to write to, we just stop." The program faults and it closes. Yeah. And so again, it doesn't really prevent the bug in the sense of the program working. The program still doesn't work. What it does is it stops it from turning into anything other than basically a denial of service attack, right?
So, does that make just light sense to to start with? Yeah, yeah, yeah, yeah, yeah. There's a lot of talk in chat right now about about ASan. We should probably highlight like ASan for example is not meant to be um an exploit mitigation in the sense that you use ASan to block uh hackers, right? Because all ASan does is put a predictable pattern as a shadow region in a memory space so that when that is corrupted, it's like, "Hey, it's not the same. You probably should fix this." But the pattern that it puts is probably uh is deterministic, right? So, like an attacker could just put the FA's in the right spot and you know, that would not trigger ASan while still violating memory safety. So, ASan is more like a a tool that you compile your code with to make it as fall over as fast as possible as possible to put it in your fuzzing rig in CI, right? So, that in 2 weeks when your fuzzing is done, it hopefully has crashed at some point if there's a bug.
Contrary to, you know, Casey's like the like the the PhilC thing, which is let's instead of having ASan just kill it, let's put in like intermediate representation logic within LLVM that says like, "Hey, we're going to assign lengths and things to C arrays such that you are not allowed to program in memory or memory unsafety." Um so, there's kind of two different schools of thought on like um sanitization versus runtime if that makes sense.
And for people who don't know cuz like a lot of people probably haven't written like systems level code, like maybe Ed, you can just give a really brief brief overview of like how that memory unsafety leads to bad things happening on someone's computer cuz I feel like a lot of people they just literally don't even know what's going on there. Yeah, 100% I mean so like the crux of every memory exploit boils down to this pattern, okay? Let's take a um an array and we want to index into that array using the index I, right? Okay? Now, let's instead of that I being uh a number that we program into our code statically, uh we read I off of the network and we're using some type length value network protocol where we have like the type of a field, the length of a field, and then the number of or the length of the field and then the data, right? Um most of the time it just happens that oops, the developer forgot to validate that I is within the scope of that array and so you get an arbitrary read arbitrary write. And that ability to arbitrarily read and write data gives you ASLR bypass, it gives you stack canary bypass, it gives you the ability to overwrite relocatables so you can redirect program control to somewhere else. And that like that is the crux of almost 80% of memory corruption bugs, right? There's some other ones that are a little more weird. Um So, if you literally just create proper bounds in a language that is memory unsafe that disallow a user to write outside of their confines, that's that solves the problem. And so PhilC, again, I haven't used it. I haven't explored too much into it. What I understand is that PhilC uses LLVM IR to say like, "Oh, you've made an array that is 64 bytes. I'm going to put I'm you basically turn all arrays into vectors and then do runtime checks on the vector before you do writes." And like, "Oh, if you violate that, you can't continue."
Um and so that that stops most bug classes. I think Casey was talking. I see, it's a little it's it's more hardcore than that. Like PhilC is like kind of uh Like if you actually if you're someone who is 100%, you know, at the Rust party ladling out the Rust Kool-Aid, yeah, in into into into the little Rust cups that you hand out and go like, "Let's do this Let's drink this, guys."
then you should love PhilC because it takes it way more seriously even. Uh so, essentially the way that PhilC is designed to work is it's a lot like the hardware extensions only instead of trying to be relatively transparent, it's saying, "Look, we're going to incur a cost."
And so what it actually does is it's it tracks essentially all allocated objects of any kind. So, anytime you actually do any kind of allocation it's going to say, "All right, I'm going to track that in using I mean what you would call like memory outside of the addressable space of your language." Meaning inside what you you know, doing what you're able to do inside a PhilC program, you cannot access the tracking data if that makes sense, right?
And so that tracking data will then be used anytime you're trying to work with one of these pointers, uh you know, like a a regular C pointer.
To you, it looks like you're working with the pointer normally like you would in C, but actually PhilC is going to look to make sure that that pointer originated from the actual part of memory that you are accessing, right?
So, it it tracks not just are you in bounds? Meaning not just are you within the particular object that you >> [clears throat] >> um that you were sort of claimed you were accessing, but are you in the one that this pointer originally came from?
And this works even if you like read and write pointers to like blind memory and stuff like this, right? Um because they're caught because essentially what PhilC is doing is it's using sort of almost like a pseudo pointer. It's using a a 64-bit value that you don't directly use, you indirectly use it by by looking at sort of that that backing that tracking information to make sure that you're tagged like that you you like match what you're trying to access.
Um and so when they do this in hardware, it's a sort of a weaker version of this.
What they do is for pointers in in the hardware versions of this, they just use the top bits of the pointer that wouldn't be used because you don't have that much memory. You know, you don't have 64 bits worth of memory in a machine. They use the top bits to assign say like a 4-bit tag, you know, a value between 1 and 15, let's say, and 0 is usually reserved, that sort of stuff.
They'll use that tag and then every block of memory that you sort of allocate or rather that you mark, you can say like this region of memory, you can mark regions of memory with tags, whatever you want, some random tag that you associate. Every time you use a pointer to access some of some memory, it checks to see whether the tags match.
So, that even if two blocks of memory are right next to each other, if you go from one to the other by incrementing the pointer like uh like little level was saying, if you go outside of like an array bound the tags hopefully won't match because hopefully any two neighboring regions got different tags, right? But that's really like mo- there's some other things that you can use that these extensions do, but you know, for the most part it's doing that sort of thing.
And PhilC is just sort of like the on steroids version of that, right? This it tracks everything about these so that you can't even have accidental conflicts of the tags. It's not just using some simple like 4-bit scheme. And it also does like uh more aggressive use-after-free tracking and all this other sorts of stuff by using garbage collection to like never remove those things so that it remembers like each region until it's actually not accessible by anyone anymore and so on.
So, hopefully that's just a little bit like that's like so it's a much more complete system than something like address sanitizer if that makes sense.
So, does I don't know I I that's a lot of stuff in there, but Yeah, is it effectively turning all memory accesses into like a virtual pointer?
Where like Yes. It's like a look up into another object table and then it does access >> it That's That's probably not the That's probably it sounds a little bit more uh That might be a slightly more aggressive way to say it. You can think of it more like um >> [clears throat] >> there's almost like a shadow version of thing I you You should go take a look.
They have a very nice page I'll show you, but I have to power up first. Jesus Christ. Where do you have all these FINGERS FROM? WHY?
WHY?
OKAY. THAT'S PRETTY GOOD. NOW I'M SUPER Saiyan mode cuz we have a whiteboard, okay? Super Saiyan Rust user, I like it.
>> Yeah. Okay. So, in this case right? We have like pointer X, it's pointing to 40, right? Y 44, right? You can imagine in memory we've got these two pointers, right?
What happens in normal C when you access like X5?
Yeah, you just get zero or whatever whatever like the next if element is, yeah. We get over here. But in PhilC, it says, "Yo, this if we did like malloc 4 and malloc 4 for both of these, right?"
In this case, it's going to say it's got a lower bound of 40 and upper bound of 43. Yeah. And here's where it currently is. Well, I understand that. I'm more curious about the implementation, right?
Like in this example, what is X? Is X a pointer to a thing or is X a look up to a table?
>> Yeah. X to you the user is still just this pointer. Interesting.
>> But if this is I'm assuming this is what this is what I'm going to I'm maybe we can get confirmation. As far as I could tell from reading and everything else it gives you back exactly this. This is what you think you've got. I think it's wider.
>> don't think that's how it works and it's not wider.
>> wide though, right? No, no, no, no. It's It's the same size. It's 64 bits. Oh, it is. Okay, it's the same size. It's I I don't use PhilC and the first time I heard about PhilC was was when you guys said we were doing an episode about PhilC. So, okay. I apologize for not knowing more about it. If I was a fill C user, I'd be happy to get the flux patient. I believe the way that it works is they use a shadow allocation. So, every time you allocate something, they allocate twice that effectively, right?
>> Yes, you're right. You're right, Casey.
And then they use So, effectively what X is is it's going into the shadow region, which then tells fill C where like how to get the additional data, right? Data.
In fact, we you said the the the person who wrote it was in chat. Is that a correct Would that be a good summary?
Cuz I read about this literally yesterday. So, that's all I know. But, that I believe was how it was explained in the in the documentation.
Yes. Yes, I think you're right, Casey.
Yes. Yeah, that was my apologies. It doesn't return the wider one. It has one somewhere else that it's holding on to that tells you >> invisi caps, right? It has the invisible capability stored off in a region in which you're not allowed to access in which the thing returned to you looks just like a pointer, acts like a pointer, smells like a pointer, and then see it's just literally a number, and then boom, bada bing, it does the runtime checks against it. And that's why you can still add to it and work with it like you normally would because because they have a shadow region, they can still like figure out like what's going on there, right? Or things like this. And so, I I don't know the specifics. I want to now read more about it cuz I thought it was really cool when I was like oh, this is a really neat thing. Um so, I'd like to go read about how they handle all the actual practical details, but I didn't immediately find sort of the document of that. Like there's an there's really good overview documents, but like oh, how did you handle this? How did you handle that?
Like that's I didn't find that immediately. So, I'd like to go read like how do how do you actually use the shadow region? Like how is it doing that? And all that sort of stuff. And also, the other important thing that they they bring up in this documentation, which I think is important to mention as well, is that if like a naive implementation of stuff like this would have a lot of problems with threading potentially cuz like different people can sort of mutate pointers and from you know, and you can have race conditions, that sort of stuff.
And so, fill C is also also very careful to make sure that they get those things right, which again, like if you look at it, it's like wow, this sounds very complicated. Like why did it have to you know, why does it have to allocate all this extra memory or things like that?
And the answer is because they were they were trying to take this really seriously. Like not like oh, we cut some memory bugs, but like no, we really do provide a secure operating model, which is which again, if you're drinking the rust Kool-Aid, you have to respect that.
This is this is doing it for real and on existing programs. It's pretty great.
Yes, we like that. This is the crazy thing for the rust people, we even with my rust super super crazy hair on right now, that I don't really get is like this is good. This stops this from happening. Right now, if you ran C code and you did this, it would be it would be chill.
You're like it would let you it would be chill. It would let you just read from memory that's not the thing that you're doing. That's bad. We don't like that.
We want computers to work good. Like that was the that that's the thing that I don't get. I like so, that part's good. I And and it seems like for some reason everyone's mad about it, and I don't really get why they're mad. I don't know. Because it's because it's good.
Most people really hate it when you introduce something good that's not the thing that they were previously telling everyone was good, right? Like like they don't like to hear that someone else made something good that might be a reason not to use their good thing.
That's true. True.
>> like heaven forbid, right? But yeah, there's I do have one question about fill C that I I wasn't able to answer directly from my sort of like 5-second read. So, again, like it'd be nice to maybe if if if the author is in chat, maybe they can come on sometime and tell us so that they so that people can have a more accurate description of what it's actually doing cuz that would be really nice, and obviously they would not get it wrong because they wrote it.
But, what I was going to say is I don't really know how this works with things like okay, I create a block of memory that I'm going to sub allocate out of, and I wasn't sure like what it does for that.
Like that's what one thing like like on my list now I'd like to go read about like how it deals with that.
And like like are there is that just disallowed? Is it allowed?
And we just say oh well, it doesn't catch problems >> right now. What? No sub capabilities right now. I assume that's because if you take a pointer from that region, you technically have a lower bound of the original lower and another bound of the of the big upper. So, And so, I was And so, like that's a thing that makes it kind of hard to port a lot of existing programs cuz a lot of them will do that, right? And so, then it's kind of like okay, those programs kind of have to be rewritten to like maybe there's some way that you know, fill C could be extended to support that. Like hey, allow us to sort of write a section that's like here's the here's how the memory marking is going to work inside our thing. I don't know. But like that would that would make it challenging to port programs that were written in that style, which is a very good style of writing. Like it's a very efficient. And so, it's kind of I I don't know what you do about that if it's you know, in terms of I want to use this in some subset, and I want to just use my existing C code.
Effectively, the creator P is saying the best thing you can do with your arena allocators is to replace them with individual maliks.
Okay. I mean, which is not that hard cuz usually your arena allocations are going through like a pound define kind of a thing to like allow you to switch them for debug and stuff like that anyway, or to mark like where they're coming from.
So, I assume I guess let me ask another question while we have the benefit of the author in chat. So, do you then just like how do you cuz normally arena frees are just going to free the whole arena.
So, does that just taken care of by the garbage collector then?
>> call free, let the GC deal with it.
Don't Then yeah. Then so, that then that's a not a hard port. Yeah. Right?
That's not a that's not a difficult port, I don't think. For most people cuz like at least for my own code, I always have those running through a macro so you can mark them with file and line and debug and stuff like that. So, that seems pretty pretty reasonable. And and you've been following along. We'll link as well Pizolnator, your X in the like description of the episode. But like Pizolnator's been working on a bunch of different like very complicated, very real world C programs that are big that you cannot just rewrite to Rust.
Guys, you can't do it. And talking about like Emacs and Ruby and a few other ones, you can follow along as he's kind of like micro blogging as they say.
That's that's in these days, right?
Micro blogging. I'm on Tumblr, obviously. You can tell from my hair. Um So, you can follow along there for a bunch of different ones and see see what he's been up to and how he's gotten there, which is cool. Cool. TJ, as the resident Rust expert, >> Yes, thank you.
could you could you help us understand things that fill C doesn't do?
Or why why would you like if you're starting brand new, and you're really good at C, why would you even want to choose Rust if you want to type like or at this level of safety, and you're like well, I could just use fill C, but why would you want to choose Rust? Yeah, a blue field project, if you will, for me.
>> Yes. Yes. Um So, >> project TJ. Blue sky. A blue sky project. If I was starting a new blue sky project today, what would I pick?
Okay, so, one reason you wouldn't use fill C, you don't enjoy writing C.
That's one reason. That's a legit reason, okay? There's lots of projects that don't need to be written in C, okay? That's fine. In fact, there's lots of projects that don't need to be written in Rust. I almost have to take this off when I say this, right? It's just true. It's just true.
>> You lost your blue hair on that one. I know. I know. I get it.
I think you're going to have to lose the wig, TJ. That that was Yes. You you've been yeah, you you've been removed from your board seat on the Rust Foundation for that. But okay.
>> Yes. But let's say let's say you're starting out a new project, and the requirements are such that Rust makes or or some systems language makes a good choice, right? So, or or you just have some other requirements. The example for me that that like when I was working at Sourcegraph, we have a very straightforward in and out system where we have text come in, and we need syntax highlights to come out on the other side.
It actually matters for that to be really fast. You want it to go really fast. It's always going to look the same shape. You have text come in. You'd like to copy it not so often. You're going to run this for like lots of different files and lots of different languages for lots of different customers. You'd like this to be really good and really nice and really really fast. Okay, you have options for what you could do, right? Um you could write that service in C, I guess, right? It's a maybe a little bit it's a little bit harder to picture, but there are like decent like parser generators and other stuff you could use to get you part of the way there, and then you could apply some like syntax highlighting from that and all that good stuff. But now, if you're going to go and do something with fill C, you're going to experience a slow down. And if you don't do that, you you know, you're more likely to experience some bad security vulnerabilities on a bunch of untrusted input because you're highlighting random people's code, right? So, oh, they put in a Unicode character that was too wide for your thing, and then overflowed this Now you access this. It's corrupted memory, and you screwed yourself over.
Too bad, so sad, right? So, uh so, in in some cases like this where you need you need a lot of speed, you're maybe going to work on a lot of untrusted input, you're connected to the internet, you're doing other stuff like that.
Like I think there's good reasons why you might want to choose Rust, and you'd be able to get like faster performance or something like that with Rust. I mean, also I think um you know, from a like technical standpoint, a lot of people appreciate the some of the like type system guarantees you can get from rust that Phil C is not going to give you. You're hopefully now, like you won't in in many cases have like an actual security vulnerability. You won't have a CVE from these kinds of problems, but it will crash like at runtime, which is good. That's objectively better.
Also, rust crashes at runtime for things, too. That's also how it solves some problems. So, that's not like if rust access something access to something outside and it's unchecked, that's just an expect or a panic and then it will crash. Sweet. That's memory safe. We are happy. That's actually good. Um but like there's lots of things. The example you had brought up earlier for like file descriptors, right? In rust, if I open up a file and I am making my own, you know, like API for it, I'll have the file descriptor uh like or I'll have the function take a callback. That callback's one of the parameters will be a reference to the file descriptor. In rust, the borrow checker will prevent me at compile time from accessing that outside of the callback, right? So, you couldn't like save the file descriptor to a global and then try and read from it later. That won't that like won't work, right? Um and most of the time it's like not clonable and not copyable. So, you would have to go through like a lot of hoops to try and even get that value out in a way you could even literally like just copy this.
>> pattern is impossible in rust. It's so hard to use. The callback pattern in rust, it's so freaking tough.
>> Yes.
>> haven't figured out streams quite successfully yet. Yeah. [laughter] Um but that would be a thing, right?
That like if I try and use this value, this file descriptor, outside of the callback, the type system and the borrow checker, right? The linear type system that rust has will block you from being able to do that at compile time instead of like runtime, right?
That's like for me, I'm a I'm a type systems guy. Like types, for me that makes me happy, right? Like of course, especially with the blue hair on. That makes me really, really happy.
Um so, that would be something where like if what you want to do, right? Like push left, we're going to push the errors to happen earlier along in the dev cycle. We're going to experience those at the compiler and there's no like 100,000 lines of battle-tested code that has a bunch of stuff, you might choose rust over like Phil C, right? And then you like and that would be I think a reasonable choice. But for me, that's everyone seems to be talking past each other about that on the internet, which is surprising. Can I Can I ask a clarifying question there? I'm not sure I 100% followed that. First of all, I would also say that the phrase push left Yeah. Strongly like sort of suggests a left-to-right leading language reading language because that's the order you're going in. So, I think you lose the blue hair on that one as well, but True.
Uh you should say more towards the beginning of a sentence push is the correct way to say that. Yeah, exactly.
Uh what I would say is what is the bug you're trying to prevent with this file handle scenario? Just so I understand what you mean by rust preventing this better than Like if you if you have some function, right? That like opens up and then closes a file handle for you and says like, "Hey." Or file descriptor, right? Or any kind of this thing, database connection, any kind of thing where you have like a handle, right?
>> Uh-huh. Uh if you're writing this in like this is not true of just C, but this would be like in Python or something, too. You could just like save that handle inside of your callback to some global value. It can escape its region.
Right?
So, if you like do with open file descriptor in Python and then inside of there you like save the file descriptor and later in your program after that original thing's already closed it, you're outside of that region now, you try and read from it again, it'll be an error. It will crash, right? But I mean, that's pretty easy to implement in in C or C++ as well, right? Like especially C++. Like what To do what part? Just you just wrap that wrap file handles in an in in an accessor and that will just work, right? So, like if you wanted that protection in C, you could just get it, right?
Um >> Like you don't need a language for being defeated as we speak. No, I mean like I'm I'm not trying to diss on rust. I'm just saying I don't understand why you couldn't just make that same thing by just making sure that instead of using like an int as your file descriptor, you actually use a struct that does something, you know, or or you know, a C++ class for object-oriented programmers, right? Whatever. But but I'm saying it like sort of regardless of that, I think I think we're not we're not talking about the same thing. I'm saying like we could prevent in like rust from the with the borrow checker, you can prevent the value from escaping its region, right? Which I don't which I maybe there is a C++ I'm sure there is a C++ thing that can do that. I don't know. I just assume everything is possible.
>> you're just talking about like you want like because they have special cased file descriptors with the static analysis in rust or something like this.
>> uh yeah, I think I'm I'm saying >> talking about type system and I'm like, well, the type system in both can do what you're talking about. So, if we're just talking about the type system as opposed to other things, right?
>> Yes. I'm I'm just talking about the kinds of things like this is, you know, as like I'm I'm trying to present the case for why someone would say they would rather write this kind of thing in rust, right? Is instead of experiencing a crash with Phil C at runtime, Okay. we could find that out from the compiler.
Okay.
>> oh, this kind of access isn't allowed.
That's not thread safe. That's not that escaped its region, but it shouldn't.
This kind of value right? Like there there are things that we can do there, right? In like rust with the type system that fight the same kinds of bugs you might get you might get solved from Phil C, right? But instead of instead of having a crash at runtime, we get it doesn't compile and I handle that case.
>> the borrow checker defeats use after free and double free at compile time.
That that is the objective of the of the borrow checker.
>> Yes. That's a probably way more succinct way to say that. Good job, Ed. Got it. I like to think of it as just like it's effectively a unique pointer, Yeah. but at compile time. Mhm. Right. So, so my point being separately from I think it's obviously good that there's an option where we can solve a bunch of these classes classes of bugs in C and prevent it, right? In this case of like which language would I pick for certain projects, there are definitely like reasons you would pick rust over just picking Phil C for like a new greenfield project. Of course, there's other reasons why you might pick C over rust as well.
Um like you might actually ship it and things like that, which is cool.
Um so, but that's like those kinds of bugs Phil C does not solve that at compile time. That's all I'm trying to say as like a comparison of the two and that's like a reasonable trade-off that people want to make. Yes. And that's also that's also that's because of the borrow checker, not the type system, right?
Just so we're clear on that part, right?
Uh yeah, I mean Or just so I'm just so I'm understanding it, I should say, right? Cuz that was the part that threw me. I was like, why is that a type system problem? Okay. Technically, Okay. So, it is actually the type system. Well, the borrow checker is sort of like a result of the linear affine type system that rust has. Okay. And so, I don't know what's going on. I'm just saying Okay. They go together. You would like the borrow checker >> type system the type system being like including the borrow checker. Yes. Okay.
Got you.
>> Yes, exactly.
>> That makes sense. So, I also have another question, which is that does rust catch all of the same memory errors that Phil C does because I don't know if that's true. Phil C might catch more. It does. Yeah. That's the fastest way to say that. So, like if you really care about security, you probably shouldn't be using rust. Yeah.
>> [laughter] >> Rust will catch them, but like it'll turn the condition into a DOS. So, it's like it's not an exploitable memory access, but it's also not caught at compile time.
So, like like you can do that.
>> even I mean even at runtime, does Phil C catch things that rust doesn't catch? Is my question.
At runtime, I don't >> a I unfortunately forgot to save it, but it's a condition in which Phil C does not catch something in which rust does.
I I really wish I would have saved it.
>> blocks, there are I think certain things you can do that in rust inside of unsafe blocks that rust does not check. Real quick.
>> Even all of its stuff and maybe still I'm not actually 100% sure if it will do a CVE, but inside of unsafe blocks that Phil C does catch.
>> I do have I do have to go in 5 minutes.
I have a question for you off the cuff real quick.
>> Yeah, still, Ed. Syscall related memory safety issues. Are you saying, for example, in a syscall handler where it does a copy to user like outside of the bounds of a memory region? Like what what about syscalls in particular? I'm curious what you're saying there. And then I do have to run. I'm sorry, guys.
I'm going to page you while you're gone.
>> he said he did confirm CVE in unsafe blocks is totally possible.
>> yes. Okay, how would Phil C detect that?
Yes. Piz, give us the give us the the nine yards.
>> And then we'll have to just have Phil come on.
>> Yeah, 100%. I'm so curious. That's the best the right thing is to have him on the show. If you if so long as he wants to come on, I mean. He said yes. Okay, good. Yes. Yes. There's also I I do think All right. I'll just mention one other thing as the rust person. I'll just put this back on.
Oh. Sometimes 20% slower or up to four times and 1.5 to two times as much memory actually makes it not possible to do constrained hardware or like other stuff like that will just literally make it so that's just not possible to accept the performance hit because some places in the world performance still actually matters and you can't just spin up 5,000 new lambdas and pay 10 million dollars in cloud costs. Okay, there you go.
You've just sum You're going to summon DHH, dude. You're going to summon him.
He's going to be like, YES, WE CAN.
HE'S LIKE, YES, WE CAN. We will spin up all of them.
No, he's against also true. You got to be careful. You can technically spin up all of them. You just pay a lot of money.
Like I'm paying Like this is blowing my mind right now. He says that it intercepts all syscalls at the ABI layer, which makes sense.
>> Bill, I know what we need. We need a slideshow with these examples and we can work on it together. I'll message you after this on X and we'll get this set up. And we'll come back with a slideshow with code examples and then Ed, you can ask every single question you want.
>> I've been wanting to do this a lot ever since Trash to the the TypeScript presentation. I've been wanting to do more presentations and then have us all interrupt the presentation be like, "But what about this? What about this? What about this?" And that was such a fun time.
Yes. All right.
>> Okay. Well then, let's end it right now.
Oh, go ahead, Brian. I'm sorry. I will say that every time I use a union in C, I get so happy and so sad at the same time cuz it does make me long and yearn for Rust. I will say that automatic tagged unions at the syntax level is just a thing of glory and beauty 100% of the time. Yeah, but don't worry. In another 50 years, the C++ committee will finally get one working.
>> [laughter] >> We're almost there, guys. Just one more committee. ONE ONE MORE VERSION.
PAGE REVISION AND THEY'LL GET to the discriminated unions working properly instead of sucking.
>> Casey, if that were true, then why are some people using like C17 instead of C94? That doesn't even make sense then.
I It doesn't make sense. Oh, checkmate.
Cuz 94 is bigger than 17, so we should be using that one, don't you think?
>> [laughter] >> Sounds worse then, really.
>> [laughter] >> All right, everybody. We'll go as well just because this is happening. Ed already left us and now the stream is completely screwed up. Thank you everybody for joining us for this. Hey, if you are watching on YouTube, you can see everything on Spotify. You get the full episode cuz you miss a lot of the banter when you only watch it on YouTube. So, thank you very much for watching. Thank you for all the guests.
Ed with lowlevel.academy, Casey with computerenhanced.com, and Teegs with boot.dev/teeg.
Yeah, or by the way. Or by the way, if you want to support both TJ and I cuz I also have two courses on there as well.
I just did like a Spider-Man thing. And but the name is the Spider-Man. All right. Thank you everybody. Woke up [singing] today.
Five code errors on my screen. [music] Terminal coffee and hair.
Living the dream.
Related Videos
OpenHuman VS Hermes AI: Who Wins?
JulianGoldieSEO
285 views•2026-05-29
Long-Running Agents — Build an Agent That Never Forgets with Google ADK
suryakunju
142 views•2026-05-30
This computer is made from real human brain cells. And you can buy it.
Talktmsmedia
3K views•2026-05-28
BREAKING: Microsoft’s New Image Generating Model Beat Out GPT 1.5 and Nano Banana 2
aimmediahouse
122 views•2026-06-03
I Made the Same Anime Fight Scene in Every AI Video Generator
NobleGooseAnime
295 views•2026-05-30
Nvidia Bets Big On AI PCs | New Chip To Power Windows Laptops | Technology | AI Updates | N18S
cnnnews18
3K views•2026-06-01
I Tested NEW Opus 4.8 on Four Projects (Updated LLM Leaderboard)
AICodingDaily
298 views•2026-05-29
3D Platformer Update - NO CAPES
SolarLune
294 views•2026-05-30











