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

size_t or int for malloc-type functions?

P: n/a
Rcently I posted code in this group, to help a user
that asked to know how he could find out the size of
a block allocated with malloc.

As always when I post something, the same group
of people started to try to find possible errors,
a harmless passtime they seem to enjoy.

One of their remarks was that I used "int" instead of
"size_t" for the input of my allocator function.

As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.

I researched a bit the subject, and I found a type

ssize_t

The name is defined for instance in
http://www.delorie.com/gnu/docs/glibc/libc_239.html

Data Type: ssize_t
This data type is used to represent the sizes of blocks that can be
read or written in a single operation. It is similar to size_t, but must
be a signed type.

Another reference to this type appears in:
http://bochs.sourceforge.net/cgi-bin...dent?i=ssize_t
with
#define ssize_t long

This concern with the usage of an unsigned type that can be
easily lead to errors (of course only for people that do
make errors like me...) is also expressed in the document
ISO/IEC JTC1 SC22 WG14 N1135 :
"Specification for Safer, More Secure C Library Functions"
where they propose:

Extremely large object sizes are frequently a sign that an object’s size
was calculated incorrectly. For example, negative numbers appear as very
large positive numbers when converted to an unsigned type like size_t.

Also, some implementations do not support objects as large as the
maximum value that can be represented by type size_t.

For those reasons, it is sometimes beneficial to restrict the range of
object sizes to detect programming errors.

They propose having an unsigned rsize_t, but a macro RSIZE_MAX that
would limit the range of the object size.

I post this to document why having an "int" as an argument to a
malloc-type function is not such a bad idea.

Your opinion may differ.

jacob
Dec 31 '06 #1
Share this Question
Share on Google+
318 Replies


P: n/a
"jacob navia" <ja***@jacob.remcomp.frwrote in message
news:45***********************@news.orange.fr...
Rcently I posted code in this group, to help a user
that asked to know how he could find out the size of
a block allocated with malloc.

As always when I post something, the same group
of people started to try to find possible errors,
a harmless passtime they seem to enjoy.

One of their remarks was that I used "int" instead of
"size_t" for the input of my allocator function.

As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.

I researched a bit the subject, and I found a type

ssize_t

The name is defined for instance in
http://www.delorie.com/gnu/docs/glibc/libc_239.html

Data Type: ssize_t
This data type is used to represent the sizes of blocks that can be
read or written in a single operation. It is similar to size_t, but must
be a signed type.

Another reference to this type appears in:
http://bochs.sourceforge.net/cgi-bin...dent?i=ssize_t
with
#define ssize_t long

This concern with the usage of an unsigned type that can be
easily lead to errors (of course only for people that do
make errors like me...) is also expressed in the document
ISO/IEC JTC1 SC22 WG14 N1135 :
"Specification for Safer, More Secure C Library Functions"
where they propose:

Extremely large object sizes are frequently a sign that an object’s size
was calculated incorrectly. For example, negative numbers appear as very
large positive numbers when converted to an unsigned type like size_t.

Also, some implementations do not support objects as large as the
maximum value that can be represented by type size_t.

For those reasons, it is sometimes beneficial to restrict the range of
object sizes to detect programming errors.

They propose having an unsigned rsize_t, but a macro RSIZE_MAX that
would limit the range of the object size.

I post this to document why having an "int" as an argument to a
malloc-type function is not such a bad idea.

Your opinion may differ.
The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that. Nevertheless, I regularly need to deal with objects
bigger than half the address space even today, perhaps because I
write so much systems code. So I find the choice of slicing the
address space in half arbitrary and potentially dangerous.

That's why I pushed for the notion of an RSIZE_MAX to accompany
the unsigned rsize_t that Microsoft put forth in TR 24731. You
can set it to:

-- (size_t)-1 >2 if you want the same protection as a signed
byte count

-- some other value if you know how big objects can really be,
and get maximum protection against silly sizes

-- (size_t)-1 if you want to turn the damned checking off

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Dec 31 '06 #2

P: n/a
P.J. Plauger a écrit :
>
The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that.
Yes. I see this too as a problem, but then, in such small
systems, the amount of ram tends to be very small too, and
the situation remains the same.

In a DSP I used last year the total amount of RAM was
4K, so a sizeof(int) 16 bits I had plenty of space
anyway :-)

Nevertheless, I regularly need to deal with objects
bigger than half the address space even today, perhaps because I
write so much systems code.
In that case it can be useful to have two sets of malloc functions
maybe, one for the small allocations, and another for the "big"
ones.
So I find the choice of slicing the
address space in half arbitrary and potentially dangerous.

That's why I pushed for the notion of an RSIZE_MAX to accompany
the unsigned rsize_t that Microsoft put forth in TR 24731. You
can set it to:

-- (size_t)-1 >2 if you want the same protection as a signed
byte count

-- some other value if you know how big objects can really be,
and get maximum protection against silly sizes

-- (size_t)-1 if you want to turn the damned checking off
Checking can be a nuisance but it can be an advantage sometimes. It
depends on the situation.

Thanks for your input.

jacob
Dec 31 '06 #3

P: n/a
jacob navia said:

<snip>
As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.
Why would you need a small negative number as an argument to malloc? Are you
trying to allocate a negative amount of memory?
>
I researched a bit the subject, and I found a type

ssize_t

The name is defined for instance in
http://www.delorie.com/gnu/docs/glibc/libc_239.html
It's a POSIX type, not a C type. Try comp.unix.programmer.

<snip>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 31 '06 #4

P: n/a
jacob navia wrote:
P.J. Plauger a écrit :
>>
The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that.

Yes. I see this too as a problem, but then, in such small
systems, the amount of ram tends to be very small too, and
the situation remains the same.
It's the same, and yet not the same. The size of a data
structure does not usually scale linearly with the width of
its constituent words. I have not worked with 16-bit machines
for a number of years now, but when I did it was not unusual to
want to allocate >32K to a single object. By contrast, I have
never needed to allocate >2G as a single object on a 32-bit
system.

YMMV, but it seems to me that the need to "use all the
bits" is more pressing on small systems than on large ones.
>Nevertheless, I regularly need to deal with objects
bigger than half the address space even today, perhaps because I
write so much systems code.

In that case it can be useful to have two sets of malloc functions
maybe, one for the small allocations, and another for the "big"
ones.
Walk that road with caution: I've been down it, and it is
twisty and dangerous, beset with bandits and worse. You need
to exercise a *lot* of discipline to segregate the memory blocks
you get from multiple allocators: If you obtain a block from a
hypothetical lmalloc() and release it with plain free(), chaos
is likely.

But then, you may be considering a different path, like an
smalloc(int) as a sanity-checker wrapped around malloc(size_t):

#include <stdlib.h>
void *smalloc(int bytes) {
return (bytes < 0) ? NULL : malloc(bytes);
}

