I have been reading the MSDN dev guide to COM. However the code on this page is confusing. Reproducing here:
The following code sample shows the recommended way of handling unknown errors:
HRESULT hr;
hr = xxMethod();
switch (GetScode(hr))
{
case NOERROR:
// Method returned success.
break;
case x1:
// Handle error x1 here.
break;
case x2:
// Handle error x2 here.
break;
case E_UNEXPECTED:
default:
// Handle unexpected errors here.
break;
}
The GetScode function doesn't seem to be defined, nor is NOERROR, and searching MSDN didn't help. A web search indicated that GetScode is a macro that converts HRESULT to SCODE, however those are both 32-bit ints so I'm not sure what it is for.
It was suggested that it is a historical artifact that does nothing on 32-bit systems, but on 16-bit systems it converts hr to a 16-bit int. However, if that is true, then I do not see how E_UNEXPECTED would be matched, since that is 0x8000FFFF. Also, it's unclear whether x1 and x2 are meant to be 0x800..... values, or some sort of truncated version.
Finally, this code treats all-but-one of the success values as errors. Other pages on the same MSDN guide say that SUCCEEDED(hr) or FAILED(hr) should be used to determine between a success or failure.
So, is this code sample really the "recommended way" or is this some sort of documentation blunder?
This is (pretty) old stuff. The winerror.h file in the SDK says this:
////////////////////////////////////
// //
// COM Error Codes //
// //
////////////////////////////////////
//
// The return value of COM functions and methods is an HRESULT.
// This is not a handle to anything, but is merely a 32-bit value
// with several fields encoded in the value. The parts of an
// HRESULT are shown below.
//
// Many of the macros and functions below were orginally defined to
// operate on SCODEs. SCODEs are no longer used. The macros are
// still present for compatibility and easy porting of Win16 code.
// Newly written code should use the HRESULT macros and functions.
//
I think it's pretty clear. I would trust the SDK first, and the doc after that.
We can see SCODE is consistently defined like this in WTypesbase.h (in recent SDKs, in older SDKs, I think it was in another file):
typedef LONG SCODE;
So it's really a 32-bit.
The text is correct; one should be wary of blindly returning failure codes from internal functions, particularly if your code uses a facility code defined elsewhere in the system.
Specifically, at the COM interface function level, you should ensure that the error codes you're returning are meaningful for your interface, and you should remap errors that originate from inside the function to meaningful error codes.
Practically speaking, however, nobody does this, which is why you see bizarre and un-actionable error dialogs like "Unexpected error".
Related
I have an error type that impls the Error trait, and it wraps an underlying error cause, so the source method returns Some(source). I want to know whether the Display impl on my error type should include a description of that source error, or not.
I can see two options:
Yes, include source in Display output, e.g. "Error opening database: No such file"
This makes it easy to print a whole error chain just by formatting with "{}" but impossible to only display the error itself without the underlying chain of source errors. Also it makes the source method a bit pointless and gives client code no choice on how to format separation between each error in the chain. Nevertheless this choice seems common enough in example code I have found.
No, just print the error itself e.g. "Error opening database" and leave it to client code to traverse and display source if it wants to include that in the output.
This gives client code the choice of whether to display just the surface error or the whole chain, and in the latter case how to format separation between each error in the chain. It leaves client code with the burden of iterating through the chain, and I haven't yet fallen upon a canonical utility for conveniently formatting an error chain from errors that each only Display themselves excluding source. (So of course I have my own.)
The snafu crate (which I really like) seems to hint at favoring option 2, in that an error variant with a source field but no display attribute defaults to formatting Display output that does not include source.
Maybe my real question here is: What is the purpose of the source method? Is it to make formatting error chains more flexible? Or should Display really output everything that should be user-visible about an error, and source is just there for developer-visible purposes?
I would love to see some definitive guidance on this, ideally in the documentation of the Error trait.
#[derive(Debug)]
enum DatabaseError {
Opening { source: io::Error },
}
impl Error for DatabaseError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
DataBaseError::Opening { source } => Some(source),
}
}
}
impl fmt::Display for DatabaseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
DatabaseError::Opening { source } => {
// ??? Should we include the source?
write!(f, "Error opening database: {}", source)
// ??? Or should we leave it to the caller to call .source()
// if they want to include that in the error description?
write!(f, "Error opening database")
}
}
}
}
The two options of whether to print the source error on a Display implementation creates two schools of design. This answer will explain the two while objectively stating their key differences and clarifying a few possible misconceptions in the way.
Design 1: Yes, include source on your Display impl
Example with SNAFU:
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not read data set token: {}", source))]
ReadToken {
#[snafu(backtrace)]
source: ReadDataSetError,
},
}
The key advantage, as already mentioned in the question, is that providing the full amount of information is as simple as just printing the error value.
eprintln!("[ERROR] {}", err);
It is simple and easy, requiring no helper functions for reporting the error, albeit with the lack of presentation flexibility. Without string manipulation, a chain of colon-separated errors is what you will always get.
[ERROR] Could not read data set token: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
Design 2: No, leave out source on your Display impl
#[derive(Debug, Snafu)]
enum Error {
#[snafu(display("Could not read data set token"))]
ReadToken {
#[snafu(backtrace)]
source: ReadDataSetError,
},
}
While this will not give you the full information with a single line print like before, you can leave that task to a project-wide error reporter. This also grants the consumer of the API greater flexibility on error presentation.
A simple example follows. Additional logic would be required for presenting the error's backtrace.
fn report<E: 'static>(err: E)
where
E: std::error::Error,
E: Send + Sync,
{
eprintln!("[ERROR] {}", err);
if let Some(cause) = err.source() {
eprintln!();
eprintln!("Caused by:");
for (i, e) in std::iter::successors(Some(cause), |e| e.source()).enumerate() {
eprintln!(" {}: {}", i, e);
}
}
}
Playground
It's also worth considering the interest of integrating with opinionated libraries. That is, certain crates in the ecosystem may have already made an assumption about which option to choose. In anyhow, error reports will already traverse the error's source chain by default. When using anyhow for error reporting, you should not be adding source, otherwise you may come up with an irritating list of repeated messages:
[ERROR] Could not read data set token: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
Caused by:
0: Could not read item value: Undefined value length of element tagged (5533,5533) at position 3548
1: Undefined value length of element tagged (5533,5533) at position 3548
Likewise, the eyre library provides a customizable error reporting abstraction, but existing error reporters in the eyre crate ecosystem also assume that the source is not printed by the error's Display implementation.
So, which one?
Thanks to the efforts of the Error Handling project group, a key guideline regarding the implementation of Display was proposed in early 2021:
An error type with a source error should either return that error via source or include that source's error message in its own Display output, but never both.
That would be the second design: avoid appending the source's error message in your Display implementation. For SNAFU users, this currently means that applications will need to bring in an error reporter until one is made available directly in the snafu crate. As the ecosystem is yet to mature around this guideline, one may still find error utility crates lacking support for error reporting in this manner.
In either case...
This decision only plays a role in error reporting, not in error matching or error handling in some other manner. The existence of the source method establishes a chain-like structure on all error types, which can be exploited in pattern matching and subsequent flow control of the program.
The Error::source method has a purpose in the ecosystem, regardless of how errors are reported.
In addition, it's ultimately up to the developers to choose how to design their errors and respective Display implementations, although once it starts integrating with other components, following the guideline will be the right way towards consistent error reporting.
What about Rust API guidelines?
The Rust API guidelines do not present an opinion about Display in errors, other than C-GOOD-ERR, which only states that the error type's Display message should be "lowercase without trailing punctuation, and typically concise". There is a pending proposal to update this guideline, instructing developers to exclude source in their Display impl. However, the pull request was created before the guideline was proposed, and has not been updated since then (at the time of writing).
See also:
The error handling protect group (GitHub)
Inside Rust Blog post 2021-07-01: What the error handling project group is working towards
We have a plugin system that calls functions in dlls (user-generated plugins) by dlopening/LoadLibrarying the dll/so/dylib and then dlsyming/GetProcAddressing the function, and then storing that result in a function pointer.
Unfortunately, due to some bad example code being copy-pasted, some of these dlls in the wild do not have the correct function signature, and do not contain a return statement.
A dll might contain this:
extern "C" void Foo() { stuffWithNoReturn(); } // copy-paste from bad code
or it might contain this:
extern "C" int Foo() { doStuff(); return 1; } // good code
The application that loads the dll relies on the return value, but there are a nontrivial number of dlls out there that don't have the return statement. I am trying to detect this situation, and warn the user about the problem with his plugin.
This naive code should explain what I'm trying to do:
typedef int (*Foo_f)(void);
Foo_f func = (Foo_f)getFromDll(); // does dlsym or GetProcAddress depending on platform
int canary = 0x42424242;
canary = (*func)();
if (canary == 0x42424242)
printf("You idiot, this is the wrong signature!!!\n");
else
real_return_value = canary;
This unfortunately does not work, canary contains a random value after calling a dll that has the known defect. I naively assumed calling a function with no return statement would leave the canary intact, but it doesn't.
My next idea was to write a little bit of inline assembler to call the function, and check the eax register upon return, but Visual Studio 2015 doesn't allow __asm() in x64 code anymore.
I know there is no standards-conform solution to this, as casting the function pointer to the wrong type is of course undefined behavior. But if someone has a solution that works at least on 64bit Windows with Visual C++, or a solution that works with clang on MacOS, I would be most delighted.
#Lorinczy Zsigmond is right in that the contents of the register are undefined if the function does something but returns nothing.
We found however that in practice, the plugins that return nothing also have almost always empty functions that compile to a retn 0x0 and leaves the return register untouched. We can detect this case by spraying the rax register with a known value (0xdeadbeef) and checking for that.
My constructor is as next
ScaperEngine::ScaperEngine(GrabberType grabberType, bool timing) {
switch (grabberType)
{
case GrabberType::DepthSenseGrabber:
this->interface = new pcl::DepthSenseGrabber("");
break;
default:
throw new std::exception("Grabber type wasn't chosen correctly");
break;
}
executionPipeline = new ExecutionPipeline();
executionPipeline->setTiming(timing);
}
And then I have some code like:
void ScaperEngine::StartPipeline()
{
IPCLNormalCalculator* normalCalculator = new PCLNormalCalculator(normalCalcMaxDepthChangeFactor, normalSmoothingSize);
executionPipeline->SetPCLNormalCalculator(normalCalculator);
The most strange thing is that the constructor is building executionPipeline in the right way putting its place in memory in 0x0000020ef385e830, but when my c# managed code calls StartPipeline the executionPipeline address changed to 0xcdcdcdcdcdcdcdcd and in Quick Watch the following text appears for its variables <Unable to read memory>.
Please anyone has a clue whats going on?
With many thanks.
The 0xcdcdcdcdcdcdcdcd you are seeing is a special feature of the Visual Studio debugger that represents uninitialized heap memory. A more comprehensive list of codes are available from this StackOverflow question. In brief, it seems as though your C# code is calling StartPipeline() on an invalid object. This could happen, for example, if the pointer is altered to point to a random location in heap memory. Make your C# code (and the runtime) is properly storing the pointer to the ScraperEngine object and not corrupting it along the way.
In my tiny little Rust program, I'm calling a Windows API and want to make sure that everything went OK. In order to do so, I'm using the functionality provided by std::io::Error::last_os_error(). I also want to deliberately ignore some of the errors that may occur.
I could not find any information on how to do that, other than just printing out the Error returned by that function. What I actually need is a kind of a match statement in which I can handle the various known errors.
I understand that the function returns an std::io::Error struct but I could not find any information on error IDs or similar concepts.
Currently, my code reads like
use std::io::Error;
fn main() {
// do some stuff that may lead to an error
match Error::last_os_error() {
163 => // Do nothing. This error is to be expected
// _ => Err("Something went wrong "),
}
}
The actual problem is that last_os_error() returns an error struct but I want to match on the ID of the error that is listed in WinError.h (this program only runs under Windows).
Can anybody help me on how to distinguish the various errors behind the error structs in such a match statement?
You can use io::Error::raw_os_error to get the original error code and then match against that:
match Error::last_os_error().raw_os_error() {
Some(163) => {} // Do nothing. This error is to be expected
Some(e) => panic!("Unknown OS error {}", e),
None => panic!("Not an OS error!"),
}
It's a different question of whether this is a good idea or not. You can also match against known error types. I'd recommend using that where possible. You may also want to create (or find) an enum that maps the various error codes to human-readable values, as it's a lot easier to tell that you meant NotEnoughMemory instead of SecurityDescriptorInvalid than it is to tell the difference of 123 and 132.
I need to create a user program that will be able to see how many processes are running with help of system calls. I found out that getsysinfo() function can give me the result but I get errors when I try to compile my code.
I used the following code:
struct kinfo kinfo;
int nr_tasks, nr_procs;
getsysinfo(PM_PROC_NR, SI_KINFO, &kinfo);
nr_procs = kinfo.nr_pro;
The problem is, I get many errors when compiling. I see that there are many undefined variables and I don't know what libraries I should include. The code just seems too shallow to understand.
A Google search for 'minix getsysinfo' reveals various sources, including:
How does function getsysinfo work in Minix
This says, amongst other things, that the function is only accessible inside the kernel, not in user code. It also contains a code fragment very similar to what you show, along with the commentary:
endpoint_t who // from whom to request info
int what // what information is requested
void *where // where to put it
size_t size // how big it should be
Example:
struct kinfo pinf;
int num_procs;
getsysinfo(PM_PROC_NR, SI_KINFO, &pinf);
num_procs = pinf.nr_pro;
It's at least somewhat curious that the description says '4 arguments' and the example uses just '3 arguments' (and your code does too).
Minix identifier search: getsysinfo()
Defined as a function in:
minix/lib/libsys/getsysinfo.c, line 8
Defined as a function prototype in:
minix/include/minix/sysinfo.h, line 8
One of the fragments of code also referenced shows a call:
if (getsysinfo(RS_PROC_NR, SI_PROCPUB_TAB, rprocpub, sizeof(rprocpub)) != OK …
This shows the fourth argument described but omitted from the example quoted in the question and the first link.
Both those and the other references look like kernel code rather than user code. So, superficially, if you're writing a user-side program for Minix, you can't access this function because it is in the kernel, not in the user-callable C libraries.