TE
科技回声
首页24小时热榜最新最佳问答展示工作
GitHubTwitter
首页

科技回声

基于 Next.js 构建的科技新闻平台,提供全球科技新闻和讨论内容。

GitHubTwitter

首页

首页最新最佳问答展示工作

资源链接

HackerNews API原版 HackerNewsNext.js

© 2025 科技回声. 版权所有。

Stupid Smart Pointers in C

146 点作者 seansh2 个月前

26 条评论

rwmj2 个月前
Really, don&#x27;t do this, it&#x27;s a portability and safety nightmare (aside from C not being memory safe already).<p>C programmers are better off with either of these two techniques:<p>* Use __attribute__((cleanup)). It&#x27;s available in GCC and Clang, and we hope will be added to the C spec one day. This is widely used by open source software, eg. in systemd.<p>* Use a pool allocator like Samba&#x27;s talloc (<a href="https:&#x2F;&#x2F;talloc.samba.org&#x2F;talloc&#x2F;doc&#x2F;html&#x2F;libtalloc__tutorial.html" rel="nofollow">https:&#x2F;&#x2F;talloc.samba.org&#x2F;talloc&#x2F;doc&#x2F;html&#x2F;libtalloc__tutorial...</a>) or Apache&#x27;s APR.<p>(I didn&#x27;t include using reference counting, since although that is also widely used, I&#x27;ve seen it cause so many bugs, plus it interacts badly with how modern CPUs work.)
评论 #43388885 未加载
评论 #43388357 未加载
评论 #43395956 未加载
评论 #43387969 未加载
评论 #43389574 未加载
评论 #43388096 未加载
评论 #43395370 未加载
评论 #43388350 未加载
评论 #43396252 未加载
评论 #43395338 未加载
flohofwoe2 个月前
IMHO trying to emulate smart pointers in C is fixing a problem that shouldn&#x27;t exist in the first place, and is also a problem in C++ code that uses smart pointers for memory management of individual objects.<p>Objects often come in batches of the same type and similar maximum lifetime, so let&#x27;s make use of that.<p>Instead of tracking the individual lifetimes of thousands of objects it is often possible to group thousands of objects into just a handful of lifetime buckets.<p>Then use one arena allocator per lifetime bucket, and at the end of the &#x27;bucket lifetime&#x27; discard the entire arena with all items in it (which of course assumes that there are no destructors to be called).<p>And suddenly you reduced a tricky problem (manually keeping track of thousands of lifetimes) to a trivial problem (manually keeping track of only a handful lifetimes).<p>And for the doubters: Zig demonstrates quite nicely that this approach works well also for big code bases, at least when the stdlib is built around that idea.
评论 #43394082 未加载
PortiaBerries2 个月前
Around 1994, when I was a nerdy, homeschooled 8th grader teaching myself coding I came up with something I was inordinately proud of. I had gotten a book on PowerPC assembly so using Metrowerks CodeWarrior on my brand-new PowerMac 7100 I wrote a C function with inlined assembly that I called debugf. As I recall, it had the same signature as printf, called sprintf and then passed that resulting string to DebugStr. But the part I was proud of was that it erased itself from the stack so when the debugger popped up it was pointing to the line where you called debugf. I&#x27;m still proud of it :-).
scoopr2 个月前
Oh well, maybe we&#x27;ll soon have `defer`? [0]<p>[0] <a href="https:&#x2F;&#x2F;thephd.dev&#x2F;c2y-the-defer-technical-specification-its-time-go-go-go" rel="nofollow">https:&#x2F;&#x2F;thephd.dev&#x2F;c2y-the-defer-technical-specification-its...</a>
评论 #43388121 未加载
casenmgreen2 个月前
I maintain a combined error and resource state per thread.<p>It is first argument to all functions.<p>If no errors, function proceeds - if error, function instead simply immediately returns.<p>When allocating resource, resource is recorded in a btree in the state.<p>When in a function an error occurs, error is recorded in state; after this point <i>no code executes</i>, because all code runs only if no errors.<p>At end of function is boilerplate error, which is added to error state if an error has occurred. So for example if we try to open file and out of disk, we first get error &quot;fopen failed no disk&quot;, then second error &quot;opening file failed&quot;, and then all parent functions in the current call stack will submit <i>their</i> errors, and you get a call stack.<p>Program then proceeds to exit(), and immediately before exit frees all resources (and in correct order) as recorded in btree, and prints error stack.
评论 #43396038 未加载
Tewboo2 个月前
Smart pointers in C often feel like trying to force a square peg into a round hole. They’re powerful, but without native language support like C++, they can lead to more complexity than they solve.
评论 #43393284 未加载
Dwedit2 个月前
Highjacking the return address can only be done if you know you actually have a return address, and a reliable way to get to that return address. Function inlining can change that, adding local variables could change that, omitting frame pointer, etc.<p>It would also need to be a function that will truly be implemented as one following the ABI, which usually happens when the function is exported. Often times, internal functions won&#x27;t follow the platform ABI exactly.<p>Just changing the compiler version is probably enough to break anything like this.<p>Save the return address highjacking stuff for assembly code.<p>---<p>Meanwhile, I personally have written C code that does mess with the stack pointer. It&#x27;s GBA homebrew, so the program won&#x27;t quit or finish execution, and resetting the stack pointer has the effect of giving you a little more stack memory.
abcd_f2 个月前
Hacky and not really fit for production for more reasons than one, but clever and nice nonetheless. Good stuff.
queuebert2 个月前
C is the LS engine of programming languages. People love to drop it in and mod it until it blows up.
p0w3n3d2 个月前
<p><pre><code> I see undefined behaviours. they walk they talk they [0?W0OF??0?r??reeBSD they don&#x27;t know they&#x27;re undefined.</code></pre>
pjdesno2 个月前
Note that this will probably cause branch prediction misses, just like thread switching does - modern CPUs have a return address predictor which is just a simple stack. I don’t think you can avoid this without compiler support.
qwertox2 个月前
Not to mention that any future CPU microcode update released in order to mitigate some serious CVE might break the entire product you&#x27;ve been shipping, just because it relied on some stack manipulation wizardry.
lionkor2 个月前
&gt; Managing memory in C is difficult and error prone. C++ solves this with smart pointers like std::unique_ptr and std::shared_ptr.<p>No, it does not. Smart pointers are useful to help model lifetimes and ownership, but the real killer feature is RAII. Add that to C (standardized) and you can make smart pointers, and any other memory management primitive you need. Smart pointers are not a solution, they are one of many tools enabled by RAII.
PeterWhittaker2 个月前
1) 2018<p>2) <i>I recently discovered the implementation of free_on_exit won&#x27;t work if called directly from main if gcc aligns the stack. In this case, main adds padding between the saved eip and the saved ebp, (example). I think this can be fixed some tweaking, and will update this article when it is fixed.</i><p>I do not believe the article was updated, suggesting that the &quot;tweaking&quot; was far more complex than the author expected...<p>...which doesn&#x27;t surprise me, because the overall tone is one of a clever but far-less-experienced-than-they-think programmer having what they think is a flash of insight and realizing thereby they can solve simply a problem that has plagued the industry and community for decades.
评论 #43395375 未加载
jay-barronville2 个月前
Like many C hacks, this is a fun one, but hacks like this should absolutely be avoided for any serious C code–the magic is simply not worth the potential bugs!
评论 #43395351 未加载
kazinator2 个月前
This kind of approach of allocating objects to a context which is freed all at once is implemented in GNU obstacks.
mac3n2 个月前
this is way overkill<p>the way i do this in C looks like<p><pre><code> initialize all resource pointers to NULL; attempt all allocations; if all pointers are non-NULL, do the thing (typically calling another routine) free all non-NULL pointers </code></pre> realloc(ptr, 0) nicely handles allocations and possible-NULL deallocations
评论 #43390188 未加载
评论 #43393134 未加载
qalmakka2 个月前
Or rather, given that every relevant C compiler is also a c++ compiler, just compile as c++ and use std::unique_ptr? I love C but I just can&#x27;t understand the mental gymnastics of people that prefer this kind of hacks compared to just using C++
评论 #43393316 未加载
评论 #43388604 未加载
whatsakandr2 个月前
This article should of had the conclusion of this is why you should use arena allocator.
nanolith2 个月前
It&#x27;s a clever use of assembler, but in production code, it&#x27;s much better to use a bounded model checker, like CBMC, to verify memory safety across all possible execution paths.
feverzsj2 个月前
Just C programmer&#x27;s daily struggle to mimic a fraction of C++.
评论 #43388489 未加载
afarah12 个月前
See also the &quot;arena allocator&quot;, which has been discussed here before: <a href="https:&#x2F;&#x2F;nullprogram.com&#x2F;blog&#x2F;2023&#x2F;09&#x2F;27&#x2F;" rel="nofollow">https:&#x2F;&#x2F;nullprogram.com&#x2F;blog&#x2F;2023&#x2F;09&#x2F;27&#x2F;</a><p>I haven&#x27;t used it personally yet, but it addresses the same issue with a different approach, also related to stack-like lifetimes.<p>I&#x27;ve used simple reference counting before, also somewhat relevant in this context, and which skeeto also has a nice post about: <a href="https:&#x2F;&#x2F;nullprogram.com&#x2F;blog&#x2F;2015&#x2F;02&#x2F;17&#x2F;" rel="nofollow">https:&#x2F;&#x2F;nullprogram.com&#x2F;blog&#x2F;2015&#x2F;02&#x2F;17&#x2F;</a>
adrianN2 个月前
I wonder how that affects compiler optimization
评论 #43388334 未加载
评论 #43387658 未加载
anacrolix2 个月前
The naive assumption is that shared_ptr is always better than manual tracking. It&#x27;s not. Tracking and cleaning up resources individually is a burden at scale.
devit2 个月前
That&#x27;s completely asinine since it can&#x27;t be made to work properly with inlining (including LTO), architectures that use a shadow stack or don&#x27;t use a frame pointer, and also ridiculously inefficient and requiring assembly code for all architectures.<p>Use C++ or __attribute__((cleanup)) instead.
评论 #43399058 未加载
Joker_vD2 个月前
Wow, an actual, purposeful, and quite general return-pointer-smashing gadget, built right into the program itself. Just what any program written in C needs.