From: Terje Mathisen "terje.mathisen at on
MitchAlsup wrote:
> On Jun 25, 12:52 am, Terje Mathisen<"terje.mathisen at tmsw.no">
> wrote:
>> MitchAlsup wrote:
>>> But back on topic: Can anyone show me a piece of code that depends on
>>> integer overflow to create a buffer overrun? (Note: not integer
>>> underflow)
>>
>> That seems almost trivial:
>>
>> An integer overflow turns a too-large positive result into a negative
>> value instead, right?
>>
>> In that case buffer[a+b] turns out to really address buffer[-8] which is
>> where the virtual method pointer (or some other interesting data item)
>> happens to be located...
>
> But why is this an integer overflow and not an integer underflow?
>
> That is:: most arrays are from 0:max-1 or 1:max.
> The most common form of buffer overrun is buffer[max+small_int]
> The second most common form is buffer[-small_int]
> Both of these are detected by bounds checking
> Neighter of these is detected by integer(32-bit) overflow or
> underflow.

OK, I see what you mean. It is only when using (for some strange reason)
embedded 8 or 16-bit counters/offsets into power of two array sizes that
it becomes relevant.

> Nor is the second form detected by unsigned underflow {where
> small_positive becomes small_negative}
> Additionally, bounds checking is one of those algorithms that one can
> teach the optimizer of a compiler to recognize and minimize the
> overhead possible down into the noise floor without loosing any safety/
> robustness.
>
> Which leads me to a vastly better question:
>
> Why do application programmers use int (integers) to index arrays?
> Should not these actually be unsigned int? It seems to me that one
> should have to justify using a signed value by the necessity of
> needing negative value at some time durring its computation.

Thanks!

This is one of my pet peeves! As I've mentioned previously in this
thread I try to use unsigned wherever I can. It is only when indexing
from n-1 down to 0 that it sometimes makes sense to use ints to detect
the point when you go below zero.

In real life (i.e. asm :-) ) I would have used the carry flag instead,
but in C the alternative is to change the loop from a for () to a top
test (if needed, often it isn't) and a do while().

if ((unsigned i = n) != 0) {
do {
i--;
do_something(i);
} while (i);
}

Terje
--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"
From: Jean-Marc Bourguet on
Andy 'Krazy' Glew <ag-news(a)patten-glew.net> writes:

> I posited earlier that appropriate casting to unsigned and back again might
> make some such operations standards compliant.
[...]
> There's lots of mixing of (signed) integer and logical. Is that also
> undefined.

IIRC,

- converting a signed to unsigned is defined do the right thing
(i.e. repeated addition/substraction of U_MAX+1 to get the value into the
unsigned range, so it will not change the bit pattern for 2's complement
machines)

- the converting an unsigned to signed is implementation defined. I
(perhaps na�vely?) expect the implementation to do the reverse of the
above implementation (at least when the types are the same size),
especially on 2's complement machines where that would mean don't change
the bit pattern (which would be another possible behavior for the other
machines)

- logical operations on signed is also implementation defined. Again for
2's complement machine I'd expect the bit patterns to be feeded as it to
the logical unit.

None or these is undefined, the optimisers can't assume they will not
happen.

Yours,

--
Jean-Marc
From: Andy 'Krazy' Glew on
On 6/27/2010 9:51 AM, Robert Myers wrote:
> Terje Mathisen wrote:
>> Anton Ertl wrote:
>
>>
>>> But of course, all of this is outside the standardized subset of C.
>>
>> In my not so humble opinion, this is simply broken.
>>
>
> What this thread has demonstrated to me, yet again, is what a fatally
> flawed enterprise c is, and yet, I know that, without c or something
> like it, we would never have anything like Linux.

I think that C was less flawed before the standardization process got a hold of it. In this aspect, at least.
From: MitchAlsup on
On Jun 26, 9:07 pm, Andy 'Krazy' Glew <ag-n...(a)patten-glew.net> wrote:
>       int
>       read(int d, char *buf, int nbytes)
> DESCRIPTION
>
> Read() attempts to read nbytes of data from the object referenced by the file descriptor d into the buffer pointed to by
> buf.
>
> RETURN VALUES
>
> If successful, the number of bytes actually read is returned. Upon reading end-of-file, zero is returned. Otherwise, a
> -1 is returned and the global variable errno is set to indicate the error..- Hide quoted text -

Clearly this is a case where an int is required by the library
definition and similar definitions hold for argc,...
My argument is not directed towards these, but after the code checks
for error conditions (negative values), many times you will be better
off assigning the now known to be positive value to an unsigned for
future use.
So the use code might look something like:

{ signed long int readc;
unsigned long int index;
readc = read(infile, inbuf, InBufMAX);
if( readc >=0 )
{
for( index=0; index < readc; index++)
// readc is known to be non-negative
....inbuf[index]....
}
}

Mitch
From: Terje Mathisen "terje.mathisen at on
MitchAlsup wrote:
> On Jun 26, 3:46 pm, Andy 'Krazy' Glew<ag-n...(a)patten-glew.net> wrote:
>> I.e. you cannot simply say
>>
>> unsigned response_count;
>> response_count++;
>> assert( response_count> 0 );
>>
>> since C defines wraparound arithmetic for unsigneds, and does not do overflow. (Again, I may be misreading, I don't
>> have my copy of the C standard (where'd I put it?), and I am sure that i will be told.)
>>
>> you must do assert(response_count< some_max_count)
>> and assume that underlow wraps to a large number.
>
> No assumption is needed on 1s-complement or 2s-complement machines.

Isn't it even stronger? I.e. C guarantees that unsigned math is modulo
math, even if the modulus can vary between machines.

This means that any unsigned variable which decrement from zero must end
up with the largest possible positive value instead of -1.

> {Does anyone know of a machine using integer signed-magnitude that is
> still existing?}
>
> And note:
> assert( uindex< MAX )
> is simpler than the signed equivalent:
> assert( sindex>=0&& sindex< MAX )
> and checks for the same index ranges (in terms of untyped bit
> patterns).

I have been using this for at least 25 years to simplify and speed up my
error handling code.

>
> After the assert fails, one can observe (i.e. print) the index. If it
> is just a little above the MAX then it can be assumed to have overrun
> the buffer, and if it is massively larger than MAX it can be assumed
> to have underrun the buffer.
>
>>> One of the things that using "unsigned" gives you is the ability to tell
>>> the compiler/system that it is an error to try to decrement (or have a
>>> subtract result) below 0. To me, this is equivalent to overflow detection.
>>
>> Agreed. It wouyld be nice to have the system tell you are trying to make an unsigned number negative.
>
> However, there is no hardware that will detect and raise an exception
> on this condition automatically. One has to go and look for the carry
> condition.

Right.

Terje

--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"