strndup: RFC

W

websnarf

Roland said:
strdup, getline and other functions require deallocation by the user.

So does malloc, calloc, and realloc. In a very similar sense, so does
fopen.
They were deliberately excluded from the C Standards.

Indeed, and gets was deliberately kept in, and the C *language* is
responsible for something like 75% of all security exploits in
existence. At this point, someone should call 3 strikes and you're
out.
[...] Not by
oversight, not because they were difficult to implement, not because
they wouldn't have been 'useful'.

And not for any good reason either. I would have some sympathy if they
demanded a name change to: strcpyalloc. Then they could assert a
simple naming pattern: functions ending in "alloc" need to return their
allocated storage to free(). Whatever, I wouldn't take any action by
the C standard committee to suggest that such a course of action is
even plausibly rational.
 
W

websnarf

Roland said:
It's bad style.

Yes, but that would make it more consistent with C's design. I mean
the C language makes myspace.com look elegant and attractive.
[...] The responsibility for deallocation becomes unclear.
In your program you have some functions that return a char* that must
be freed and other functions retruning char* without that requirement:
a perfect receipt for a leaking program.

This sounds like an argument for removing malloc/calloc/realloc and
fopen from the standard.
Moreover, functions like getline foster an inefficient style. They
dynamically allocate memory for each line even when most of the lines
would fit into a char[80] buffer and only exceptional cases needed
dynamic allocation.

You sir, are the kind of person that virus/exploit writers have wet
dreams about. They know you exist, and they spend their time
fantasizing about you.
Why should they abandon good style?

Doesn't that assume they had some good style that they were abandoning
in the first place?
 
R

Roland Pibinger

But it's clearer to write

FILE* log = fopen(...);
write_log_header (log);
fclose (log);
That's a good example. In effect, the function is a wrapper around
fopen().

Where do you find that style? Certainly not in K&R.
If you absolutely insist on having strict pairings of
functions for allocation and deallocation, you could write
FILE *open_log(int i);
int close_log(FILE *log);
but close_log would do exactly the same thing as fclose().

The point of open_log and close_log is that they refer to a 'log
device' which needs not be a file. When you use FILE* in the interface
you cannot change the log destination without breaking user code. You
probably also use a write_log function (instead of fwrite) which
prepends the log enty with a timestamp, line number, ...
In general, some functions allocate resources, and other functions
deallocate those same resources. Having a strict one-to-one mapping
between the two can be helpful, I suppose, but IMHO it's not strictly
necessary.

It's not necessary but it helps you create large-scale applications.
It's an important idiom to keep track of the resources in a C program.

Even the standard memory allocation functions don't do
this; malloc() and calloc() both allocate memory, free() deallocates
it, and realloc() potentially does both. The clean symmetry of
fopen() and fclose() is broken by freopen().

Not by freopen() which just associates the existing stream with a new
file.
Programmers simply have to *read the documentation* to find out which
function does what.

Yes, always, but that's not the point here.
The interface described by the documentation
should be as simple as possible, but no simpler. If it makes sense to
have a strict pairing of allocators and deallocators, by all means do
that; if it doesn't, don't.

Programming in any language becomes manageable only when people adhere
to certain styles and idioms. If you merely knew the language syntax
you would know handly anything of a language. IMO, it's important to
propagate idioms that 'work' and warn of those that don't.
(In OO terms, there's no requirement to have exactly one constructor
and exactly one destructor for a given type.)

I don't see a problem in more than one open/create/init function per
'object', e.g. open_log1(), open_log2(), ...

Best regards,
Roland Pibinger
 
R

Richard Bos

But it's clearer to write

FILE* log = fopen(...);
write_log_header (log);
fclose (log);

Says you. You're probably right if it happens once. But if you have over
a dozen places in your program where you start a log file?
Where do you find that style? Certainly not in K&R.

I don't find so many styles in K&R. I don't think you'll find sparse
arrays in K&R. Does that mean we shouldn't use them?
Yes, always, but that's not the point here.

Yes, it is. If you read the documentation for start_logfile(), you will
read that you need to call fclose() to close the log file. If you do not
read that documentation, you will indeed be completely puzzled by this
"unclear" style, but then you're a fool.
Programming in any language becomes manageable only when people adhere
to certain styles and idioms. If you merely knew the language syntax
you would know handly anything of a language. IMO, it's important to
propagate idioms that 'work' and warn of those that don't.

And this idiom works. IMnot very humbleO _and_ E.

Richard
 
S

Stan Milam

Richard said:
What should the compiler do with the following code, if such a flag is in
operation?

#include <stddef.h>
void foo(int *p, int *q, size_t len)
{
while(len--)
{
*p++ = *q++;
}
}

Do we need a compiler error ("Error: undefined behaviour in foo()") here, or
not? The answer is: it all depends. Specifically, it depends on how the
function is called. And the compiler might never see this code and the
calling code in the same invocation.

If that is what it takes, then yes. And what I meant was that before
any function made its way into a production library or program it would
have to be compiled with said flag. You can remove all of the ambiguity
of the above code:

for (; len; p++, q++, len-- ) *p = *q;

Which is what is happening and what you intended.


--
Regards,
Stan Milam
=============================================================
Charter Member of The Society for Mediocre Guitar Playing on
Expensive Instruments, Ltd.
=============================================================
 
S

Stan Milam

CBFalconer said:
In part because I disapprove of global variables.

Well, at least we have one thing in common.


--
Regards,
Stan Milam
=============================================================
Charter Member of The Society for Mediocre Guitar Playing on
Expensive Instruments, Ltd.
=============================================================
 
A

Arthur J. O'Dwyer

Richard Heathfield wrote:
[re: a hypothetical compiler flag "-warn-on-UB"]
If that is what it takes, then yes. And what I meant was that before any
function made its way into a production library or program it would have to
be compiled with said flag. You can remove all of the ambiguity of the above
code:

for (; len; p++, q++, len-- ) *p = *q;

Which is what is happening and what you intended.

However, you have not removed any of the possible undefined behaviors
of that code. (IMO, your revised version is harder to read, too, so it
looks like a lose-lose!)

Consider that *p++ increments p, /then/ dereferences it; and then
consider what happens if p's value is null or indeterminate.

-Arthur
 
C

CBFalconer

Stan said:
If that is what it takes, then yes. And what I meant was that
before any function made its way into a production library or
program it would have to be compiled with said flag. You can remove
all of the ambiguity of the above code:

for (; len; p++, q++, len-- ) *p = *q;

Which is what is happening and what you intended.

Why obfuscate the original, and simple:

while (len--) *p++ = *q++;
 
R

Richard Heathfield

Stan Milam said:

And what I meant was that before
any function made its way into a production library or program it would
have to be compiled with said flag. You can remove all of the ambiguity
of the above code:

for (; len; p++, q++, len-- ) *p = *q;

If I understand you correctly, your ideal compiler would reject this code
because it might exhibit undefined behaviour.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top