Hitokage said:"Function" isn't in hungarian notation!
NLB2 said:comma?
Hitokage said:Ok, here's my serious submission. I fully expect it to be laughably wrong.
The program seems to be a sanity check, making sure that pb isn't larger than its buffer, and neither is pb or pb buffer larger than a predefined limit. However, given that everything checks out, both comparisons return TRUE and thus the function returns TRUE, except... a nonzero return value is an error code... then again, I do remember Windows being bizzare in this respect... so yeah... nevermind.
Lathentar said:Uhh... if pbBuffer is null, pb might be under the buffersize and the function will return true?
aaaaa0 said:The function is trying to verify that pb is pointing to something within pbBuffer, assuming pbBuffer is 32KB in size and is valid.
While passing pbBuffer = NULL into the function is indeed an error (since a pointer with value NULL is always invalid), it is not the bug here.
You can assume the code calling this function will not pass NULL for pbBuffer.
Lathentar said:As a clarification, you're checking to make sure of this:
pbBuffer <= pb < pbBuffer + BUFFER_SIZE
maharg said:Lets say pBuffer is 5 and BUFFER_SIZE is 10.
pb is 6 (thus, this should return true)
pb - pbBuffer = -1
HOWEVER, the result of a pointer subtraction is an unsigned int (size_t actually), and in an unsigned int, -1 underflows to the highest value unsigned int can hold, which is clearly > BUFFER_SIZE.
When two pointers are subtracted, the difference is converted to a signed integral value by dividing the difference by the size of a value of the type that the pointers address.
Fafalada said:I wouldn't necesserily call it a bug, but the second comparison
(pb - pbBuffer < BUFFER_SIZE)
is definately unsafe code.
The substraction result of two pointers will be converted to whatever integral type your specific compiler implementation uses for the purpose - and that type size MAY(depends on the implementation) be smaller then the size of pointers, which in turn will break the code if the two pointers are too far apart.
To be on the safe side, you'd want to write
(pb < pbBuffer + BUFFER_SIZE) which compares the values as two pointers.
If there's other bugs, I can't see them right now :|
maharg said:Just want to note that while I am indeed wrong, that's not the C standard
The C Language Reference describes the C programming language as implemented in Microsoft C. The book's organization is based on the ANSI C standard with additional material on the Microsoft extensions to the ANSI C standard.
maharg said:crap I'm a retard. Most likely it's a signedish thing though.
Hitokage said:BUFFER_SIZE is negative.
BugCatcher said:The function returns TRUE if pb is less than zero, but I don't know the reason for it.
rastex said:then if pb is very large with teh MSB being 1 and pBuffer being much smaller such that the MSB is 0 and the difference has MSB 1 then it'll be a negative and always less than the BUFFER_SIZE.
OS dependent, I would presume.(Now, to be nitpicky, C officially does not define what will happen when two arbitrary pointers are subtracted from each other if they're not from the same allocation block, though most compilers will allow it, so you can argue this whole function was flawed from the very beginning for bonus points.)
Shompola said:you should have used ansi c standard for the pointers and difference between pointers here wich means you should have used stddef.h for these types.
Maybe when I'm awake. :/rastex said:I like these, do another one!!
BugCatcher said:So how do you rewrite the function to perform the same task, but without the bug?
it is undefined behaviour (C99 draft standard) in the event that ptrdiff_t is not large enough to hold it.[#9] When two pointers to elements of the same array object
are subtracted, the result is the difference of the
subscripts of the two array elements. The size of the
result is implementation-defined, and its type (a signed
integer type) is ptrdiff_t defined in the <stddef.h> header.
If the result is not representable in an object of that
type, the behavior is undefined. In other words, if the
expressions P and Q point to, respectively, the i-th and j-
th elements of an array object, the expression (P)-(Q) has
the value i-j provided the value fits in an object of type
ptrdiff_t. Moreover, if the expression P points either to
an element of an array object or one past the last element
of an array object, and the expression Q points to the last
element of the same array object, the expression ((Q)+1)-(P)
has the same value as ((Q)-(P))+1 and as -((P)-((Q)+1)), and
has the value zero if the expression P points one past the
last element of the array object, even though the expression
(Q)+1 does not point to an element of the array object.
Unless both pointers point to elements of the same array
object, or one past the last element of the array object,
the behavior is undefined.76
maharg said:At any rate, the real fix for this bug is to never use pointers in such a way that you're left guessing on matters like this. If you're left guessing on where a pointer goes, you're doing something wrong as far as I'm concerned. (certain exceptions apply: asserts, gaurding against stack overflows (but there are often better ways) -- especially in a context where privilege escalation is possible).
And yeah, the rather obscure ways signed and unsigned interact in C/C++ are one of the worst things about them as languages. Even the best programmers make mistakes like this quite easily.
// read the header of the file
ReadHeader( &pHeader );
// verify buffer is no bigger than we are expecting
if( pHeader->cElements * sizeof( AN_ELEMENT ) > MAX_BUFFER )
{
// OH NOS SOMEONE CORRUPTED OUR FILE!
return WHOAH_HEADER_IS_CORRUPT;
}
Yeah these kind of bugs can be pretty horric, particularly since they don't tend to occur in predictable manner while testing.maharg said:And yeah, the rather obscure ways signed and unsigned interact in C/C++ are one of the worst things about them as languages. Even the best programmers make mistakes like this quite easily.
rastex said:I like these, do another one!!
template<int n>
struct F1
{ enum { a = F1<n-1>::a * n };
};
template<>
struct F1<0>
{ enum { a = 1 };
};
template<int v1, int v2>
class F2
{ enum { a = F1<v2>::a,
b = F1<v1>::a*F1<v2-v1>::a
};
public:
enum { c = a/b };
};
//
//
printf("Result: %d \n",F2<7,12>::c);
maharg said:And of course, the wonder of all this is that it's done statically at compile time without the language having a built-in factorial operator. The joy of templates and quasi-functional programming