By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,930 Members | 1,381 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,930 IT Pros & Developers. It's quick & easy.

Index out of bounds question

P: n/a
Say I have the following:

int main(void) {
char* p, q;
p = (char*) malloc(sizeof(char)*10);
q = (p + 100) - 99; /* legal? */
free(q - 1); /* legal? */
....
return 0;
}

Will this program always produce UB, always work, or is it compiler
dependent?
Nov 14 '05 #1
Share this Question
Share on Google+
26 Replies


P: n/a
Method Man wrote:
Say I have the following:
#include <stdlib.h>
int main(int argc, char* argv[]) {
char* p = (char*)malloc(sizeof(char)*10);
char* q = (p + 100) - 99; // illegal!
free(q - 1); // illegal!
// ....
return 0;
} Will this program always produce UB?
This is an improper question.
Undefined Behavior (UB) is undefined.
There is no specific behavior to "produce".
Always work?
It works everywhere.
Or is it compiler dependent?


There are no ANSI/ISO C99 compliant compilers
that will not accept this code
and generate the expected output.
Nov 14 '05 #2

P: n/a
"Method Man" <a@b.c> writes:
Say I have the following:

int main(void) {
char* p, q;
This is deceptive syntax. It *looks* like it's meant to declare
two pointers, but it *actually* declares a pointer and an
integer.
p = (char*) malloc(sizeof(char)*10);
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.

* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.

Some others do disagree, such as P.J. Plauger (see article
<9s*****************@nwrddc01.gnilink.net>).

When calling malloc(), I recommend using the sizeof operator on
the object you are allocating, not on the type. For instance,
*don't* write this:

int *x = malloc (128 * sizeof (int)); /* Don't do this! */

Instead, write it this way:

int *x = malloc (128 * sizeof *x);

There's a few reasons to do it this way:

* If you ever change the type that `x' points to, it's not
necessary to change the malloc() call as well.

This is more of a problem in a large program, but it's still
convenient in a small one.

* Taking the size of an object makes writing the statement
less error-prone. You can verify that the sizeof syntax is
correct without having to look at the declaration.

Finally, sizeof(char) is always 1.
q = (p + 100) - 99; /* legal? */
Constraint violation that requires a diagnostic. See C99
6.5.16.1 "Simple assignment". Also, the pointer arithmetic
yields undefined behavior, because you're going beyond
one-past-the-end in an array.
free(q - 1); /* legal? */
Also a constraint violation. See C99 6.5.2.2 "Function calls"
para 2.
....
return 0;
}

Will this program always produce UB, always work, or is it compiler
dependent?


It won't compile without diagnostics. It also produces undefined
behavior.
--
Ben Pfaff
email: bl*@cs.stanford.edu
web: http://benpfaff.org
Nov 14 '05 #3

P: n/a
In article <sp*****************@read1.cgocable.net>, Method Man <a@b.c> wrote:
Say I have the following:

int main(void) {
char* p, q;
p = (char*) malloc(sizeof(char)*10);
Don't Do That.
This line is broken, since you forgot to #include <stdlib.h>; the compiler
incorrectly assumes (as required by the language definition) that malloc
returns int, and your cast prevents it from complaining about attempting
an invalid conversion (from int to pointer).
Preferred form:
p = malloc(10 * sizeof *p);
Since sizeof(char) is required to be 1, in this case you can even do:
p = malloc(10);
q = (p + 100) - 99; /* legal? */
No, but unlikely to cause problems on systems with a flat memory space
and general-purpose registers used for both pointer and integer operations
(that is, pretty much any system you're ever likely to use).
free(q - 1); /* legal? */
If q is a valid pointer to 1 past the pointer you got from malloc (which,
as noted above, is the only result you're likely to see from the line
above), this is legal and will do exactly what you appear to expect.
....
Badly formed code.
return 0;
}
Will this program always produce UB, always work, or is it compiler
dependent?


Always produce UB, and almost always (but compiler and, more likely,
hardware dependent) do the "exactly what you expect" that's the worst
possible kind of UB (except perhaps the "exactly what you expect, until
somebody important is watching" kind).

A system that checks every pointer value generated (such systems are
well within the bounds of the requirements on implementations, though
I'm not sure if any actually exist) can trap after evaluating `(p+100)'
(the left operand of the '-' operator in the line of code you're asking
about), since this generates a pointer that's 90 bytes past the end
of the chunk of memory allocated by malloc. Most systems only check
pointers (if at all) when you dereference them and not when you create
them, and since you never dereference this particular invalid pointer,
this check won't catch it.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
Since you're a hobbyist, I'm sure you'll want to write the code more
correctly than a mere professional might do.
--Richard Heathfield in comp.lang.c
Nov 14 '05 #4

P: n/a
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> writes:
Method Man wrote:
Say I have the following:


#include <stdlib.h>
int main(int argc, char* argv[]) {
char* p = (char*)malloc(sizeof(char)*10);
char* q = (p + 100) - 99; // illegal!
free(q - 1); // illegal!
// ....
return 0;
}

Will this program always produce UB?


This is an improper question.
Undefined Behavior (UB) is undefined.
There is no specific behavior to "produce".
Always work?


It works everywhere.
Or is it compiler dependent?


There are no ANSI/ISO C99 compliant compilers
that will not accept this code
and generate the expected output.


Tisdale has lied to us yet again. The code quoted above is not what
Method Man wrote. It's obvious that Tisdale isn't going to respond to
complaints, so I'll just post this as a warning to others.

The actual code was:

] int main(void) {
] char* p, q;
] p = (char*) malloc(sizeof(char)*10);
] q = (p + 100) - 99; /* legal? */
] free(q - 1); /* legal? */
] ....
] return 0;
] }