If so, the hobgoblin of multiple allocators disappears. But
implementing smalloc() is no trick at all; you can do it for
yourself with the tools already provided, if you like. You might
want to consider leaving the argument type as size_t, though, to
give yourself more freedom in setting the failure threshold:

#include <stdlib.h>
#include <limits.h>
#define THRESHOLD ((INT_MAX / 2u + 1) * 3) /* for example */
void *smalloc(size_t bytes) {
return (bytes < THRESHOLD) ? malloc(bytes) : NULL;
}

Returning for a moment to your original motivation for using
a signed argument:
As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.
I don't see this as a big problem. If the program blunders and
asks for -42 bytes, conversion to size_t turns this into a request
for a very large amount of memory (by the machine's standards,
and assuming a size_t of similar "width" to the addresses). The
request almost certainly fails and returns NULL, with no harm
done. So instead of filtering the argument going into malloc(),
it might be more useful to monitor the result:

#include <stdlib.h>
void *zmalloc(size_t bytes) {
void *new = malloc(bytes);
if (new == NULL)
print_debugging_info();
return new;
}

This would catch absurd arguments (they'll provoke malloc()
failure) and also help track down the slobs who call malloc()
and fail to check the result for NULL. If desired, one could
also monitor the incoming argument for "reasonableness," to
help find code that's making excessively greedy requests.

--
Eric Sosman
es*****@acm-dot-org.invalid
Dec 31 '06 #5

P: n/a
Eric Sosman a écrit :
jacob navia wrote:
>P.J. Plauger a écrit :
>>>
The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that.


Yes. I see this too as a problem, but then, in such small
systems, the amount of ram tends to be very small too, and
the situation remains the same.


It's the same, and yet not the same. The size of a data
structure does not usually scale linearly with the width of
its constituent words. I have not worked with 16-bit machines
for a number of years now, but when I did it was not unusual to
want to allocate >32K to a single object. By contrast, I have
never needed to allocate >2G as a single object on a 32-bit
system.

YMMV, but it seems to me that the need to "use all the
bits" is more pressing on small systems than on large ones.
With a bit of more reflection I think you (and Mr Plauger)
have a point here Eric.

Yes, in 16 bit systems all bits may be needed, and this
may be more important than catching a wrong allocation.

jacob

Dec 31 '06 #6

P: n/a
In article <Lf******************************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>jacob navia said:

<snip>
>As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.

Why would you need a small negative number as an argument to malloc? Are you
trying to allocate a negative amount of memory?
Explanation for those (like RH) with limited ability to read between the
lines: What's going on here is the combination of buggy programming
(incompetent programmers) who calculate things and then pass the results
to library functions and buggy implementations (like Linux) that allow
all mallocs to succeed.

You put the two together, and you get chaos.

Dec 31 '06 #7

P: n/a
Richard Heathfield a écrit :
jacob navia said:

<snip>

>>As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.


Why would you need a small negative number as an argument to malloc? Are you
trying to allocate a negative amount of memory?
Can't you read?

This thread is not for you

I said in my original message:

"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"

You never do any errors heathfield since you are a "competent
C programmer". Please go away. This thread is about errors
and their prevention. You do not need it.

Dec 31 '06 #8

P: n/a
"jacob navia" <ja***@jacob.remcomp.frwrote in message
news:45***********************@news.orange.fr...
P.J. Plauger a écrit :
>>
The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that.

Yes. I see this too as a problem, but then, in such small
systems, the amount of ram tends to be very small too, and
the situation remains the same.

In a DSP I used last year the total amount of RAM was
4K, so a sizeof(int) 16 bits I had plenty of space
anyway :-)
That may be your experience, but mine has been that 16-bit systems
often have >32KB of memory. Anything that interferes with handling
all of memory in one go is sure to cause trouble, sooner or later.
>Nevertheless, I regularly need to deal with objects
bigger than half the address space even today, perhaps because I
write so much systems code.

In that case it can be useful to have two sets of malloc functions
maybe, one for the small allocations, and another for the "big"
ones.
A nice complement to the malloc(0) discussion elsegroup. My idea
of elegance is to have one function that accepts any size from 0 to
the largest representable object, and do something uniformly sane
with it. But YMMV.
>So I find the choice of slicing the
address space in half arbitrary and potentially dangerous.

That's why I pushed for the notion of an RSIZE_MAX to accompany
the unsigned rsize_t that Microsoft put forth in TR 24731. You
can set it to:

-- (size_t)-1 >2 if you want the same protection as a signed
byte count

-- some other value if you know how big objects can really be,
and get maximum protection against silly sizes

-- (size_t)-1 if you want to turn the damned checking off

Checking can be a nuisance but it can be an advantage sometimes. It
depends on the situation.
But you *always* have to check if you want to keep your program sane.
The only advantage of a signed byte count is that it makes it slightly
easier to check for a clearly bogus size. And the program had still
better check for a null pointer return from malloc. I find it hard to
conceive of a situation in this day and age where you *wouldn't* want
both malloc and the caller of malloc to check. I can't imagine what
situation would make such checking an avoidable "nuisance".
Thanks for your input.
P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Dec 31 '06 #9

P: n/a
jacob navia wrote:
>
Rcently I posted code in this group, to help a user
that asked to know how he could find out the size of
a block allocated with malloc.

As always when I post something, the same group
of people started to try to find possible errors,
a harmless passtime they seem to enjoy.

One of their remarks was that I used "int" instead of
"size_t" for the input of my allocator function.
.... snip ...
>
I post this to document why having an "int" as an argument to a
malloc-type function is not such a bad idea.

Your opinion may differ.
It does. Are you or are you not the implementor of lcc-win32? If
so, you can easily limit the range accepted within the malloc code,
without fouling the specifications of the standard. If not you
shouldn't be fooling with routines that are defined in the
standard.

--
Some informative links:
<http://members.fortunecity.com/nnqweb/ (newusers)
<http://www.catb.org/~esr/faqs/smart-questions.html>
<http://www.caliburn.nl/topposting.html>
<http://www.netmeister.org/news/learn2quote.html>
<http://cfaj.freeshell.org/google/ (taming google)
Dec 31 '06 #10

P: n/a
jacob navia said:
Richard Heathfield a écrit :
>jacob navia said:

<snip>

>>>As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.


Why would you need a small negative number as an argument to malloc? Are
you trying to allocate a negative amount of memory?

Can't you read?
I can read just fine. Why would you need a small negative number as an
argument to malloc?
This thread is not for you
This is Usenet. If you want a private discussion, use email.
I said in my original message:

"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"
On the contrary, using an unsigned type as malloc's argument *eliminates*
the possibility of requesting a negative size.

<nonsense snipped>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Dec 31 '06 #11

P: n/a
"jacob navia" <ja***@jacob.remcomp.frwrote in message
news:45***********************@news.orange.fr...
One of their remarks was that I used "int" instead of
"size_t" for the input of my allocator function.
As long as your allocator isn't named malloc(), calloc(), or realloc(),
that's up to you.

