Arraym malloc() and free() question

M

Michael Wojcik

You're right, it is. The "almost" was intended either to cover either
ancient non-conforming compilers or my own laziness in failing to take
the time to convince myself that a diagnostic is mandatory.

There's also the case where stdlib.h is not included but the code
supplies its own prototype for malloc. No constraint is violated
(by the use of malloc without a cast), so the implementation need
not issue a diagnostic, but the code still invokes undefined
behavior.

This says nothing about why casting the return value of malloc is
a bad idea, of course. It's just another justification for that
"almost".

--
Michael Wojcik (e-mail address removed)

Duck: No secret what's worth a hoot ought to be kept quiet.
Pogo: Secrets is usually perty doggone fascinatin'.
Duck: Egg-zackly ... it's completely illogical to keep a secret secret.
Pogo: An' unfair. -- Walt Kelly
 
D

Dave Vandervies

Michael Wojcik said:
There's also the case where stdlib.h is not included but the code
supplies its own prototype for malloc. No constraint is violated
(by the use of malloc without a cast), so the implementation need
not issue a diagnostic, but the code still invokes undefined
behavior.

If you've given your own prototype for malloc, yes, because you Really
Do Need size_t for it. (Unless you've included <stddef.h> instead of
<stdlib.h>.) But you're invoking undefined behavior by giving it the
wrong argument type, not by using the wrong return type.

If you've given a declaration with a correct return type and call it
with an argument of the correct type, like this:
--------
void *malloc();
int *malloc_an_int()
{
return malloc(sizeof int);
}
--------
then you're not invoking undefined behavior, only bad form.

If you've given a declaration with an incorrect return type:
--------
malloc(); /*implicit int - incorrect*/
/*-OR-*/
int malloc(); /*explicit incorrect return type*/
--------
then assigning the return value without a cast is still a constraint
violation.


dave
 
E

Eric Sosman

Dave said:
If you've given a declaration with a correct return type and call it
with an argument of the correct type, like this:
--------
void *malloc();
int *malloc_an_int()
{
return malloc(sizeof int);
}

It's implementation-specified whether this invokes
undefined behavior. `size_t' might be a type that is
subject to argument promotions in the absence of a
prototype, and then you'd be calling malloc() with the
promoted type rather than the expected type.

Let's summarize all this blather about calling
undeclared functions with one piece of advice: Don't.
See the commentary on the Fourth Commandment at

http://www.lysator.liu.se/c/ten-commandments.html
 
K

Keith Thompson

Herbert Rosenau said:
It IS undefined behavior to convert an by malloc not used int variable
to a pointer. Ther is nothing that says that a function returnin void*
must set up the place the caller thinks a function returning int uses
as result. There is nothing that defines that a voud* has the same
size, alignment... as an int - so undefined behavior is invoked. Read
the standard!

I didn't say anything about a function returning int.

The original program does invoke undefined behavior, because there's
no declaration for malloc (because there's no #include <stdlib.h>).
But that's not what you said. You said that "casting the result of an
function returning a pointer to void invokes undefined behavior".

Taken literally, your statement implies that the following:

#include <stdlib.h>
int main()
{
int *ptr;
ptr = (int*)malloc(sizeof(int));
return 0;
}

invokes undefined behavior. It doesn't.

I'm sure that wasn't what you meant, but I was responding to what you
actually wrote.
 
D

Dan Pop

There's also the case where stdlib.h is not included but the code
supplies its own prototype for malloc. No constraint is violated
(by the use of malloc without a cast), so the implementation need
not issue a diagnostic, but the code still invokes undefined
behavior.

I can't see any undefined behaviour if the code supplies the correct
prototype for malloc. Which is perfectly possible, because there are
several other headers defining size_t.

Dan
 
D

Dan Pop

In said:
It's implementation-specified whether this invokes

Nope, it is implementation-specific but not implementation-specified.
There is nothing in the C standard requiring an implementation to specify
how size_t is defined.
undefined behavior. `size_t' might be a type that is
subject to argument promotions in the absence of a
prototype, and then you'd be calling malloc() with the
promoted type rather than the expected type.

OTOH, you're not going to find such a pathological implementation in the
real world. There is NO *good* reason for making size_t shorter than
unsigned int on a hosted implementation (and freestanding implementations
need not provide malloc in the first place).

Dan
 
D

Dan Pop

In said:
Except in C99.

In C99 this whole discussion is pointless: calling malloc without a
declaration in scope no longer invokes undefined behaviour, a diagnostic
is required.

Dan
 
L

Lawrence Kirby

....


In C99 this whole discussion is pointless: calling malloc without a
declaration in scope no longer invokes undefined behaviour, a diagnostic
is required.

Certainly, but the discussion didn't make this clear.

Lawrence
 
M

Michael Wojcik

I can't see any undefined behaviour if the code supplies the correct
prototype for malloc. Which is perfectly possible, because there are
several other headers defining size_t.

I had forgotten about the C90 7.1.7 exception to the "declaring
identifiers in the standard library" UB rule (7.1.3). Though I note
that the actual text in 7.1.7 is:

Provided that a library function can be declared without reference
to any type defined in a header, it is also permissible to declare
the function, either explicitly or implicitly, and use it without
including its associated header.