Method Man's code had serious error: "char *p, q;" declares p as a
pointer to char, and q as a char. Tisdale, for some unfathomable
reason, decided to quietly pretend the error didn't exist rather than
tell Method Man about it.

(Note to Mabden: Based on your past behavior I expect you'll jump in
and flame me for calling Tisdale on his lie. I know your opinion on
the matter and I'm really not interested in hearing about it again.)

Assuming the declaration is corrected to

char *p, *q;

the evaluation of p + 100 invokes undefined behavior, because it
yields a value outside the bounds of the memory allocated by malloc().
Once undefined behavior is invoked, all bets are off.

If you change the statement
q = (p + 100) - 99;
to
q = (p + 10) - 9;
there's no problem; p+10 points just past the last element of the
allocated memory (which is ok as long as you don't dereference it),
and q then points to p[1]. q - 1 is then equal to p, and passing that
value to free() is valid.

Will it "work"? Quite possibly. The possible consequences of
undefined behavior always include behaving just as you expect
(assuming you have any expectation). It may or may not be the case
that the code "works" in all existing implementations, but a
bounds-checking implementation with fat pointers could easily trap.
The only sensible thing to do is avoid the undefined behavior in the
first place.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #5

P: n/a
E. Robert Tisdale wrote:
Method Man wrote:
Say I have the following:


#include <stdlib.h>

int main(int argc, char* argv[]) {
char* p = (char*)malloc(sizeof(char)*10);
char* q = (p + 100) - 99; // illegal!


Excuse me, Sir, but you are mis-quoting the Man.

Don't do that.

--
Chris "electric hedgehog" Dollin
Nov 14 '05 #6

P: n/a
Chris Dollin <ke**@hpl.hp.com> scribbled the following:
E. Robert Tisdale wrote:
Method Man wrote:
Say I have the following:
#include <stdlib.h>

int main(int argc, char* argv[]) {
char* p = (char*)malloc(sizeof(char)*10);
char* q = (p + 100) - 99; // illegal!

Excuse me, Sir, but you are mis-quoting the Man. Don't do that.


Telling Tisdale not to mis-quote people is like telling P.J.Plauger not
to advertise his compiler, Dan Pop not to tell people to engage their
brains, or me not to insult people. I.e. like talking to a brick wall.

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-------------------------------------------------------- rules! --------/
"This is a personnel commuter."
- Train driver in Scientific American
Nov 14 '05 #7

P: n/a
In <ck**********@oravannahka.helsinki.fi> Joona I Palaste <pa*****@cc.helsinki.fi> writes:
Telling Tisdale not to mis-quote people is like telling P.J.Plauger not
to advertise his compiler,


Huh?!?

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #8

P: n/a
In article <ck**********@sunnews.cern.ch>, Dan Pop <Da*****@cern.ch> wrote:
In <ck**********@oravannahka.helsinki.fi> Joona I Palaste
<pa*****@cc.helsinki.fi> writes:
Telling Tisdale not to mis-quote people is like telling P.J.Plauger not
to advertise his compiler,


Huh?!?


Since, as far as I know, PJP doesn't have a compiler to advertise,
telling him not to advertise it wouldn't do much good, would it?

(Though I think Joona really meant to say Jacob Navia here.)
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
I should also have said that it's perfectly possible to do this in
multiple dimensions. Just hurts a bit to think about...
--Peter Boyle in comp.arch
Nov 14 '05 #9

P: n/a
Dave Vandervies <dj******@csclub.uwaterloo.ca> scribbled the following:
In article <ck**********@sunnews.cern.ch>, Dan Pop <Da*****@cern.ch> wrote:
In <ck**********@oravannahka.helsinki.fi> Joona I Palaste
<pa*****@cc.helsinki.fi> writes:
Telling Tisdale not to mis-quote people is like telling P.J.Plauger not
to advertise his compiler,
Huh?!?

Since, as far as I know, PJP doesn't have a compiler to advertise,
telling him not to advertise it wouldn't do much good, would it? (Though I think Joona really meant to say Jacob Navia here.)


Yes, I meant Jacob Navia. Sorry.

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-------------------------------------------------------- rules! --------/
"C++ looks like line noise."
- Fred L. Baube III
Nov 14 '05 #10

P: n/a

"Method Man" <a@b.c> wrote

int main(void) {
char* p, q;
p = (char*) malloc(sizeof(char)*10);
q = (p + 100) - 99; /* legal? */
technically not, since p + 100 could load an illegal address into an address
register and trigger a trap, or something equally nasty.
free(q - 1); /* legal? */
covered by the first question. On most systems it will of course free the
pointer allocated by malloc(), but a perverse implementation or one with
funny constraints could crash you whilst keeping within the standard.
return 0;
}

Will this program always produce UB, always work, or is it compiler
dependent?

It is always UB. However on most systems the UB will be "correct" behaviour.
Nov 14 '05 #11

P: n/a

"Method Man" <a@b.c> wrote in message
news:sp*****************@read1.cgocable.net...
Say I have the following:

int main(void) {
char* p, q;
p = (char*) malloc(sizeof(char)*10);
q = (p + 100) - 99; /* legal? */
free(q - 1); /* legal? */
....
return 0;
}

Will this program always produce UB, always work, or is it compiler
dependent?


Thanks for the answers. Apologies for the missing stdlib.h header and
misdeclared char* pointer. I was a bit over-anxious. ;-)

I thought that the C standard might have a rule for performing the constant
arithmetic first (for efficiency reasons) so that 'q = (p + 100) - 99' would
always evaluate to 'q = p + 1'. So I've learned, this is not the case and UB
should be expected (regardless if it's right or wrong).
Nov 14 '05 #12

P: n/a
In article <DX*****************@read1.cgocable.net>, Method Man <a@b.c> wrote:
I thought that the C standard might have a rule for performing the constant
arithmetic first (for efficiency reasons) so that 'q = (p + 100) - 99' would
always evaluate to 'q = p + 1'. So I've learned, this is not the case and UB
should be expected (regardless if it's right or wrong).


Note that there's nothing stopping a compiler from recognizing that doing
the constant arithmetic first is correctness-preserving (that is, won't
make correct code incorrect) and doing it, preventing this (incorrect)
code from causing a bad pointer to be generated as a side effect.

Undefined behavior is like that; there are no requirements on it (except
as defined by something other than the C standard), so doing what you
expect (and even transforming the code into something that does what
you expect without invoking UB) is allowed. Relying on it is just Not
A Good Idea.
dave

--
Dave Vandervies dj******@csclub.uwaterloo.ca
If writing an OS for the DeathStation 9000, which UBs should invoke nasal
demons (or daemons), how many, which nostril (or nostrils) and what support
code needs to be written for them? --Geoff Field in comp.lang.c
Nov 14 '05 #13

P: n/a
E. Robert Tisdale wrote:

Method Man wrote:
Say I have the following:


#include <stdlib.h>

int main(int argc, char* argv[]) {
char* p = (char*)malloc(sizeof(char)*10);
char* q = (p + 100) - 99; // illegal!
free(q - 1); // illegal!
// ....
return 0;
}

Will this program always produce UB?


This is an improper question.
Undefined Behavior (UB) is undefined.
There is no specific behavior to "produce".


The answer to the question is "yes"

3.18
[#1] undefined behavior
behavior, upon use of a nonportable or erroneous program
construct, of erroneous data, or of indeterminately valued
objects, for which this International Standard imposes no
requirements
[#2] NOTE Possible undefined behavior ranges from ignoring
the situation completely with unpredictable results, to
behaving during translation or program execution in a
documented manner characteristic of the environment (with or
without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of
a diagnostic message).
[#3] EXAMPLE An example of undefined behavior is the
behavior on integer overflow.

--
pete
Nov 14 '05 #14

P: n/a
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.
How about the case where the code is intended for
both ANSI and pre-ANSI compilers?
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?
Nov 14 '05 #15

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.


How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


If you're still using a pre-ANSI compiler, I pity you. You're
working with technology that's 15 years old. Feel free to use
whatever workarounds are needed.

Most posters to this newsgroup have no such need. We tend to
assume that code is in ANSI C unless otherwise specified.
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?


I could envision an implementation that discards bits on
conversion to a pointer type with a bigger-than-byte required
alignment. In general, converting from A* to B* via C* is not
guaranteed to work.
--
Ben Pfaff
email: bl*@cs.stanford.edu
web: http://benpfaff.org
Nov 14 '05 #16

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.


How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


Then you've got more problems than deciding whether to cast the result
of malloc(). You can't use prototypes (except perhaps conditionally),
you can't assume that malloc is declared in <stdlib.h> rather than in,
say, <malloc.h>, etc. etc.

Fortunately, the need to write pre-ANSI-compatible C has pretty much
vanished. (I think the latest gcc even assumes an ANSI-compliant
bootstrap compiler.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #17

P: n/a
Ben Pfaff <bl*@cs.stanford.edu> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.
How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


If you're still using a pre-ANSI compiler, I pity you.


I don't normally use such compilers myself. Certain software
that I work on forces me to consider such issues. But I'll
gladly accept the pity. :)

Most posters to this newsgroup have no such need. We tend to
assume that code is in ANSI C unless otherwise specified.


Right; that's why I posed the question as a question and
specifically mentioned pre-ANSI compilers. Other things
being equal, it seems like more widely applicable is better.
So in some sense the question is, how unequal are the two
things? That may be weighted by the relative likelihood
of the different environments if one wishes.

* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?


I could envision an implementation that discards bits on
conversion to a pointer type with a bigger-than-byte required
alignment. In general, converting from A* to B* via C* is not
guaranteed to work.


You're right; that could cause a problem. Does that case
ever come up if the types on the two sides have been checked?
It seems to me that this could cause a problem only if some
conversion has been invoked unknowingly, and I don't see a way
for that to happen in the presence of good type checking.

Nov 14 '05 #18

P: n/a
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.


How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


Then you've got more problems than deciding whether to cast the result
of malloc(). You can't use prototypes (except perhaps conditionally),
you can't assume that malloc is declared in <stdlib.h> rather than in,
say, <malloc.h>, etc. etc.

Fortunately, the need to write pre-ANSI-compatible C has pretty much
vanished. (I think the latest gcc even assumes an ANSI-compliant
bootstrap compiler.)


Thank you for pointing out the obvious and failing to respond
to the question.
Nov 14 '05 #19

P: n/a
On Thu, 21 Oct 2004 01:31:01 UTC, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.
How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


See the answer from Keith.
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?


When the prototype is known to the compiler: No.

When the prototype is NOT known you lives always in undefined behavior
land - not only for malloc() but with any function returning a
pointer. The default behavior is to assume that a function returns
int. Some implermentations use different methods to return pointer
than other values. Left of the prototype and casting (int) to pointer
will result in casting something but not the (complete) pointer
returned - ending in undefined behavior. When god will your program
crashes immediately after that - when not yor program can do whatever
- starting with formatting the whole disk.

Casting is the most dangerous you can ever do. Never, never cast
something to resolve from a comiler warning. Casting is mostenly the
choce to hide the bug - but not resolve it. Whenever the compiler will
warn you you should double check and double recheck what ut really
means. The compiler is stupid enough to tell you the formal but not
the real bug. So check double and recheck double to look what the real
bug is. In case p = malloc() it is always that you have miss to
present the compiler the prototype of malloc, even when the compiler
whines something else.

Casting says the compiler only: be quite because I know what I do -
but here you knows nothing, you're lying only.

Don't cast! Don't cast anyway. Don't cast - except you knows exactly
why you needs to cast. You knows that casting us unneccessary anyway -
but there are exceptions to that - and that is the only why casting is
allwoed anyway. Casting only to get the compiler quite is an error -
ever!

--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation

Nov 14 '05 #20

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Keith Thompson <ks***@mib.org> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
> Ben Pfaff <bl*@cs.stanford.edu> writes:
>
>> I don't recommend casting the return value of malloc():
>>
>> * The cast is not required in ANSI C.
>
> How about the case where the code is intended for
> both ANSI and pre-ANSI compilers?


Then you've got more problems than deciding whether to cast the result
of malloc(). You can't use prototypes (except perhaps conditionally),
you can't assume that malloc is declared in <stdlib.h> rather than in,
say, <malloc.h>, etc. etc.

Fortunately, the need to write pre-ANSI-compatible C has pretty much
vanished. (I think the latest gcc even assumes an ANSI-compliant
bootstrap compiler.)


Thank you for pointing out the obvious and failing to respond
to the question.


My pleasure. 8-)}

Sorry, I assumed the question was hypothetical. If you actually need
to worry about pre-ANSI compilers, I'm not sure how much I can help
you (or how much you already know).

There's a tool called "ansi2knr" (google it) that converts, or at
least attempts to convert, ANSI C to K&R C. It doesn't necessarily do
the whole job; I think it deals mainly with function prototypes.

I know K&R C has malloc() returning char* (because it has no void*
type). I don't remember whether it requires a cast when assigning the
result to another pointer type, but I think pre-ANSI compilers tended
to be more permissive about implicit conversions. It also depends on
the compiler; remember, there was no real standard back then.

The obvious brute-force approach is to use "#ifdef __STDC__" and
provide K&R and ANSI versions of any incompatible code. The result is
ugly, but it makes it fairly easy to strip out the K&R stuff if that
requirement finally goes away.

Or you can write pure ANSI code and invoke ansi2knr as part of your
build process. If the result isn't compilable, you might be able to
do some ad-hoc patching, but that might be more effort than it's
worth.

One thing to watch out for is function arguments of types char, short
(and their signed and unsigned variants) and float. In K&R-style
functions, these types are promoted to int or double; in ANSI-style
functions, they're not.

Of course if casting the result of malloc() makes your job easier, go
ahead and do it, perhaps wrapping it in a macro. Just make sure that
<stdlib.h> is included when you compile in ANSI mode.

Your goal, IMHO, should be to move away from the dependency on K&R C
as soon as you can. To state the obvious yet again, it's been 15
years.

--
keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 14 '05 #21

P: n/a
In <kf*************@alumnus.caltech.edu> Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.


How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


If the implementation is pre-ANSI, there may be no malloc() at all in its
library. Even if there is, what is the expected type of its argument?

Your best bet with pre-ANSI compilers is to cast, but this is not going
to solve all your problems. FYI, K&R1 only mentions calloc() and its
companion is called cfree().

These days, in real life projects, you don't have to support more than
one pre-ANSI compiler. In such cases, you simply read its documentation
and see what exactly it says about malloc and about void pointers. Keep
in mind that "pre-ANSI" covers a very wide range of compilers, from those
implementing a subset of the K&R1 specification to those implementing the
same ANSI draft as the one used by the first printing of K&R2.
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted?


Nope. Either the cast is to the right type, and then it is innocuous
from the program correctness point of view or it is to the wrong type
and then a diagnostic is required.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #22

P: n/a

In article <kf*************@alumnus.caltech.edu>, Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
I don't recommend casting the return value of malloc():

* The cast is not required in ANSI C.


How about the case where the code is intended for
both ANSI and pre-ANSI compilers?


Frankly, I'd maintain separate sources, or port a C90 front end
to the environment where I didn't have a standard implementation.
(It could always target the pre-ANSI compiler.)

It's simply not worth giving up all the improvements that C90
brought to K&R C.

If your screwdriver is broken, you don't switch to fastening
everything with duct tape; you get a new screwdriver.

--
Michael Wojcik mi************@microfocus.com

This record comes with a coupon that wins you a trip around the world.
-- Pizzicato Five
Nov 14 '05 #23

P: n/a
"Herbert Rosenau" <os****@pc-rosenau.de> writes:
On Thu, 21 Oct 2004 01:31:01 UTC, Tim Rentsch
<tx*@alumnus.caltech.edu> wrote:
Ben Pfaff <bl*@cs.stanford.edu> writes:
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?


When the prototype is known to the compiler: No.


That's what I thought but it seemed sensible to double check.

When the prototype is NOT known you lives always in undefined behavior
land - not only for malloc() but with any function returning a
pointer. [more description omitted]


Right. My usual development mode includes at least one compilation
that does strict prototype checking (always require a prototype, don't
allow more than one declaration for any function). Sometimes this
means extra compilations to handle code intended for pre-ANSI
compilers or to allow macro calls to be type checked; but my
experience has been that the extra checking is worth it.

Thanks to Herbert, Ben and Dan (and anyone else I may have forgotten)
who followed up trying to help answer my questions.
Nov 14 '05 #24

P: n/a
Keith Thompson <ks***@mib.org> writes:
Your goal, IMHO, should be to move away from the dependency on K&R C
as soon as you can. To state the obvious yet again, it's been 15
years.
Oh, my goal is much broader - to get everyone else to move away from
the dependency on K&R C. :)

As I mentioned in another posting, certain code that I work on forces
me to consider such issues. I don't develop (solely) on pre-ANSI
compilers myself, but in some cases it's important to be able to
provide such code for those poor souls who do.
[ansi2knr, #ifdef __STDC__, wrapping calls to malloc()]


I've used ansi2knr, it's very helpful.

It's necessary on occasion to use things like '#ifdef __STDC__' or
other preprocessor tricks. I don't mind using these tricks but as
much as possible I try to keep them out of mainline code (always
encapsulate). Usually this includes 'malloc()' too (you also
suggested wrapping malloc):

#define ALLOCATE(n,t) ( (t*) malloc( n * sizeof(t) ) )

Of course it doesn't work for some choices of type arguments, but
that's C syntax for you.

Thank you for the other clarifications.

Nov 14 '05 #25

P: n/a
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
#define ALLOCATE(n,t) ( (t*) malloc( n * sizeof(t) ) )


Of course I meant to write:

#define ALLOCATE(n,t) ( (t*) malloc( (n) * sizeof(t) ) )

I would never leave macro expression-parameters unwrapped
in a publically used macro.
Nov 14 '05 #26

P: n/a
In <87************@benpfaff.org> Ben Pfaff <bl*@cs.stanford.edu> writes:
Tim Rentsch <tx*@alumnus.caltech.edu> writes:
Ben Pfaff <bl*@cs.stanford.edu> writes:
* Casting its return value can mask a failure to #include
<stdlib.h>, which leads to undefined behavior.

* If you cast to the wrong type by accident, odd failures can
result.


Just curious - if stdlib.h has been #include'd, can there
still be odd failures when a malloc() return value has
been casted? If so then what are some examples?


I could envision an implementation that discards bits on
conversion to a pointer type with a bigger-than-byte required
alignment. In general, converting from A* to B* via C* is not
guaranteed to work.


In general, casting to the wrong type by accident *requires* a diagnostic.
The assignment operator involved in a malloc call only converts from
void pointer to the target pointer type.

No way for odd failures to *silently* result.

Dan
--
Dan Pop
DESY Zeuthen, RZ group
Email: Da*****@ifh.de
Currently looking for a job in the European Union
Nov 14 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.