Of course, one must wonder why you'd ever want to allow folks to request
negative amounts of memory and exactly what it means if they do. Making
the argument unsigned (whether size_t or something else) makes it much
more obvious what you intended the proper use to be, and it doubles the
number of legitimate argument values.
As I explained, I prefer a signed type to the
unsigned size_t because small negative number will be
confused with huge integers when interpreted as unsigned.
....
This concern with the usage of an unsigned type that can be
easily lead to errors (of course only for people that do
make errors like me...)
The typical C programmer answer to this is "don't do that". C's
philosophy, at its core, is to give programmers the tools to shoot
themselves in the foot if they so desire. If you frequently shoot
yourself in the foot, then consider using another language, like BASIC,
that doesn't give you that option, or spend more time learning how to
code defensively or how to use your debugger.
is also expressed in the document ISO/IEC JTC1 SC22 WG14 N1135 :
"Specification for Safer, More Secure C Library Functions"
where they propose:

Extremely large object sizes are frequently a sign that an object’s
size
was calculated incorrectly. For example, negative numbers appear as
very
large positive numbers when converted to an unsigned type like size_t.

Also, some implementations do not support objects as large as the
maximum value that can be represented by type size_t.

For those reasons, it is sometimes beneficial to restrict the range of
object sizes to detect programming errors.

They propose having an unsigned rsize_t, but a macro RSIZE_MAX that
would limit the range of the object size.
There is nothing preventing the implementor from returning NULL if the
request to malloc() et al appears to be erroneous, such as being "a
small negative number" converted to unsigned. We do not need a change
to the standard for this, since the standard already allows the
implementation to return NULL for any reason it wishes -- just like we
don't need a change to the standard to add bounds-checking pointers.
Implementors are free to do all sorts of extra work behind the scenes to
try to prevent problems, if they wish.

Most implementors, however, take the position that it's more important
to give people the freedom to do unexpected things than to treat them
like idiots who need adult supervision. Insulting your customers is not
a sustainable business practice.

S

--
Stephen Sprunk "God does not play dice." --Albert Einstein
CCIE #3723 "God is an inveterate gambler, and He throws the
K5SSS dice at every possible opportunity." --Stephen Hawking
--
Posted via a free Usenet account from http://www.teranews.com

Dec 31 '06 #12

P: n/a
In article <o_******************************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"
>On the contrary, using an unsigned type as malloc's argument *eliminates*
the possibility of requesting a negative size.
You seem to be deliberately misunderstanding - surely reading the rest
of the thread makes it clear. The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative, and if the argument to malloc() was signed, it
could notice this error, rather than treating it as a very large
positive value.

On most current general-purpose computers, such a large positive value
will fail anyway, so it wouldn't be very helpful on those systems.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Dec 31 '06 #13

P: n/a
jacob navia wrote:
Richard Heathfield a écrit :
.... snip ...
>>
Why would you need a small negative number as an argument to
malloc? Are you trying to allocate a negative amount of memory?

Can't you read?

This thread is not for you
This is a *public* newsgroup. If you don't want comments on your
posts, don't post.

--
Merry Christmas, Happy Hanukah, Happy New Year
Joyeux Noel, Bonne Annee.
Chuck F (cbfalconer at maineline dot net)
<http://cbfalconer.home.att.net>
Dec 31 '06 #14

P: n/a
In article <45***************@yahoo.com>,
CBFalconer <cb********@maineline.netwrote:
>jacob navia wrote:
>Richard Heathfield a écrit :
... snip ...
>>>
Why would you need a small negative number as an argument to
malloc? Are you trying to allocate a negative amount of memory?

Can't you read?

This thread is not for you

This is a *public* newsgroup. If you don't want comments on your
posts, don't post.
Are you really that stupid? Are you really so stupid that you don't
follow what Jacob is really saying when he says "This thread is not for
you"?

You
Macho programmers need not apply.
folks
Macho programmers need not apply.
need
Macho programmers need not apply.
to
Macho programmers need not apply.
learn
Macho programmers need not apply.
to
Macho programmers need not apply.
read
Macho programmers need not apply.
between
Macho programmers need not apply.
the
Macho programmers need not apply.
lines.

Jan 1 '07 #15

P: n/a
In article <45***********************@free.teranews.com>,
Stephen Sprunk <st*****@sprunk.orgwrote:
....
>Most implementors, however, take the position that it's more important
to give people the freedom to do unexpected things than to treat them
like idiots who need adult supervision. Insulting your customers is not
a sustainable business practice.
Seems to work just fine for MS. But then again, they're not "most
implementors", I suppose. They're insignificant.

Jan 1 '07 #16

P: n/a
On Sun, 31 Dec 2006 17:45:42 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>This thread is not for you
I'm sorry, where does it say in the Rules of Usenet that some threads
are forbidden to some posters?

(snip collection of sarcastic and gratuitous insults).
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #17

P: n/a
On 31 Dec 2006 22:25:40 GMT, in comp.lang.c , ri*****@cogsci.ed.ac.uk
(Richard Tobin) wrote:
>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,
Thats impossible, if the argument is unsigned.
>and if the argument to malloc() was signed, it
could notice this error, rather than treating it as a very large
positive value.
Huh? So you sacrifice half the possible address space, to cater for a
stupid programming error. Actually, this sounds about par for the
course, given the recent string thread.
>On most current general-purpose computers, such a large positive value
will fail anyway, so it wouldn't be very helpful on those systems.
It works fine on all my general purpose computers. That is to say, it
fails if the attempt is for too much memory, and it works otherwise.
What else would we reasonably expect it to do?
--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #18

P: n/a
Mark McIntyre a écrit :
On Sun, 31 Dec 2006 17:45:42 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:

>>This thread is not for you


I'm sorry, where does it say in the Rules of Usenet that some threads
are forbidden to some posters?
That was of course just an advise.

I said in my original post

As always when I post something, the same group
of people started to try to find possible errors,
a harmless passtime they seem to enjoy.

You belong to that group.
Jan 1 '07 #19

P: n/a
P.J. Plauger a écrit :
"jacob navia" <ja***@jacob.remcomp.frwrote in message
news:45***********************@news.orange.fr...

>>P.J. Plauger a écrit :
>>>The problem with int is that it throws away half the address space.
This is a *big* issue with 16-bit address spaces, but of course
such machines are largely relegated to embedded systems, and small
ones at that.

Yes. I see this too as a problem, but then, in such small
systems, the amount of ram tends to be very small too, and
the situation remains the same.

In a DSP I used last year the total amount of RAM was
4K, so a sizeof(int) 16 bits I had plenty of space
anyway :-)


That may be your experience, but mine has been that 16-bit systems
often have >32KB of memory. Anything that interferes with handling
all of memory in one go is sure to cause trouble, sooner or later.
Yes. You are right in this point. For 16 bit systems the
lost of 32K of addressing space is quite a hit. Specially
if you do have the full 64K.

