|
There is no definitive direction. It should be evaluated as part of the design.
Validation is an issue of documentation and design. Read Bertrand Meyer's "Programming by Contract".
|
|
|
|
|
You could do it the way the MFC libraries are implemented: a debug version where validations (pointer validations, bound checking, etc...) are done with assertions and a release version where the assertions are removed. This way you benefit from both design-time error checking and run-time performance.
Henry P.
http://www.allersoft.com
|
|
|
|
|
Hi there!
Since a mutex is a semaphore with only one resource, my frist idea was to use it, but it seems that or the mutex is not well implemented or i am using it in a bad manner...
For instance, if i use the following code:
<br />
CSemaphore s1(1,1,"S1")<br />
if (s1.Lock(500))<br />
{<br />
CSemaphore s2(1,1,"S1");<br />
if (s2.Lock(500))<br />
{<br />
TRACE("\n Semaphore failed!");<br />
}<br />
<br />
s1.Unlock(1);<br />
}<br />
... i never get to see the trace message in the display! But, if use:
<br />
CMutex m1(TRUE,"M1")<br />
if (m1.Lock(500))<br />
{<br />
CMutex m2(TRUE,"M1");<br />
if (m2.Lock(500))<br />
{<br />
TRACE("\n Mutex failed!");<br />
}<br />
<br />
m1.Unlock(1);<br />
}<br />
I Always see the trace message... even if i change the initial ownership of the mutex.
Can anyone, please, show me the right way to do it with mutexes?
Thanx for your time!
|
|
|
|
|
Windows API doesn't verify the parameters (ok, if you use the checked build it does, but... ). I'm using a lib from a big financial company that verifies the function parameters, but if you give it a bad config file, it crashes. Sucks!
Rodrigo Strauss
|
|
|
|
|
Well, I personally try to mimic the Win32 conventions for parameter validation in my own libraries. The Win32 API (as opposite to CRT and STL) does a simple parameter verification that suits for most cases: For example you can pass NULL or INVALID_HANDLE_VALUE for HANDLES, 0-pointers and so on without getting undefiend behavior. The result is a nice error code returned in GetLastError() like ERROR_INVALID_HANDLE or ERROIR_INVALID_PARAMETER, but your app does not crash.
This simple kind of parameter checking makes using these libraries a lot easier without resulting in a huge runtime overhead. And it spares you from a lot of if-statements that increase complexity of the code.
--
Daniel Lohmann
http://www.losoft.de
(Hey, this page is worth looking! You can find some free and handy NT tools there )
|
|
|
|
|
Do you think these results would be different for libraries that are only used internally (maybe just for your own use), compared to libraries that you'd give to 3rd party developers? Do we aim to make things bullet(fool)-proof when we know someone other than ourselves is using it?
=)
|
|
|
|
|
The level of the library should determine who is doing most of the validation. If I am using a low level C library functions like memcpy then all validation is on my head. But if I am using a high level library I expect it to do some, not all, of the validation. After all I bought the library so I could develop a reliable program in the leased amount of time.
FYI: I have a tendency to over validate, since program crashes, etc.. are against my religion.
John R. Shaw
"Trust in the code luke." "Ya right."
|
|
|
|
|
John R. Shaw wrote:
The level of the library should determine who is doing most of the validation
Exactly!
cheers,
Chris Maunder
|
|
|
|
|
I found the results of this poll rather puzzling.
I voted for the first option; the person who uses the library should use it correctly.
It seems like a very odd thing to do to do the error checking in two places, which is what a whole lot of you guys voted for. Why would you waste time, implementation (your own time! You should be at the beach) and CPU-time, doing the same thing twice? Especially when you know that if it's done "right", it simply executes the exact same code twice.
I could understand the argument that "it's better to be safe than sorry", but this sounds kludgy; programming by approximation ("oh, so that's where it crashes. I guess _I_ should have taken extra precautions, even though I'm used to the library catching these things for me.")
There are a number of reasons why I'd rather have the user of the library make sure he feeds correct data than having the library check it every time:
- Efficiency. If the input value needs to be between 0 and 255, the library could check it, but if the user wants to iterate from 0 to 255, that's 256 if-tests out the window CPU-wise, but more importantly:
- Allocation of responsibility. A good coder should know his libraries well enough to know what their valid input parameters are. A good library should make clear for which input values it's supposed to work.
It's important that you, the library user, knows where the check is being done, and I for one, would be much more comfortable checking my own input than having that being left to the library writer. Not that I don't necessarily trust him/them... But why should I? The excuse "I picked a bad library, so it isn't really my fault" might fly with your geekiest of friends, but the boss needs a working product.
It's been pointed out that some things are downright infeasible for the library writer to check himself, especially if it's a library for å low-level language like C or C++; how do you determine if a handle is valid? For scripting languages like PHP, I like to make a level of indirection from the handle to the user, and make sure the "Resource ID" is valid. Why? Because you can't trust a PHP-programmer to do what he should, and he'll take down the webserver given the chance. Doing this with a C/C++-library (and you could, of course), you'd be walking around in quicksand.
Obviously, C and C++ themselves advocates correct usage of libraries. You should not free a pointer not returned by malloc. You should not delete [] something not returned by new []. The STL expects you to make sure you're iterating from .begin() to .end() on the same container. Or else... all hell breaks loose.
To sum up my point of view:
- Consider your users' needs.
- For a low-level library, it's more important that the correct usage of a library is documented than enforced by code. That way, everybody knows who's to blame when things go wrong.
--
O< O- O< *quack* O- O< O- O< O- O< *kvekk* O-
Lars Thomas Denstad <larsde@redloop.com>
http://www.redloop.com/larsde/
O< *pip* *pip* *pip* O- O< O- O< O- O< *quack* O- O< O-
|
|
|
|
|
Why perform error checking in both places?
In my opinion, these days, when processors are very fast, we don't (usually) have to be as concerned with extracting the last little bit of performance from our apps.
Put it another way. Customers who use our products pay for both efficiency and robustness. Clearly, very sluggish or memory-piggish apps won't be appreciated, but neither would very fast apps which crash a lot.
Again, because processors are (usually) very fast these days, we can afford to spend some performance in assuring robustness. Just my opinion.
|
|
|
|
|
Poor data scrubbing in a library is an open invitation for security holes. If there is a flaw in a library that can be exploited, someone will find it and try to exploit it. Telling hackers and crackers to stop abusing it because they should be using it correctly poorly written library is not going to work.
I voted for number two. The responsibility for the integrity of a library rests solely upon the writer of the library.
|
|
|
|
|
Bingo! If you publish a library (esp. one without source code), you need to make darn sure it doesn't open a security hole. The evil s'kid'diots are fed more clever code every day. If your library is the hole they use to get into MY system, you'll get some hate mail.
|
|
|
|
|
Ok, now imagine a Win32 API without thorough error checking, because, as you say, the application should not pass invalid data.
You passed a wrong ACL and your data was corrupted? Well, take care next time.
You passed a wrong pointer and the OS blue screened? Take care next time.
I think you would pretty soon rethink your theory
powerful binary resource reuse - another word for "no sources, you are stuck with a pain-in-the-a## COM component"
|
|
|
|
|
Also look on the "reusability" side,
The reason the application is calling functions in a library is to reuse code, (whether it's about oop or structered programming, doesn't matter) so why should you do the same checks again and again when you can have it in one simple and safer place get checked, namely in the function.
Another argument would be that the function itself is responsible for doing actions with the input data, so it should know more about the nature of the data and thus can be more accurate in restricting the data, hence it performs the operation.
Surprising results imho as well, option number two should get more votes.
|
|
|
|
|
I think each error has a 'locus' determined by the knowledge required to detect and/or remediate the error.
A library should expect to be used as a black box, and therefore should at least validate the assumptions it makes about its arguments. What's important is that the knowledge required to validate the library arguments lies within the library itself. Requiring the caller to validate arguments disperses that knowledge to multiple locations, increasing the probability that the error detection will not be consistent.
The caller does have a role to play in validation, however. It has knowledge of the context in which the library is being used. It is the caller's responsibility to validate its use of the library against that context. In this case, the library doesn't have any way of knowing the application's context, and therefore can't validate against it.
How the library or the caller handles a detected error is immaterial; it can assert , throw an exception, return an error code, or halt the program. Any of these responses is valid, depending upon the situation (and personal taste).
Software Zen: delete this;
|
|
|
|
|
When it comes to security related functions, both parties should IMO verify data. At the very least, the library should.
But for applications which are unrelated to security, I like to use the programming by contract paradigm. It basically means that if the caller ensures that the input is valid according to the functions contract, then the function will deliver according to the contract. everything else is undefined (in debug builds that usually means ASSERT() ). Bugs are found in no time.
I put the error checks in the I/O-layer. Check the text boxes, check the file data, check the whatever-input, and issue errors as soon as possible instead of doing it 10 function calls down into the library.
Basically, this method puts more effort into checking data in one layer. Beyond that layer, everything is considered ok. It has worked for me so far.
But then again, methodologies are like religions. Pick your own path and see where it leads you.
--
Chatai. Yana ra Yakana ro futisha ta?
|
|
|
|
|
Jörgen Sigvardsson wrote:
But for applications which are unrelated to security, I like to use the programming by contract paradigm. It basically means that if the caller ensures that the input is valid according to the functions contract, then the function will deliver according to the contract. everything else is undefined (in debug builds that usually means ASSERT()). Bugs are found in no time.
Unfortunately its exactly this behaviour which causes security holes. The leaky functions are not any security related ones, because they are cleverly designed. No, its the innocent looking things like strcpy which causes troubles.
Jörgen Sigvardsson wrote:
But then again, methodologies are like religions. Pick your own path and see where it leads you.
Nope, ask someone who may know better which path is usable and improve it. Never believe that you are clever enough to invent something better than anyone else. Always get some more pairs or eyes and some other brains thinking on it.
powerful binary resource reuse - another word for "no sources, you are stuck with a pain-in-the-a## COM component"
|
|
|
|
|
I know of one major phone PBX that will crash if you send a bad connection string via its OAI stream interface.
I have one rule, I don't care what the routine does with the garbage I pass in as long as it doesn't crash.
Michael
Wonder Woman, Wonder Woman.
All the world's waiting for you,
and the power you possess.
In your satin tights,
Fighting for your rights
And the old Red, White and Blue.
|
|
|
|
|
Michael P Butler wrote:
I know of one major phone PBX that will crash if you send a bad connection string via its OAI stream interface.
Oooh, bad! On the other hand, one wouldn't have to talk to people the rest of that day.
I don't know if the vaugeness of the poll was intentional, but what you have displayed isn't what I'd call a "library" call. The (very serious) error here is that a function that should expect any input (both since it's a vital system and should reasonably have to assume bad input, and there is no way in h*ll they could reasonably assume only valid and predictable input from something as inherently unsafe as a communications port) isn't verified, and more importantly it's not handled in a reasonable manner.
I'd say it all boils down to the readers definition of "library" and what the documentation of the library states.
If library is the C lib, I would expect e.g. memcpy(0, 4711, 42); to crash.
If the library is e.g. user32.dll, I would NOT expect it to crash from bad parameters to e.g. CreateWindow (probably mostly since it's documented to return error-values, and that it has to verify parameters since it's a kernel-call).
If library is a C library documenting "If parameters are in error, we will return error code" I wouldn't expect it to crash. If it's not documented, or documented to only accept legal pointers, I'd expect it to crash given illegal input.
If it was see-hash I wouldn't expect it to even start...
|
|
|
|
|
I would have to choose the caller, because the caller can always verify the data according to the documentation, even if the library checks the data as well.
However, if the responsibility is put on the library, it is possible that the library does not take any responsibility for data and does not verify it. In this case since the caller depended on the library, and the library did not verify, then no one has checked and a problem can occur.
With that being said, I still think it depends and this design issue should be determined up front before coding or the choice of library is made .
Build a man a fire, and he will be warm for a day Light a man on fire, and he will be warm for the rest of his life!
|
|
|
|
|
c'mon, no option for "Dump core and let the user figure it out"? W0t!?!
shog
nine
Ever since i heard the voice
i thought i had no choice...
|
|
|
|
|
Eh, C++ isn't any better. (Actually worse). There we either just display a message box say "Program hosed, exiting" or we try to repair ourselves and half the time leave the program in a trashed state. I have had programs that would display an exception message box in their OnPaint. Every time you tried to exit the program, you would get another exception.
Tim Smith
I'm going to patent thought. I have yet to see any prior art.
|
|
|
|
|
:: Jeremy waves his hands franticly. :: Here, here, over here!
Jeremy Falcon
Imputek
|
|
|
|
|
Sometimes I write libraries, and sometimes I use other libraries. So, we have two scenarios:
1) When I use other libraries, I want them to be "lean", and I'll take care about error-checking. STL is a great example of this.
2) When I write a library that others will use, I'll do all error checking (unless the requirements say otherwise), so that whoever uses the library cannot blame me for their incompetence.
|
|
|
|
|
I remember barely a few years ago hearing from C++ devs who prided themselves on writing lean and mean apps that did as little error and bounds checking as was necessary. Not to say that it wasn't done: rather, that it was done before a function call and then once the data verified the function would be called. The thought that the function they were calling would do further checking was considered by some to be not just a waste of cycles but also something only of value to lame programmers who still slept with their teddy bears used night-lights.
It's interesting to see a shift in focus from performance based programming to secure and robust based programming.
cheers,
Chris Maunder
|
|
|
|
|