tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: proposal: some pointer and arithmetic utilities



> If you know a platform where two pointers of the same type to the
> same object won't have identical bits then good for you.

The reason the C spec makes it clear what is and isn't promised is so
that code can be written to be portable to platforms the author doesn't
know of (and perhaps don't even exist yet).  If portability to the
platforms I happen to be familiar with is all you care about, then
sure, go ahead and play fast and loose with assuming pointers are all
just memory addresses, that nil pointers are all-bits-0, that bytes are
exactly 8 bits, etc.

I don't do that.  (Well, not in code that's intended to be portable.)
And I don't think NetBSD should.  And, in many respects, my impression
is that NetBSD wants to avoid such issues, though it certainly doesn't
go as far in that direction as I think it should.

>> This [] paradigm strikes me as bad interface design.  It [] makes it
>> impossible for the library struct to be opaque to the application
>> code; it can be undocumented, but it can't be opaque.  It also means
>> that modifying the library struct introduces nontrivial ABI issues.
> The interface design is not a "place it at the top of any particular
> structure" paradigm, it is an "application allocates memory the
> library needs to use" paradigm.

Then you have at least some of the ABI issues no matter how you slice
it, and you either have the "can't be opaque" issue or you introduce
other issues because the application doesn't have the struct.

> If the application struct is important to keep fixed for an ABI then
> the application will know that and will allocate library overhead
> structs elsewhere.

That's not the kind of ABI issue I was talking about.  I was talking
about changes to the _library_ struct.  If its size changes, either the
application needs to be recompiled or it must always allocate it
dynamically somehow, either on the heap or on the stack, since there's
no way to define an object of static storage duration whose size is not
known at compile time.  (The closest you can get is a reference to an
object defined elsewhere.)  And, except for a few trivial changes like
just renaming members, there's no way to guarantee that a change that
doesn't affect its size on one platform won't affect it on another.

> And if the application doesn't trust itself not to write to the
> innards of the overhead ([...]) it can always write its own module to
> separately allocate and free the library struct while hiding its
> contents from the rest of itself.

I'm less concerned about that sort of issue than I am about people
writing code that goes under the hood.  If the library's overhead data
is properly opaque, they can't do this - but when it's not, even if
it's not documented, they can and occasionally do.  I've had to deal
with code that goes under stdio's hood, using horrors like f->_nb which
of course explode badly when built against a different stdio
implementation from the one they were written for.  The only excuse I
can see for not making FILE an opaque type, probably an incomplete
struct type, is that then putchar() and friends can't be
function-call-less macros, and that I'm not sure I wouldn't call
premature optimization.  (I'm not sure I would, either, mind you.)

> And, of course, it is very often convenient to provide the
> application with a complete type so that it can statically allocate
> the memory if it wants, or group small, related allocations like this
> into a larger structure which can be allocated and freed all at once,

It is...until you want to replace the library and discover you can't,
or you have to put the new stuff off in a separate place because it
won't fit in the stuff the application is allocating and you want to
just replace the library without recompiling the application.  (In the
kernel, think loadable modules instead.)

Personally, I don't much care about that; recompiling an application
when changing a library it depends on is something I expect, I
generally do not use dynamic libraries except for the ones that come
with the OS, and I do not leave loadable module support enabled in my
kernels at all.  But I don't think NetBSD shares those points of view;
am I wrong?

>> None of these problems arise when [...]
> None of those problems are really problems except [...]

I think a less biased way of putting this would be that you think those
problems should be worked around.  That a workaround exists doesn't
mean a problem isn't a problem.

> If you think no library API should work this way, however, then you
> don't have to start with fixing mine; POSIX C libraries are full of
> them so you can work on those instead.

That there are other instances of problem XYZ does not make it
inappropriate to speak out against new instances of problem XYZ.
(Whether this is actually a case of that may be arguable, but I don't
think the basic principle that speaking out against an instance of
something is reasonable even if there are other instances of it extant
is wrong.)

> You clearly have an opinion, and I might even have an opinion, but
> all my experience writing code for other people to use tells me that
> if you try to enforce your subjective opinions at a library interface
> then often the only result of that is that people with other opinions
> (perhaps better supported by contextual facts than yours are) won't
> use it.  I hence prefer to leave as many of those decisions as
> possible to the user of the library.

Your way enforces things just as mine does; they're just different
things.  That you differ from me on their relative importance doesn't
mean you're not imposing your design preferences on the library's
caller just as much as any other design does.

If you really want to allow the caller designer the freedom to make
those choices, you need to support both kinds of interfaces.  You need
to both provide some kind of object definition so that callers can
allocate it when that way works better for them and you need to provide
some kind of *_alloc() and *_free() interface so that callers to whom
the tradeofffs go the other way can do that instead.  (You still wind
up with at least one of the non-opacity issues that way, but it's not
possible to avoid that unless you go completely opaque, which makes the
caller-allocates style close to impossible.)

/~\ The ASCII                             Mouse
\ / Ribbon Campaign
 X  Against HTML                mouse%rodents-montreal.org@localhost
/ \ Email!           7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Home | Main Index | Thread Index | Old Index