jacob
Jan 1 '07 #20

P: n/a
In article <aa********************************@4ax.com>,
Mark McIntyre <ma**********@spamcop.netwrote:
>On 31 Dec 2006 22:25:40 GMT, in comp.lang.c , ri*****@cogsci.ed.ac.uk
(Richard Tobin) wrote:
>>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,

Thats impossible, if the argument is unsigned.
Incorrect. In the C language, if you pass a signed integer (for
example, the number -4) to a function where the formal parameter of that
function is declared unsigned (for example, malloc()), the "default
arithmetic conversions" (something you should read up on, by the way),
will convert that signed number to an unsigned, in order to be
compatible with the formal function declaration. On many systems,
numbers like -4 (negative numbers with small absolute values) will be
converted to very large unsigned numbers.

That's what we are talking about here. Do try to keep up.
>>and if the argument to malloc() was signed, it
could notice this error, rather than treating it as a very large
positive value.

Huh? So you sacrifice half the possible address space, to cater for a
stupid programming error. Actually, this sounds about par for the
course, given the recent string thread.
>>On most current general-purpose computers, such a large positive value
will fail anyway, so it wouldn't be very helpful on those systems.

It works fine on all my general purpose computers. That is to say, it
fails if the attempt is for too much memory, and it works otherwise.
What else would we reasonably expect it to do?
Google for "malloc overcommit Linux OOM" and get back to us, OK?

Jan 1 '07 #21

P: n/a
In article <aa********************************@4ax.com>,
Mark McIntyre <ma**********@spamcop.netwrote:
>>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,
>Thats impossible, if the argument is unsigned.
Why don't you take a leaf out of P J Plauger's book and address the
real question, instead of being a tosser and pretending not to
understand?

The value the user supplies is negative. It's converted to a positive
value as part of the function calling process.
>>and if the argument to malloc() was signed, it
could notice this error, rather than treating it as a very large
positive value.
>Huh? So you sacrifice half the possible address space, to cater for a
stupid programming error. Actually, this sounds about par for the
course, given the recent string thread.
Most current operating systems on general-purpose computers do not
allow the user to use the full theoretical address space. It's
common for 32-bit systems to only allow a single process to address
2^31 bytes.
>>On most current general-purpose computers, such a large positive
value will fail anyway, so it wouldn't be very helpful on those
systems.
>It works fine on all my general purpose computers. That is
to say, it fails if the attempt is for too much memory, and it works
otherwise.
And the result of converting, say, -1 to size_t is typically "too much
memory". So malloc(-1) will fail.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Jan 1 '07 #22

P: n/a
In article <en***********@pc-news.cogsci.ed.ac.uk>,
Richard Tobin <ri*****@cogsci.ed.ac.ukwrote:
>In article <aa********************************@4ax.com>,
Mark McIntyre <ma**********@spamcop.netwrote:
>>>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,
>>Thats impossible, if the argument is unsigned.

Why don't you take a leaf out of P J Plauger's book and address the
real question, instead of being a tosser and pretending not to
understand?
Because this is clc and that's what they (McIntyre and Heathfield, among
others) do. Get with the program!
>The value the user supplies is negative. It's converted to a positive
value as part of the function calling process.
Obviously. But where's the fun in that?

Jan 1 '07 #23

P: n/a

"jacob navia" <ja***@jacob.remcomp.frwrote in message
news:45***********************@news.orange.fr...
Mark McIntyre a écrit :
>On Sun, 31 Dec 2006 17:45:42 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:

>>>This thread is not for you


I'm sorry, where does it say in the Rules of Usenet that some threads
are forbidden to some posters?
That was of course just an advise.

I said in my original post

As always when I post something, the same group
of people started to try to find possible errors,
When I post something here, I sincerely hope that
others will attempt to find any errors it might
contain. Because if they do, and point them out,
it's to my (and probably others') benefit.
a harmless passtime they seem to enjoy.
Not only harmless, but beneficial.
You belong to that group.
The more members the better.

-Mike
Jan 1 '07 #24

P: n/a
Richard Tobin said:
In article <o_******************************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>>"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"
>>On the contrary, using an unsigned type as malloc's argument *eliminates*
the possibility of requesting a negative size.

You seem to be deliberately misunderstanding - surely reading the rest
of the thread makes it clear.
I'm failing to understand how such a mistake is considered so likely and so
undetectable that we suddenly have to change everybody's standard library.
The mistake is that you inadvertently
pass an incorrect value to malloc().

Sometimes such incorrect values will be negative,
Um, *what*?

p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this group.
It is a well-known, popular idiom.

n is an object count, so it makes sense for it to be a size_t.
sizeof *p is an object size, and is a size_t.

So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?

<snip>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #25

P: n/a
Richard Heathfield a écrit :
Richard Tobin said:

>>In article <o_******************************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:

>>>>"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"
>>>On the contrary, using an unsigned type as malloc's argument *eliminates*
the possibility of requesting a negative size.

You seem to be deliberately misunderstanding - surely reading the rest
of the thread makes it clear.


I'm failing to understand how such a mistake is considered so likely and so
undetectable that we suddenly have to change everybody's standard library.

>>The mistake is that you inadvertently
pass an incorrect value to malloc().

Sometimes such incorrect values will be negative,


Um, *what*?

p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this group.
It is a well-known, popular idiom.

n is an object count, so it makes sense for it to be a size_t.
sizeof *p is an object size, and is a size_t.

So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?

<snip>
How to ignore errors. An example of bad programming practices
-------------------------------------------------------------

Mr heathfield says that:
p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this
group.
It is a well-known, popular idiom.
Yes, but it is quite dangerous.

Suppose:
struct S {
unsigned n;
double d;
double data[8192];
};

I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?
i=65520, i*sizeof(*p)=4,294,967,040 as signed number = -256

WE OBTAIN A NEGATIVE NUMBER.

Even WORST.

What happens if you want to allocate just ONE object more?
i=65521, i*sizeof(*p)=65,296 as signed number = 65,296

YOU HAVE AN OVERFLOW and you get a POSITIVE BUT WRONG number!!!

You end allocating space for ONE object and not for
65521!!!!!!

And there is NO WAY a malloc will tell you about any errors
since the request is perfectly normal.

I am aware of this bug because we HAVE DISCUSSED this here and
I realized that the calloc implementation of lcc-win32 furnished
by the windows system had also this BUG. I immediately rewrote
the calloc function that SHOULD ALWAYS TEST FOR OVERFLOW.

What is MACHO programming?
--------------------------

It is an attitude of wrong security and lack of critical distance
to oneself. This attitude is specially pervasive in bright and
experienced programmers. You get into the frame of mind:

"I know what I am doing, I do not need barriers or security
considerations".

This is similar to:

