Recent activity

Re: Function Pointers are Special 11 days ago

From Christopher Wellons to ~skeeto/public-inbox

If there's anything wrong with my statements it's that they weren't strong 
enough. I followed up 6 years later with a more general post:

You Can't Always Hash Pointers in C
https://nullprogram.com/blog/2016/05/30/

Though this stuff is hypothetical and not worth pontification. Nearly all 
implementations have straightforward pointer representations, and the 
practical, interesting issues involve pointer provenance, which the 
standard barely touches.

> You can sort function pointers with qsort() [...] instead you treat 
> function pointers as data

Re: Go Slices are Fat Pointers a month ago

From Christopher Wellons to ~skeeto/public-inbox

Thanks for writing, Pengji!

> on x86-64, SysV requires that only parameters smaller than 16 bytes 
> would be passed in this way

Smaller or equal! Your struct fat is passed exactly as I suggested, with 
"ptr" in rdi and "len" in rsi. So my statement is true for the 2-element 
struct discussed at that point in my article.

However, you're absolutely right about 3-element struct slices, which is 
where I was heading in my article. I hadn't realized the "two eightbytes" 
limit specified in the SysV ABI under 3.2.3-5c. That's too bad! I wish it 
was just a little larger, perhaps 32 bytes. I'm guessing 16 bytes was 
chosen for congruence with SSE. Looks like Aarch64 is basically in the

Re: Arenas and the almighty concatenation operator a month ago

From Christopher Wellons to ~skeeto/public-inbox

I was thinking about this more and contrived a small test confirming that 
pointer laundering is required to avoid UB. However, the situation is 
worse than expected: I found serious alloc_size bugs in both GCC and Clang 
that makes me question using it at all. They would be especially tricky to 
track down when they occur.

I'll go over each of my test program's function one at a time:

__attribute((malloc, alloc_size(1)))
static void *alloc(int)
{
    static int mem[1<<8];
    void *p = mem;
    asm ("" : "+r"(p));  // reset provenance (Clang)

Re: Arenas and the almighty concatenation operator a month ago

From Christopher Wellons to ~skeeto/public-inbox

> a "string builder" set of utilities that's separate from the buffered IO 
> layer

True, and I was sort of assuming there would be some way to reconcile 
these systems behind the scenes with minimal duplication, which is of 
course what you're aiming at in the rest of your message. Appending a 
string to buffered output — which involves accepting maybe a portion, 
flushing, accepting another portion, etc. — is a bit different than plain 
concatenation, so there's not much duplication, but duplicating individual 
type formatters would be a poor solution.

> embed a flush function pointer

You may recall u-config has a system like this. Rather than a full-blown

Re: Cleaning up DOS/PE headers in w64devkit 2 months ago

From Christopher Wellons to ~skeeto/public-inbox

Thanks for the patch, Pali! I've had similar feelings about the DOS stub 
myself. This change interests me, and perhaps early in the project before 
anyone was making serious use of the toolchain, and therefore there was 
little to break, I might have accepted it.

However, the "MinGW" ecosystem is old and well-established, and there's a 
surprising amount of value in remaining compatible with it. Often when I 
want to build something in w64devkit, the hardest work was already done 
before w64devkit even existed. Someone previously ported it to MinGW or 
Mingw-w64, and that capability has been maintained.

I'm afraid of the potential downstream effects from changing something as 
fundamental as the PE header, even if the specification technically allows 
it. I don't know what might be counting on everything being just the way

Re: Dynamic arrays w/ custom allocators 2 months ago

From Christopher Wellons to ~skeeto/public-inbox

> The conservative "allocate small and grow if needed" mindset complicates 
> code … and IMO is not worthwhile unless you're dealing with "big data"

This mindset is common in conventional C and needs a name. Maybe something 
like "16-bit thinking"? The stdio input interfaces implicitly assume it, 
designed to handle little chunks of input at a time, and those assumptions 
propagate into programs using it. Accepting complexity and performance 
costs to absolutely minimize memory use makes sense for the constrained 
resources of a 16-bit machine, where C was incubated, but it's a poor 
trade-off on 32-bit and especially 64-bit machines.

In general, a configuration file doesn't need to be read(2) a few lines at 
time. Memory doesn't need to be freed the instant it's no longer in use 
(formalized by smart pointers and reference counting). I hadn't thought of

Re: Dynamic arrays w/ custom allocators 2 months ago

From Christopher Wellons to ~skeeto/public-inbox

Thanks for writing, Thomas! Your library sounds interesting.

> the main issue revolves around the fact that on allocation error the 
> given allocator will return NULL

After adjusting my own habits, I found that eliminating allocation failure 
checks at call sites, at least in the typical case, makes programs so much 
clearer and simpler. Such checks are a significant burden when working in 
conventional C, along with (mostly unnecessary) lifetime management. In 
this very case it's complicating the "push" interface.

Worse, at least on hosted systems these checks are usually for naught. If 
the allocator waits for the operating system to push back before failing 
to allocate, then when pushback happens, if it happens at all (e.g. Linux

Re: Arenas 2 months ago

From Christopher Wellons to ~skeeto/public-inbox

> impedance mismatch between your signed sizes and size_t

Keep in mind that:

1. A ptrdiff_t size is strictly non-negative. If in doubt, assert it. You 
might temporarily compute a negative value, but that result goes straight 
into a check (i.e. "does this fit?"), and a negative is dropped. (Having a 
negative range available for such checks is, after all, a direct benefit 
of signed arithmetic.) So it's always safe to cast a ptrdiff_t size as a 
size_t argument. Suppose due to a bug the size was negative: Had you used 
size_t all along you'd have already overflowed without noticing, which is 
the same bug but harder to catch.

2. It's a common misconception that SIZE_MAX is the maximum supported

Re: Speculations on arenas and custom strings in C++ 3 months ago

From Christopher Wellons to ~skeeto/public-inbox

Thanks for the information, Jonathan. This was very helpful! The three 
"problematic for multiple reasons" items in your article are spot on, 
capturing my own feelings.

> simply `static_cast<T&&>(arg)` (or `(T&&)arg` ...)

Ha, it's so simple. I tried throwing everything at it I might care about, 
and it worked. Your article gives me confidence it's correct, too. Part of 
my confusion was stuff like this Stack Overflow discussion, about why the 
static cast isn't quite right, the need for remove_reference, etc.

https://stackoverflow.com/questions/27501400/the-implementation-of-stdforward

So I gave up on trying to work it out myself. I should have just tried it.

Re: Arena allocator tips and tricks 4 months ago

From Christopher Wellons to ~skeeto/public-inbox

Thanks for the followup!

> It's difficult (for me, at least) to read code where assignments are 
> being hidden behind macros.

Same for me, so I'd probably dislike it for the same reason. Though at 
least it's not a worse case: when variable declarations are hidden inside 
macros.