Read literally, that would exclude providing your own declaration for
malloc, even if you had included another header that defined size_t.
The text says "without reference to any type defined in a header" -
it makes no mention of whether such a header has been included.

I suspect that's an error in the standard, and the intent was more
along the lines of "without reference to any type defined in a header
not included prior to the declaration of the library function". (I
note Phillipp Dopichaj made this same observation here in 1999, but
I was unable to find any further discussion of the issue here or in
comp.std.c.)

--
Michael Wojcik (e-mail address removed)

The surface of the word "profession" is hard and rough, the inside mixed with
poison. It's this that prevents me crossing over. And what is there on the
other side? Only what people longingly refer to as "the other side".
-- Tawada Yoko (trans. Margaret Mitsutani)
 
D

Dan Pop

I had forgotten about the C90 7.1.7 exception to the "declaring
identifiers in the standard library" UB rule (7.1.3). Though I note
that the actual text in 7.1.7 is:

Provided that a library function can be declared without reference
to any type defined in a header, it is also permissible to declare
the function, either explicitly or implicitly, and use it without
including its associated header.

Read literally, that would exclude providing your own declaration for
malloc, even if you had included another header that defined size_t.
The text says "without reference to any type defined in a header" -
it makes no mention of whether such a header has been included.

The text doesn't say "without reference to any type defined in *any*
header", it clearly talks about the header that is not included. There
is nothing wrong if I declare malloc using the definition of size_t
provided by <stdio.h>, I'm still not referring to any type defined in
<stdlib.h>, the standard doesn't require anywhere that the declaration
of malloc() must use the definition of size_t provided by the header
associated with malloc().

Dan
 
B

Ben Pfaff

I had forgotten about the C90 7.1.7 exception to the "declaring
identifiers in the standard library" UB rule (7.1.3). Though I note
that the actual text in 7.1.7 is:

Provided that a library function can be declared without reference
to any type defined in a header, it is also permissible to declare
the function, either explicitly or implicitly, and use it without
including its associated header.

Read literally, that would exclude providing your own declaration for
malloc, even if you had included another header that defined size_t.
The text says "without reference to any type defined in a header" -
it makes no mention of whether such a header has been included.

But you *can* declare malloc without reference to a type defined
in a header:
void *malloc();
 
M

Michael Wojcik

The text doesn't say "without reference to any type defined in *any*
header", it clearly talks about the header that is not included.

It most certainly does not. It says "a header"; to refer only to the
header that would have provided a declaration for the function, it
would have used the definite article.

The second paragraph of 7.1.7 is misworded. That's all there is to it.

--
Michael Wojcik (e-mail address removed)

Pocket #16: A Ventriloquist's "Helper" -- Recordings for Divers Occasions,
especially cries to put in the mouths of enemies -- "God Bless Captain
Vere!" "Les jeux sont faits!" &c. -- Joe Green
 
M

Michael Wojcik

But you *can* declare malloc without reference to a type defined
in a header:
void *malloc();

Yes, yes, fine. You could not call malloc with only such a
declaration in scope, with an argument that was neither a type
compatible with size_t nor promoted to such a type under the default
promotions. I really don't care. What I found moderately
interesting is that the text of 7.1.7 is wrong.
 
L

Lawrence Kirby

But you *can* declare malloc without reference to a type defined in a
header:
void *malloc();

However this isn't portable. C90 6.1.2.6 says:

"All declarations that refer to the same object or function shall have
compatible type; otherwise the behavior is undefined.

And C90 6.5.4.3 says for function declaration compatibility:

"If one type has a parameter type list and the other is specified by a
function declarator that is not part of a function definition and that
contains an empty identifier list, the parameter list shall not have an
ellipsis terminator and the type of each parameter shall be compatible
with the type that results from the application of the default argument
promotions."

Essentially if the the default argument promotions change the type of
size_t then simply having the declaration void *malloc() in a program
results in undefined behaviour, even if you don't call malloc().

There is an assumption here that standard library functions have an
implicit declaration for a user-defined declaration one to be incompatible
with for 6.1.2.6. 6.1.2.6 does apply to declarations in different
translation units, but standard library functions are tricky in this
respect.

Lawrence
 
B

Ben Pfaff

Lawrence Kirby said:
However this isn't portable. C90 6.1.2.6 says:

"All declarations that refer to the same object or function shall have
compatible type; otherwise the behavior is undefined.

Thanks for the insightful reading. I had never mentally
connected those paragraphs in that way, but it seems clear that
you are correct.
 
D

Dan Pop

In said:
But you *can* declare malloc without reference to a type defined
in a header:
void *malloc();

Indeed, but the C standard doesn't guarantee that this is a *correct*
declaration for malloc. Admittedly, it would fail only on pathological
implementations, but using it would ruin the strict conformance of a
program.

Dan
 
D

Dan Pop

It most certainly does not. It says "a header"; to refer only to the
header that would have provided a declaration for the function, it
would have used the definite article.

The second paragraph of 7.1.7 is misworded. That's all there is to it.

Since you seem to be the only one interpreting it that way, you may want
to take the issue to comp.std.c.

Dan
 

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

Forum statistics

Threads
474,150
Messages
2,570,853
Members
47,394
Latest member
Olekdev

Latest Threads

Top