"I am driving since 15 years now, never had an accident.
Why should I use the seat belts???"
Jan 1 '07 #26

P: n/a
jacob navia said:

<snip>
How to ignore errors. An example of bad programming practices
-------------------------------------------------------------

Mr heathfield says that:
p = malloc(n * sizeof *p);
>
is a very common idiom and about the most-typed code fragment in this
group.
It is a well-known, popular idiom.

Yes, but it is quite dangerous.

Suppose:
struct S {
unsigned n;
double d;
double data[8192];
};

I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?
If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?
i=65520, i*sizeof(*p)=4,294,967,040 as signed number = -256

WE OBTAIN A NEGATIVE NUMBER.
No, you don't. size_t is an unsigned type.
Even WORST.

What happens if you want to allocate just ONE object more?
i=65521, i*sizeof(*p)=65,296 as signed number = 65,296

YOU HAVE AN OVERFLOW and you get a POSITIVE BUT WRONG number!!!
No, you don't get overflow with unsigned types.

<snip>
I realized that the calloc implementation of lcc-win32 furnished
by the windows system had also this BUG.
It doesn't surprise me that you found a bug in lcc-win32. That is presumably
your job. But I am surprised that you found *this* bug in lcc-win32,
because it's so easy to get this right. If you have a quantity that cannot
possibly be negative (a count, a size, whatever), use an unsigned type.
I immediately rewrote the calloc function that SHOULD ALWAYS TEST FOR
OVERFLOW.
Unsigned types don't overflow.

<nonsense snipped>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #27

P: n/a
Kenny McCormack escreveu:
In article <aa********************************@4ax.com>,
Mark McIntyre <ma**********@spamcop.netwrote:
>On 31 Dec 2006 22:25:40 GMT, in comp.lang.c , ri*****@cogsci.ed.ac.uk
(Richard Tobin) wrote:
>>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,
Thats impossible, if the argument is unsigned.

Incorrect. In the C language, if you pass a signed integer (for
example, the number -4) to a function where the formal parameter of that
function is declared unsigned (for example, malloc()), the "default
arithmetic conversions" (something you should read up on, by the way),
will convert that signed number to an unsigned, in order to be
compatible with the formal function declaration. On many systems,
numbers like -4 (negative numbers with small absolute values) will be
converted to very large unsigned numbers.

That's what we are talking about here. Do try to keep up.
>>and if the argument to malloc() was signed, it
could notice this error, rather than treating it as a very large
positive value.
Huh? So you sacrifice half the possible address space, to cater for a
stupid programming error. Actually, this sounds about par for the
course, given the recent string thread.
>>On most current general-purpose computers, such a large positive value
will fail anyway, so it wouldn't be very helpful on those systems.
It works fine on all my general purpose computers. That is to say, it
fails if the attempt is for too much memory, and it works otherwise.
What else would we reasonably expect it to do?

Google for "malloc overcommit Linux OOM" and get back to us, OK?
Man, if you have a comprehensive thread on this here in c.l.c I would
like to find it, because I spend a lot of time explaining this to
newcomers in my work...
Jan 1 '07 #28

P: n/a
In article <3Z*********************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>The mistake is that you inadvertently
pass an incorrect value to malloc().
>Sometimes such incorrect values will be negative,
>Um, *what*?

p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this group.
It is a well-known, popular idiom.

n is an object count, so it makes sense for it to be a size_t.
sizeof *p is an object size, and is a size_t.

So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?
Well obviously it won't. But the idea was to protect against
programmers who make mistakes, and as we all know not all programmers
use that idiom.

As I said, I don't think the proposal would do much good, but surely
you can see what the idea was?

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Jan 1 '07 #29

P: n/a
Richard Tobin said:
In article <3Z*********************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
<snip>
>>So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?

Well obviously it won't.
Quite so.
But the idea was to protect against
programmers who make mistakes, and as we all know not all programmers
use that idiom.
The fix, then, is obvious.
>
As I said, I don't think the proposal would do much good, but surely
you can see what the idea was?
It appeared to be an attempt to introduce the additional risk of overflow to
the existing risk of specifying an allocation amount other than the amount
actually required. No, I don't see why this would be of benefit.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #30

P: n/a
Richard Heathfield wrote:
>
jacob navia said:
I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?
Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.

--
Clark S. Cox III
cl*******@gmail.com
Jan 1 '07 #31

P: n/a
Clark S. Cox III a écrit :
Richard Heathfield wrote:
>>jacob navia said:

>>>I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?


Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.
Yes, but that is only logic.

This doesn't count as argument as it seems.

heathfield will answer that unsigned ints
wrap around as specified in the standard, so
that is not an overflow (or a similar nonsense.)
Jan 1 '07 #32

P: n/a
jacob navia wrote:
Clark S. Cox III a écrit :
>Richard Heathfield wrote:
>>jacob navia said:
I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?


Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.

Yes, but that is only logic.

This doesn't count as argument as it seems.

heathfield will answer that unsigned ints
wrap around as specified in the standard, so
that is not an overflow (or a similar nonsense.)

Oh, don't take my post the wrong way; just because I corrected a single
factual error in his post, I still agree with him; and disagree with you.
There is no way to obtain a negative size_t.
Unsigned types don't overflow.
A signed argument to malloc makes absolutely no sense.
--
Clark S. Cox III
cl*******@gmail.com
Jan 1 '07 #33

P: n/a
Clark S. Cox III said:
Richard Heathfield wrote:
>>
jacob navia said:
I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?

Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.
Oh, so it can, provided you use those silly little American billions. :-)

