size_t or int for malloc-type functions?

A

av

for example:

size_t overflow(size_t x, size_t y) {
size_t xmax, ymax, szmax = -1;

if (xmax && ymax) {
xmax = szmax / ymax; ymax = szmax / xmax;
if ((x > xmax) || (y > ymax) return 0;
return x * y;
}
return 0;
}

assuming 0 is a suitable result for an overflow.

if i want to rappresent 31 bits and not 32bits
so i have a 31 bit unsigned type

and i use the last bit of size_t (0x80000000) for rappresent overflow
assuming size_t==unsigned int and sizeof(unsigned)==32
and having an x86 cpu >= 386

/* it could do 31 bits size_t multiplication */
asm{
multix:
push edx
mov eax, [esp+ 8]
test dword[esp+12], 0x80000000
jnz .1
test eax, 0x80000000
jnz .1
xor edx, edx
mul dword[esp+12]
cmp edx, 0
je .f
..1:
mov eax, 0x80000000
..f:
pop edx
ret 8
}

unsigned _stdcall multix(unsigned a, unsigned b);
size_t multiplication(size_t x, size_t y) {return multix(x, y);}

for see if the result is not right here
if(result & 0x80000000) error;
the same for +-/ for not right results
(i.e the results that use the modulo fact)
at the end if there is some error
in some place in the calculus =>
if(result & 0x80000000) error;

possibly the above it can do for 32 bits but i have add some memory
space to size_t
 
A

av

for example:

size_t overflow(size_t x, size_t y) {
size_t xmax, ymax, szmax = -1;

if (xmax && ymax) {
xmax = szmax / ymax; ymax = szmax / xmax;
if ((x > xmax) || (y > ymax) return 0;
return x * y;
}
return 0;
}

assuming 0 is a suitable result for an overflow.

if i want to rappresent 31 bits and not 32bits
so i have a 31 bit unsigned type

and i use the last bit of size_t (0x80000000) for rappresent overflow
assuming size_t==unsigned int and sizeof(unsigned)==32
and having an x86 cpu >= 386

/* it could do 31 bits size_t multiplication */
asm{
multix:
push edx
mov eax, [esp+ 8]
test dword[esp+12], 0x80000000
jnz .1
test eax, 0x80000000
jnz .1
xor edx, edx
mul dword[esp+12]
cmp edx, 0
je .f
.1:
mov eax, 0x80000000
.f:
pop edx
ret 8
}

*better* "size_t" is 32 bits i use
for an unsigned rappresentation unsigned 2^32-1
and the value -1==0xFFFFFFFF for error
(pseudo size_t on x86 cpu>=386)

/* it could do size_t multiplication
for numbers [0..2^32-2]
*/
asm{
multix:
push edx
mov eax, [esp+ 8]
cmp [esp+12], -1
je .1
cmp eax, -1
je .f
xor edx, edx
mul dword[esp+12]
cmp edx, 0
je .f
..1:
mov eax, -1
..f:
pop edx
ret 8
}

asm{
addsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
add eax, [esp+8]
jnc .f
..1:
mov eax, -1
..f:
pop edx
ret 8
}

asm{
subsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
sub eax, [esp+8]
j>= .f
..1:
mov eax, -1
..f:
pop edx
ret 8
}

unsigned _stdcall multix(unsigned a, unsigned b);
size_t multiplication(size_t x, size_t y) {return multix(x, y);}

unsigned _stdcall addsize(unsigned a, unsigned b);
size_t addx(size_t x, size_t y) {return addsize(x, y);}

unsigned _stdcall subsize(unsigned a, unsigned b);
size_t subx(size_t x, size_t y) {return subsize(x, y);}

etc

who is the troll?
 
A

av

*better* "size_t" is 32 bits i use
for an unsigned rappresentation unsigned 2^32-1
and the value -1==0xFFFFFFFF for error
(pseudo size_t on x86 cpu>=386)

/* it could do size_t multiplication
for numbers [0..2^32-2]
*/
asm{
multix:
push edx
mov eax, [esp+ 8]
cmp [esp+12], -1
je .1
cmp eax, -1
je .f
xor edx, edx
mul dword[esp+12]
cmp edx, 0
je .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

asm{
addsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
add eax, [esp+8]
jnc .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

asm{
subsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
sub eax, [esp+8]
j>= .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

unsigned _stdcall multix(unsigned a, unsigned b);
size_t operator*(size_t x, size_t y) {return multix(x, y);}
unsigned _stdcall addsize(unsigned a, unsigned b);
size_t operator+(size_t x, size_t y) {return addsize(x, y);}
unsigned _stdcall subsize(unsigned a, unsigned b);
size_t operator-(size_t x, size_t y) {return subsize(x, y);}
etc
size_t result, a, b, c, d, h;
.....
result=a*b+c*d-h;

i forget to say it there is some overflow in some place
if(result==-1) error;

but this change the definiton of size_t.

your dear c standard is wrong in the definition on size_t

is there someone agree with me?
 
R

Richard Heathfield

av said:

your dear c standard is wrong in the definition on size_t

is there someone agree with me?

Unlikely, since you're wrong. The C Standard correctly defines size_t.
 
A

av

*better* "size_t" is 32 bits i use
for an unsigned rappresentation unsigned 2^32-1
and the value -1==0xFFFFFFFF for error
(pseudo size_t on x86 cpu>=386)

/* it could do size_t multiplication
for numbers [0..2^32-2]
*/
asm{
multix:
push edx
mov eax, [esp+ 8]
cmp [esp+12], -1
je .1
cmp eax, -1
je .f
xor edx, edx
mul dword[esp+12]
cmp edx, 0
je .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

asm{
addsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
add eax, [esp+8]
jnc .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

asm{
subsize:
mov eax, [esp+ 4]
cmp [esp+8], -1
je .1
cmp eax, -1
je .f
sub eax, [esp+8]
j>= .f
.1:
mov eax, -1
.f:
pop edx
ret 8
}

unsigned _stdcall multix(unsigned a, unsigned b);
size_t operator*(size_t x, size_t y) {return multix(x, y);}
unsigned _stdcall addsize(unsigned a, unsigned b);
size_t operator+(size_t x, size_t y) {return addsize(x, y);}
unsigned _stdcall subsize(unsigned a, unsigned b);
size_t operator-(size_t x, size_t y) {return subsize(x, y);}
etc
size_t result, a, b, c, d, h;
.....
result=a*b+c*d-h;

i forget to say it there is some overflow in some place
if(result==-1) error;

but this change the definiton of size_t.

your dear c standard is wrong in the definition on size_t

is there someone agree with me?
so where are answers?
do you like doublepost? :)
 
J

jaysome

Ben Pfaff a écrit :

Yes, I know that, and I agree that the semantics of unsigned is
wrap around. What I am saying is that when "the result cannot be
represented" and this wrap around semantics reduces the result,
this reduced result is mathematically WRONG in the sense of the USUAL
multiplication operation.

PHEW!!!!

Specifically when I use the malloc (p * sizeof *p) "idiom"
even if the semantics are well defined this is NOT what I
inteded with that multiplication!!!!

Your problem is that you should neither be using nor advocating the
use of malloc() if "p * sizeof *p" results in a mathematical value
that is greater than (or arguably even light years close to) the
maximum value that can be represented by size_t. Nor should you be
using or advocating the use of malloc() if the size of memory you need
to "allocate" is known at compile-time.

<anecdotal>
In my life, I've seen more misuses of malloc() than I've seen
legitimate uses of malloc(). One of the misuses of malloc() I've seen
goes something like this snippet (I'm not kidding):

char *p;
assert(p = (char*)malloc(sizeof(char)));
*p = 1;
</anecdotal>

Your original example was ostensively contrived, and the astute
observer may ask the question "why not declare the storage as static
and not even use malloc()?"

To which you may have replied something to the tune of: "but I don't
know the size of memory I need to allocate at compile-time".

To which the the astute observer may have replied: "so use malloc(),
and make sure that the size requested is not abnormally unreasonable."

To which you may have replied: "I see."

Or not.

There are a couple of more points to consider juxtaposing against the
arguments you have proffered so far in this thread:

1. "overflow" of a signed value results in undefined behavior.
2. malloc() is not the only function covered by the spirit of your
arguments. You must consider the following functions, inter alia,
also:

void qsort(void*, size_t, size_t, int (*)(const void*, const void*));
void* memchr(const void*, int, size_t);
int memcmp(const void*, const void*, size_t);
void* memcpy(void*, const void*, size_t);
void* memmove(void*, const void*, size_t);
void* memset(void*, int, size_t);
size_t strlen(const char*);
int strncmp(const char*, const char*, size_t);
char* strncpy(char*, const char*, size_t);
size_t fread(void*, size_t, size_t, FILE*);
size_t frite(const void*, size_t, size_t, FILE*);
 
N

Nick Keighley

jacob said:
(e-mail address removed) a écrit :

Who cares about rings?

We are speaking about overflow in a well defined
context. Yes, the C standard defines the behavior
for overflow, and overflow then, it is defined
for unsigned integers. This doesn't mean that it
doesn't happen or that this "ring" stuff is meaningful.

Or are you implying that

65521 x 65552 is 65296 and NOT 4295032592

????

With that 'x' I mean multiplication as is
understood by all people in this planet except
C buffs that know more about C standards than about
software engineering and mathematics???

If I were you I'd get a mathematical education *before* you start
pontificating on the subject. Please google for "mathematics ring".
Mathematics is not limited to the arithmatic you learned at primary
school.

What the standard is doing is merely accepting
overflow after the fact, and "defining" multiplication
by unsigned integers as an operation within a ring of
integers.

This "meaning" to multiplication is maybe OK for justifying
the behavior of C, but it is nothing else than
describing what an overflow DOES in most machines!

The nonsense of heathfield becomes worst given the context where
he is saying that we should go on using this construct:

malloc (n * sizeof *p)

to allocate memory instead of using calloc that should test
for overflow!

The bug I am referring to is when you multiply
65521 * 65552 --> 65 296

Since malloc doesn't see anything wrong it will succeed,
giving you a piece of RAM that it is NOT as long as you
would think it is, but several orders of magnitude SMALLER.

Even when heathfield says a patently insane stuff he is
"the guru" and people here will justify his ramblings.

I am well aware of what the standard says for overflow.
I studied the question when I implemented (as the only C
compiler in existence) an OVERFLOW CHECK feature that
would trap on overflow. And I did it only for signed
integers to remain compatible with the standard.

Nevertheless this behavior of unsigned C arithmetic is
sureley NEVER CORRECT and I have never seen a useful
program that relies on this behavior for something useful.

packet (PDU) numbering in a communication protocol.
unsigned short was 16-bits so it neatly wrapped round when it
got to the end.
 
J

jacob navia

Nick Keighley a écrit :
packet (PDU) numbering in a communication protocol.
unsigned short was 16-bits so it neatly wrapped round when it
got to the end.

in a multiplication operation????
Please clarify this.
 
J

jacob navia

jaysome a écrit :
Your problem is that you should neither be using nor advocating the
use of malloc() if "p * sizeof *p" results in a mathematical value
that is greater than (or arguably even light years close to) the
maximum value that can be represented by size_t.

Exactly. And this is what I am arguing in this thread
since the beginning. We agree then.
> 1. "overflow" of a signed value results in undefined behavior.
No I did not say that. I just said it overflows and the result
is not the result of the multiplication but some other arithmetic
modulo some number.
2. malloc() is not the only function covered by the spirit of your
arguments. You must consider the following functions, inter alia,
also:

Probably. So what?
 
J

jaysome

jaysome a écrit :

Exactly. And this is what I am arguing in this thread
since the beginning. We agree then.

Okay, then, I think we agree.

I was wondering ... do you agree that the following is a C conforming
program, and it enters an "infinite" loop, and it never executes the
return statement, and it sets the variable ii to all values between 0
and UINT_MAX, inclusive?

int main(void)
{
volatile unsigned ii = 0;
for (;;) ii++;
return 0;
}

I was also wondering: do you agree that the following compiler warning
for the above code:

Warning 527: Unreachable code at token 'return'

is acceptable?

Regards
 
A

av

Since it's the defining document, what do you mean by "wrong"
here?

so you too write financials functions using integers in Z/(2^n-1)?
it is not the right mathematical model, i prefer to use Z or R
and find "overflow" if i would do it in a PC

so there is a need o type that finds "overflows"
 
A

av

There are a couple of more points to consider juxtaposing against the
arguments you have proffered so far in this thread:

1. "overflow" of a signed value results in undefined behavior.
2. malloc() is not the only function covered by the spirit of your
arguments. You must consider the following functions, inter alia,
also:

void qsort(void*, size_t, size_t, int (*)(const void*, const void*));
void* memchr(const void*, int, size_t);
int memcmp(const void*, const void*, size_t);
void* memcpy(void*, const void*, size_t);
void* memmove(void*, const void*, size_t);
void* memset(void*, int, size_t);
size_t strlen(const char*);
int strncmp(const char*, const char*, size_t);
char* strncpy(char*, const char*, size_t);
size_t fread(void*, size_t, size_t, FILE*);
size_t frite(const void*, size_t, size_t, FILE*);

3) or in a financial software when happen some like
"On Sun, 24 Dec 2006 02:52:52 GMT, Dik T. Winter wrote:"

|I would do it as:
| long amount = 20000; /* 2 times the amount in cents */
| ...
| for(i = 1; i <= n; i++) {
| amount += amount * 1000_i_per_n / 1000;
| amount += (amount & 1);
| }
| amount /= 2; /* the real amount in cents after the calculations */
|Your formulation is wrong. When the amount is 10769 cents (3-rd
|iteration), the interest calculations give an interest of 269.225 cents,
|that is rounded 269 cents. The next result is 11038 cents. Your formula
|gives 11039.

in the case some
"amount * 1000_i_per_n/1000" "overflow" long signed integer
in the case like above there is no ceck for safe arguments
and i don't know how the writer can calculate them **first**
 
C

Chris Dollin

av said:
so you too write financials functions using integers in Z/(2^n-1)?

/I/ don't write financial functions at all. What's that got to
do with the C Standard's definition of the size_t type? I note
that if one /were/ to do financial calculations, in C, blindly
picking `size_t` as the type to use would be bonkers, and
multiplying one amount-of-money by another amount-of-money
would be even more so.
it is not the right mathematical model, i prefer to use Z or R
and find "overflow" if i would do it in a PC

so there is a need o type that finds "overflows"

It looks like your answer to my question is "The Standard's
definition of size_t is wrong because that type isn't the
one I want." Well, then use a different type. Duh. Take
the necessary precautions. I mean, yes, it would be nice
if C had arbitrarily many useful arithmetic types built-in,
but it doesn't.
 
J

John Bode

I posted something similar to this elsethread, but I think it bears
repeating:

jacob said:
Richard Heathfield a écrit :

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

Mr heathfield says that:


Yes, but it is quite dangerous.

Weakness in one corner case != dangerous.

If you're worried about potential overflow, then do a sanity check on
the request size *before* making the call to malloc():

void *sane_malloc(size_t eltSize, size_t count)
{
size_t maxSize = 0;
void *p = NULL;

maxSize--; // wraps to max size_t value.

if (maxSize / eltSize < count)
{
// request is too large
// indicate error either through errno or other mechanism
}
else
{
p = malloc(count * sizeof *p);
}

return p;
}

....

ptr = sane_malloc(sizeof *ptr, n);

This is infinitely better than relying on undefined behavior (making
the argument to malloc() signed and hoping that signed overflow works
the same everywhere).

[snip remainder]
 
C

CBFalconer

Richard said:
av said:


No, it isn't.

--

+-------------------+ .:\:\:/:/:.
| PLEASE DO NOT F :.:\:\:/:/:.:
| FEED THE TROLLS | :=.' - - '.=:
| | '=(\ 9 9 /)='
| Thank you, | ( (_) )
| Management | /`-vvv-'\
+-------------------+ / \
| | @@@ / /|,,,,,|\ \
| | @@@ /_// /^\ \\_\
@x@@x@ | | |/ WW( ( ) )WW
\||||/ | | \| __\,,\ /,,/__
\||/ | | | jgs (______Y______)
/\/\/\/\/\/\/\/\//\/\\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
==============================================================

fix (vb.): 1. to paper over, obscure, hide from public view; 2.
to work around, in a way that produces unintended consequences
that are worse than the original problem. Usage: "Windows ME
fixes many of the shortcomings of Windows 98 SE". - Hutchinson
 
N

Nelu

CBFalconer said:
Nelu wrote:
.... snip ...

I think that works everywhere. I would rework it slightly to:

void *calloc(size_t n, size_t s) {
void *result;
size_t sz;

result = NULL;
if (SIZE_MAX / n < s) {

It's (SIZE_MAX / n > s), otherwise you allocate more than SIZE_MAX.
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,794
Messages
2,569,641
Members
45,353
Latest member
RogerDoger

Latest Threads

Top