Page 2 of 2
Re: How do you handle your Errors?
Posted: Sun Jan 12, 2014 9:33 pm
by brunexgeek
I return a negative error code or zero on success. I try to be consistent with return values in my API's, thus almost all functions returns an error code (sometimes I use positive values to return sizes like in C standard library). But I have some exceptions, like functions returning a pointer instead (NULL if some error occurred).
JamesM wrote:... I have a function "set_errno()" which sets a thread-local variable ...
I don't use this technique in my kernel/OS (yet?), but I did in many other developments. I think it's a good solution too and allow you to provide some extra useful information, like a specific error message, line number and filename. Someone can say I can simply put this in a log file, but sometimes I don't want to log every "instance" of an error (I can decide if I will log it in another function).
Re: How do you handle your Errors?
Posted: Mon Jan 13, 2014 10:28 am
by rdos
IMO, returning negative error codes is the worse of all solutions. Then you can no longer test return values from procedures as if they are boolean, and you need different code to check for pointers (0 = not ok) and for error returns (0 = ok). It also creates horrible code like if (!someproc()) success, which is highly error-prone and non-intuitive.
The idea to use C++ exception handling has merits, but it doesn't work between separately compiled drivers, and between kernel and user-space, which limits it's utility.
Re: How do you handle your Errors?
Posted: Mon Jan 13, 2014 12:12 pm
by brunexgeek
rdos wrote:IMO, returning negative error codes is the worse of all solutions. Then you can no longer test return values from procedures as if they are boolean, and you need different code to check for pointers (0 = not ok) and for error returns (0 = ok). It also creates horrible code like if (!someproc()) success, which is highly error-prone and non-intuitive....
Edit: I think logical tests with this kind of return (using zero for success and non-zero for failure) is not correct. Logical tests should be used with..."logical" return values (zero means failure and non-zero success). Maybe with pointers in which NULL means failure.
I agree with you about the problem with different codes for check pointers and errors, but IMO that's not too bad as you said.
BTW I don't use something like "if (!someproc())". I prefer more explicit error checking like:
Code: Select all
void *ptr;
int result;
...
if (ptr == NULL) ...
if (result < 0) ...
Re: How do you handle your Errors?
Posted: Mon Jan 13, 2014 3:26 pm
by b.zaar
brunexgeek wrote:
Code: Select all
void *ptr;
int result;
...
if (ptr == NULL) ...
if (result < 0) ...
I prefer this way. It's fast and simple and when reading the code you understand the flow easily. If an error occurs then you can do a more detailed examination of the errno in whatever format that it may be stored. Usually a return value will either be a positive or a pointer so this works for the majority of functions.
In assembly I miss the old JC on error from a interrupt. I don't set carry in my asm functions as C can't check it quickly like a negative return value.
Re: How do you handle your Errors?
Posted: Tue Jan 14, 2014 1:31 am
by VolTeK
--
Re: How do you handle your Errors?
Posted: Tue Jan 14, 2014 2:28 am
by Combuster
My system calls should return success status in CF. But instead of that, 90% of them actually panic for now to force me to fix the calling code.
The remainder of the system and driver interface (which is both the largest part and fully IPC-based) passes tuples with information that end up in callback functions, and you won't find any C-style return value in that part system. Instead there will be one of two separate functions called as an result: one for the success case, and one for the error case. This also means you can never forget an error.
Re: How do you handle your Errors?
Posted: Tue Jan 14, 2014 4:49 am
by rdos
b.zaar wrote:
In assembly I miss the old JC on error from a interrupt. I don't set carry in my asm functions as C can't check it quickly like a negative return value.
If you have a decent C compiler, it's not hard to decode CF from syscalls. I still use the CF for success / failure. I even support non-implemented functions by having a default-stub that just returns with CF set. It works because all syscalls must pass parameters in registers, and all syscalls use CF for success / failure.
The problematic issue typically is to set CF to the correct value from a C handler procedure. I think that it works easiest to simply define the entry-points for all syscalls in assembly, and then let them call C code to handle complex things. Otherwise the code gets really strange and hard to understand.
It would be far better if the C compiler instead could define a "success" variable (preferently of boolean type), which is implemented with CF on x86. That shouldn't be that hard to do, and it would create more readable code. After all, it only takes one instruction to test CF, while it takes two to check a register for being 0.
Re: How do you handle your Errors?
Posted: Tue Jan 14, 2014 5:09 am
by nerdguy
I should be ashamed of this, but even for handling errors I have method called trial-and-error.
That works pretty nice even in real life, but is not always dependable
Nah, usually I first look at the region where the fault is suspected to reside, next I randomly
insert some string print code like : 'Stage 1 Complete', next I again see where it stops,
doing this a few times gets me the code that has a fault, next I hear Bochs shouting, usually on this stage
I know what the problem is, I RTFM for a while and that tells me where I am going wrong.
Re: How do you handle your Errors?
Posted: Tue Jan 14, 2014 7:00 am
by iansjack
I'm afraid you seem to have misunderstood the topic being discussed.
Re: How do you handle your Errors?
Posted: Sun May 11, 2014 4:08 am
by elderK
I'm rich in the ways that I can handle errors as my kernel is implemented in Scheme. I can "return" multiple values or throw around exceptions.
Generally, I dispatch to different functions depending on the outcome of a call. When a function calls another, it tells the callee who it should call next. "Returning" a value is nothing but an illusion as the functions never return. They simply pass their results to their successors when they invoke them.
This mechanism is called "continuation passing style" and I've found it to be both very useful and very powerful.
In the case mentioned directly above, the callee has only one successor. You can, however, have a function that accepts as many targets as there are error conditions. So, it goes to k1 on success, k2 on read timeout, k3 on allocation failure, etc.
~K
Re: How do you handle your Errors?
Posted: Sun May 11, 2014 6:23 am
by alexfru
The main problem with errors is not detecting and passing them, but figuring out what to do with them, how to recover from them if at all possible. And this gets worse if the information about errors gets lost while being passed between the layers of software. It's also pretty bad if you're using a 3rd party piece of code and you have no idea what errors it can return and what they actually mean.
Say, file writing fails. Why? Did the disk become full? Did you reach a quota? Did the file reach the maximum size allowed by the FS? Did the FS get corrupted? Did the media get corrupted (bad cluster, etc)? Did you lose access rights in the process? Did you lose connection with a remote file server? Did the remote file server misbehave and if it did why did it and what can you do about it? Did you lose access rights to anything between you and the file (all the network stuff)? Did the local and remote times go out of synch and affect network protocol operation? Were there too much activity on the network and/or the server that precluded the write request from being satisfied in a reasonable time period and you got a timeout? There's probably a bunch more cases why things can fail. Now, if you don't get a descriptive enough error code/message or if it doesn't let you differentiate different causes, you don't really know what you can do about the error. Next comes the question about the context. Was it a user file? Can you properly inform the user of the problem and suggest a workaround/fix/etc? Is giving too detailed error information a good thing from security standpoint, and if it is not, how do you choose between usability and security? Was it a system file? If it was, is it some critical file that you absolutely must have r/w access to? If you must, you must stop and shut down the OS, but can you still store the error in the log or not (ditto for crash dumps)? If it's not something that critical, what happens if you log the error and continue? Are there any security implications of ignoring the error? What are they? What can you do about them?