In which case, what's the big deal? 65520 * 65552 is 4294967040 which is a
little smaller than 4294967295. Probably the allocation will fail (because
it's just so colossal) and NULL will be returned, but if the RAM is there,
it may even succeed. I don't see a problem here.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #34

P: n/a
jacob navia said:
Clark S. Cox III a écrit :
>Richard Heathfield wrote:
>>>jacob navia said:
I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?


Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.

Yes, but that is only logic.
Well, I wouldn't have called it that. I'd have called it a mistake on my
part. They happen.
This doesn't count as argument as it seems.
<shrugWhat's to argue? On the matter of 32-bit unsigned integer types, I
made a simple mistake in fact, but the principle remains sound.
heathfield will answer that unsigned ints
wrap around as specified in the standard, so
that is not an overflow
Arithmetic on unsigned integer types is reduced modulo 2^(MAX+1) where MAX
is the maximum value that can be stored in an object of that type.
Therefore, overflow doesn't happen.
(or a similar nonsense.)
If you want to think of the truth as being nonsense, that's up to you, but
it doesn't stop it from being the truth.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #35

P: n/a
Clark S. Cox III a écrit :
jacob navia wrote:
>>Clark S. Cox III a écrit :
>>>Richard Heathfield wrote:
jacob navia said:

>I want to allocate 65520 objects of size 65 552 bytes each.
>
>If you do that in a 32 bit system what you obtain?

If by "32 bit system" you mean that size_t is a 32-bit type, then its
maximum value is 65535. If you don't mean that, what do you mean?
Umm, a 32-bit size_t (with no padding bits, etc.) can hold up to about
4-billion.

Yes, but that is only logic.

This doesn't count as argument as it seems.

heathfield will answer that unsigned ints
wrap around as specified in the standard, so
that is not an overflow (or a similar nonsense.)

Oh, don't take my post the wrong way; just because I corrected a single
factual error in his post, I still agree with him; and disagree with you.
His majesty is always right, no matter how much nonsense
he says.
There is no way to obtain a negative size_t.
Of course not. It is an unsigned number. The whole point is that
when you have

void fn(unsigned arg);

and you write:

fn(-3);

an implicit cast from signed to unsigned is done,
what in all implementations I know leads to no
machine code, but just a change in the way the bits
of the argument are interpreted.

Obviously this is a simplification of a real situation
when the values are not explicitely gibve like in the
example above.

Unsigned types don't overflow.
This is nonsense. Why I obtain

65521 * 65552 --65296 ????

You (and heathfield) are just playing with words. That
overflow is defined for unsigned numbers within C doesn't
mean that the result is mathematically VALID, or that is
the expected result.

The whole point of my argumentation is that the "idiom"

result = malloc(n * sizeof *p);

is a dangerous construct. Use

result = calloc(n, sizeof(*p))

and ensure your implementation of calloc doesn't have the bug!

A signed argument to malloc makes absolutely no sense.
It would catch the overflow in some cases above, as I explained in
my post.

You ropinion may be different, but it would be helpful if you
tried to advance an argument, just saying
"makes no sense"

makes no sense to anyone but you.
Jan 1 '07 #36

P: n/a
jacob navia said:
Clark S. Cox III a écrit :
<snip>
>There is no way to obtain a negative size_t.

Of course not. It is an unsigned number. The whole point is that
when you have

void fn(unsigned arg);

and you write:

fn(-3);

an implicit cast from signed to unsigned is done,
There is no such thing as an implicit cast. Casts are explicit conversions.

<snip>
>Unsigned types don't overflow.

This is nonsense.
No, it isn't.
Why I obtain

65521 * 65552 --65296 ????
Unsigned integer arithmetic is done by reducing the unsigned number to the
range 0 to MAX, where MAX is the maximum value for the type.
You (and heathfield) are just playing with words. That
overflow is defined for unsigned numbers within C doesn't
mean that the result is mathematically VALID, or that is
the expected result.
Overflow is not defined for unsigned numbers within C, and that's because
overflow is not *possible* for unsigned numbers within C.

The Standard makes this very clear: "A computation involving unsigned
operands can never overflow, because a result that cannot be represented by
the resulting unsigned integer type is reduced modulo the number that is
one greater than the largest value that can be represented by the resulting
unsigned integer type."

And the result is indeed mathematically valid, since unsigned integer types
with N value bits represent a ring with 2^N elements.

The whole point of my argumentation is that the "idiom"

result = malloc(n * sizeof *p);

is a dangerous construct.
You have not demonstrated this to be the case.
Use

result = calloc(n, sizeof(*p))

and ensure your implementation of calloc doesn't have the bug!
Better still, use malloc. If your implementation is buggy, get it fixed or
get it changed.
>A signed argument to malloc makes absolutely no sense.

It would catch the overflow in some cases above, as I explained in
my post.
You can't overflow an unsigned type, as has been explained ad nauseam.
You ropinion may be different, but it would be helpful if you
tried to advance an argument, just saying
"makes no sense" makes no sense to anyone but you.
This isn't a matter of opinion. See ISO/IEC 9899.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #37

P: n/a
"Richard Heathfield" <rj*@see.sig.invalidwrote in message
news:3Z*********************@bt.com...
Richard Tobin said:
>In article <o_******************************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>>>"... the usage of an unsigned type that can
easily lead to errors (of course only for people that do
make errors like me...)"
>>>On the contrary, using an unsigned type as malloc's argument *eliminates*
the possibility of requesting a negative size.

You seem to be deliberately misunderstanding - surely reading the rest
of the thread makes it clear.

I'm failing to understand how such a mistake is considered so likely and
so
undetectable that we suddenly have to change everybody's standard library.
>The mistake is that you inadvertently
pass an incorrect value to malloc().

Sometimes such incorrect values will be negative,

Um, *what*?

p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this
group.
It is a well-known, popular idiom.

n is an object count, so it makes sense for it to be a size_t.
sizeof *p is an object size, and is a size_t.

So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?
It won't, of course, but it can still be erroneous if the arithmetic
wraps around. This is because malloc is using an unsigned type to
pass a *non-negative* argument value. Wraparound may be valid for
the host type but not for the intented purpose of the conveyed
argument value. An error is an error, even if the compiled code
isn't obliged to catch it.

A robust program would have code something like:

if ((size_t)(-1) / sizeof (*p) < n)
<non-negative overflow will occur>

but it's rare to see such code in real life. Navia is correct
that calloc(n, sizeof *p) robustly passes the problem off to
calloc, which may itself be robust enough to know nonsense
when it sees it. Or not. I've seen C libraries go both ways.

Note that replacing size_t with its equivalent signed type offers
little protection for oversize allocations:

-- A valid allocation of over half of full memory yields a false
positive, since the signed version of the byte count is negative.

-- An invalid allocation of more than full memory has a 50/50
chance of yielding a negative value, or a bogus positive value.

The best of all worlds is probably a calloc that checks as it
should for wraparound, and further checks a non-wrapped byte
count against RSIZE_MAX, a la TR 24731. And this doesn't really
require any change to existing calloc calls -- just better
runtime checking.

But none of this blather about the virtues of signed arithmetic,
or the imperviousness to overflow of unsigned arithmetic,
addresses the true problem of allocating storage sanely and
reporting insane requests properly.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
Jan 1 '07 #38

P: n/a
Richard Heathfield a écrit :
>
>>Why I obtain

65521 * 65552 --65296 ????


Unsigned integer arithmetic is done by reducing the unsigned number to the
range 0 to MAX, where MAX is the maximum value for the type.
This "arithmetic" has nothing to do with arithmetic
and overflow is just declared normal, leading
to unexpected results.

But it is useless to discuss with you

HINT:

I did not answer to you but to somebody else

Overflow doesn't exist?

65521 *65552 --65296 ???

OK.

Then if I want to allocate 65521 objects of
65552 bytes each I obtain a block 65296 bytes long

WONDERFUL!

Then, I can write more than 4GB into 65296 bytes

You should work for RAM producers heathfield.
The would be very inetersted in your
method for writing 4GB into 65296 bytes!!!

:-)
>
>>The whole point of my argumentation is that the "idiom"

result = malloc(n * sizeof *p);

is a dangerous construct.


You have not demonstrated this to be the case.
I have demonstrated that the multiplication
65521 * 65552 gives 65296, what is clearly not
enough space to store 65521 objects of size 65552
each. You are free to call that "multiplication that
doesn't overflow".

You can babble as much as you like but that is a fact.
Jan 1 '07 #39

P: n/a
jacob navia <ja***@jacob.remcomp.frwrites:
[...]
Can't you read?

This thread is not for you
[...]
You never do any errors heathfield since you are a "competent
C programmer". Please go away. This thread is about errors
and their prevention. You do not need it.
Gosh, I didn't know one person could ban someone like that.

Let me try it. navia, this newsgroup is not for you. Please go away.

--
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.
Jan 1 '07 #40

P: n/a
P.J. Plauger a écrit :
The best of all worlds is probably a calloc that checks as it
should for wraparound, and further checks a non-wrapped byte
count against RSIZE_MAX, a la TR 24731. And this doesn't really
require any change to existing calloc calls -- just better
runtime checking.
I discovered this bug precisely in the windows CRTDLL.DLL
C runtime library provided by the system. The calloc in
there will NOT check if the multiplication overflows.

I replaced it with:

void *calloc(size_t n,size_t s)
{
long long siz = (long long)n * (long long)s;
void *result;
if (siz>>32)
return 0;
result = malloc((unsigned)siz);
if (result)
memset(result,0,(unsigned)siz);
return result;
}

In an implementation with 32 bit unsigned ints (size_t)
and 64 bit long long the multiplication can never
overflow. I just test if the upper 32 bits are different than
zero, what catches all errors of this type.

At least in my opinion. Maybe there is a bug above.
But none of this blather about the virtues of signed arithmetic,
or the imperviousness to overflow of unsigned arithmetic,
addresses the true problem of allocating storage sanely and
reporting insane requests properly.
True.
Jan 1 '07 #41

P: n/a
On Mon, 01 Jan 2007 01:33:55 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>As always when I post something, the same group
of people started to try to find possible errors,
a harmless passtime they seem to enjoy.
Don't go giving yourself airs, laddy.

/Anyone/ posting to this group finds their posts scanned for errors.
It'd be pretty poor if mistakes didn't get noticed don't you think.
>You belong to that group.
Glad to hear it.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #42

P: n/a
On 1 Jan 2007 02:05:06 GMT, in comp.lang.c , ri*****@cogsci.ed.ac.uk
(Richard Tobin) wrote:
>In article <aa********************************@4ax.com>,
Mark McIntyre <ma**********@spamcop.netwrote:
>>>The mistake is that you inadvertently
pass an incorrect value to malloc(). Sometimes such incorrect values
will be negative,
>>Thats impossible, if the argument is unsigned.

Why don't you take a leaf out of P J Plauger's book and address the
real question,
Which is? If the argument is unsigned, you can't pass a -ve value to
it. If you're using an unsigned type throughout you can't even
generate a negative value. Sure, you could somehow pass a huge
positive value to malloc. Where's the problem?
>instead of being a tosser and pretending not to
understand?
And why don't you swivel on it, since we're being polite?
best regards

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #43

P: n/a
On Mon, 01 Jan 2007 20:01:54 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>Clark S. Cox III a écrit :
>>
Oh, don't take my post the wrong way; just because I corrected a single
factual error in his post, I still agree with him; and disagree with you.

His majesty is always right, no matter how much nonsense
he says.
No, truth is always right, no matter how much nonsense people try to
conceal it behind.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #44

P: n/a
On Mon, 01 Jan 2007 12:14:39 +0100, in comp.lang.c , jacob navia
<ja***@jacob.remcomp.frwrote:
>
I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?
i=65520, i*sizeof(*p)=4,294,967,040
>as signed number = -256
So what?
>WE OBTAIN A NEGATIVE NUMBER.
Only if you are stupid enough to copy it into a signed type. Clearly,
since you can't allocate negative memory, that is dopey. Use an
unsigned type, and everything is peachy.
>YOU HAVE AN OVERFLOW
You can't overflow unsigned types.
>and you get a POSITIVE BUT WRONG number!!!

You end allocating space for ONE object and not for
65521!!!!!!

And there is NO WAY a malloc will tell you about any errors
since the request is perfectly normal.
Capsitis. any day now, you'll ANNOUNCE that you are a CHAIR.

--
Mark McIntyre

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are,
by definition, not smart enough to debug it."
--Brian Kernighan
Jan 1 '07 #45

P: n/a
jacob navia said:
Richard Heathfield a écrit :
>>
>>>Why I obtain

65521 * 65552 --65296 ????


Unsigned integer arithmetic is done by reducing the unsigned number to
the range 0 to MAX, where MAX is the maximum value for the type.

This "arithmetic" has nothing to do with arithmetic
and overflow is just declared normal, leading
to unexpected results.
The results are not unexpected to those who know how unsigned integer
arithmetic works. It's not unreasonable to expect people to know a thing or
two about the language before they start using it for stuff like allocating
memory dynamically. Unsigned integer arithmetic is dealt with on page 36 of
K&R, whereas malloc isn't mentioned until page 143. Unsigned integer
arithmetic is primitive, obvious stuff. To call its results "unexpected" is
to betray one's ignorance of the language.
But it is useless to discuss with you
Yes, and you know why? Because you never *listen*, that's why. That, You
seem to take almost every disagreement as a personal attack.
HINT:

I did not answer to you but to somebody else
If you want your answer to be read only by a particular individual, use
email. If you publish an article on Usenet, you should be prepared for it
to be read, and replied to, by anybody at all.
Overflow doesn't exist?
Right.
65521 *65552 --65296 ???
Before you can know the answer to that question, you need to define your
universe of discourse. In N, the answer is 4295032592. In the ring of
integers modulo 2^b, the answer is 4295032592 modulo 2^b.
OK.

Then if I want to allocate 65521 objects of
65552 bytes each I obtain a block 65296 bytes long
On any given implementation, either size_t is big enough to store 65521 *
65552 or it isn't. If it is, there is no issue. And if it is not, your
request is meaningless, since you're asking for an object bigger than the
system can provide.

<snip>
>>
>>>The whole point of my argumentation is that the "idiom"

result = malloc(n * sizeof *p);

is a dangerous construct.


You have not demonstrated this to be the case.

I have demonstrated that the multiplication
65521 * 65552 gives 65296,
No, assuming you are using unsigned arithmetic it gives 4295032592 modulo
2^b where b is the number of bits in the unsigned integer type you are
using. If b is 33 or more, the answer is 4295032592, not 65296. The width
of size_t is implementation-defined.
what is clearly not
enough space to store 65521 objects of size 65552
each. You are free to call that "multiplication that
doesn't overflow".
The Standard says it doesn't overflow, and therefore it doesn't overflow
(unless the Standard is wrong, which is something you can take up with ISO
if you like, but I don't rate your chances).
You can babble as much as you like but that is a fact.
Well, it's a highly selective fact which chooses to ignore all sorts of
other rather important facts, such as what the Standard says, how wide a
size_t is allowed to be, and so on.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Jan 1 '07 #46

P: n/a
On Mon, 1 Jan 2007 08:04:15 -0600, Richard Tobin wrote
(in article <en***********@pc-news.cogsci.ed.ac.uk>):
In article <3Z*********************@bt.com>,
Richard Heathfield <rj*@see.sig.invalidwrote:
>>The mistake is that you inadvertently
pass an incorrect value to malloc().
>>Sometimes such incorrect values will be negative,
>Um, *what*?

p = malloc(n * sizeof *p);

is a very common idiom and about the most-typed code fragment in this
group.
It is a well-known, popular idiom.

n is an object count, so it makes sense for it to be a size_t.
sizeof *p is an object size, and is a size_t.

So we have size_t * size_t - how, precisely, will that produce a negative
number when passed to a function taking size_t as an argument?

Well obviously it won't. But the idea was to protect against
programmers who make mistakes, and as we all know not all programmers
use that idiom.

As I said, I don't think the proposal would do much good, but surely
you can see what the idea was?
I'll take a stab it. The proposal is to arbitrarily chop the available
address in space, for those rare cases in which someone wishes to
malloc an amount of memory /larger/ than the available address space on
the processor. I.e., they want a boatload of RAM, so restrict them to
less than half of that they need to make things "safer". That has BS
written all over it, imo.

If the programmer knows how to ask for that much memory, but can't
figure out how to make sure he doesn't ask for more than will fit in
size_t, he needs to be writing DOS .bat files instead, where he can do
less damage. Or maybe he should just go off and write his own pseudo-C
compiler instead.

--
Randy Howard (2reply remove FOOBAR)
"The power of accurate observation is called cynicism by those
who have not got it." - George Bernard Shaw

Jan 2 '07 #47

P: n/a
Randy Howard a écrit :
I'll take a stab it. The proposal is to arbitrarily chop the available
address in space, for those rare cases in which someone wishes to
malloc an amount of memory /larger/ than the available address space on
the processor. I.e., they want a boatload of RAM, so restrict them to
less than half of that they need to make things "safer". That has BS
written all over it, imo.
Not at all. Please just see what the proposal really was
before going to answer to phantasy proposals.

The proposal was discussing the idea of using a signed
type to avoid problems with small negative numbers
that get translated into huge unsigned ones.

THAT was the reason.

After this discussion, and after the remarks of Mr Plauger
I am not so sure that that proposal was actually a very good
idea.

The problem is in this discussions, that everybody is trying to
discuss in such an emotional way, that acknowledging
something in your "adversary" argumentation is seen as
an equivalent of "surrender"...

:-)

Look at you, deforming the proposal in such a way that
it is completely NUTS. Of course THEN it is easy to
say:

IT IS NUTS!!!

Obvious Mr Howard. But if you care to follow a bit the
discussion that wasn't proposed at all.

The argument of Mr Plauger that convinces me is that anyway
a multiplication error like the one I signaled to heathfield
will ANYWAY cause havoc even if we put the signed type in
the argument to malloc, so it is actually not a good idea at all.
If the programmer knows how to ask for that much memory, but can't
figure out how to make sure he doesn't ask for more than will fit in
size_t, he needs to be writing DOS .bat files instead, where he can do
less damage. Or maybe he should just go off and write his own pseudo-C
compiler instead.
A programmer is a human, and human make errors. This discussion
is not designed for people that do not make errors. It is for
people that want to discuss how can we build safety into software
in such a waythat the consequences of errors are limited, for instance
a malloc that diagnoses a bogus argument returns NULL instead of
crashing the software.
Jan 2 '07 #48

P: n/a
Richard Heathfield <rj*@see.sig.invalidwrites:
jacob navia said:
[...]
>what is clearly not
enough space to store 65521 objects of size 65552
each. You are free to call that "multiplication that
doesn't overflow".

The Standard says it doesn't overflow, and therefore it doesn't overflow
(unless the Standard is wrong, which is something you can take up with ISO
if you like, but I don't rate your chances).
[...]

You're both arguing about the meaning of the word "overflow", which is
IMHO less important than the actual behavior of integer types.

Multiplication of two values of type size_t (or of any unsigned
integer type) can yield a mathematical result that cannot be
represented as a value of type size_t. The standard does not call
this "overflow", but in my opinion "overflow" *would* be a valid term
for it.

The point is this: If a result of an unsigned multiplication cannot be
represented, the result is reduced modulo 2**N (where the maximum
value of the type is 2**N-1 -- "**" denotes exponentiation). If the
result of a signed multiplication cannot be represented, the behavior
is undefined.

Using an unsigned type as the parameter of malloc() means that a
larger range of arguments can be used than if it took the
corresponding signed type. This can be significant for systems with a
16-bit size_t that can allocate more than 32767 bytes, or for systems
with a 32-bit size-t that can allocate more than 2147483647 bytes.

jacob's argument is that using a signed type for the parameter of a
malloc-like function is beneficial, supposedly because if a user
incorrectly passes a very large value as the argument, it is likely to
wrap around to a negative value, which can be detected as an error.

In fact, the standard does not guarantee any such thing. Signed
overflow for an arithmetic operation invokes undefined behavior.
Overflow on conversion to a signed type yields an
implementation-defined result (or, in C99, raises an
implementation-defined signal).

Wraparound to a possibly negative value is not uncommon. However, the
result is just as likely to be positive (and still incorrect). Using
a signed type might catch *some* errors, but in my opinion it's not a
good solution. Unsigned types are tricky; that can't be changed
without changing the language. The only real solution is for the
*programmer* to avoid overflow in the first place, and choosing any
particular type as the parameter to a malloc-like function can't help
much with that. You might as well use size_t for consistency with the
standard library.

At times, it would be very nice to be able to define some different
behavior for unsigned "overflow" (i.e., for operations that yield a
mathematical value outside the range of the type). If I multiply two
unsigned values and get an out-of-range result, the result reduced
modulo 2**N *might* be what I want, but more often it's an error that
I'd like to know about. Ditto for signed and floating-point. But C
doesn't let us do that, at least not portably.

--
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.
Jan 2 '07 #49

P: n/a
jacob navia <ja***@jacob.remcomp.frwrites:
[...]
Suppose:
struct S {
unsigned n;
double d;
double data[8192];
};

I want to allocate 65520 objects of size 65 552 bytes each.

If you do that in a 32 bit system what you obtain?
i=65520, i*sizeof(*p)=4,294,967,040 as signed number = -256

WE OBTAIN A NEGATIVE NUMBER.
[...]

We obtain undefined behavior.

--
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.
Jan 2 '07 #50

318 Replies

This discussion thread is closed

Replies have been disabled for this discussion.