From 63f0169643d4385ac88c15c44d7d1b20453f4d96 Mon Sep 17 00:00:00 2001 From: Dmitry Vasilevsky Date: Tue, 8 Jun 2021 00:24:26 -0700 Subject: [PATCH 01/13] Use of exceptions recommendation --- src/Qir/QIR-RT-API-Design-Guidelines.md | 129 +++++++----------------- 1 file changed, 39 insertions(+), 90 deletions(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index b56987b0ac6..aefd81913f6 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -353,16 +353,44 @@ The plan was to replace the exception throw with the [`exit()`](https://www.cplu or [`terminate()`](https://www.cplusplus.com/reference/exception/terminate) or [`abort()`](https://www.cplusplus.com/reference/cstdlib/abort) or other alternatives. -To minimize the risk of getting the C++ exceptions crossing the ABI boundary, minimize the use of the throwing calls. -Consider the non-throwing versions of the calls that you use. -E.g. -* Consider the _nothrow_ version of the [`operator new()`](https://www.cplusplus.com/reference/new/operator%20new/) -(for single elements) and -[`operator new[]()`](https://www.cplusplus.com/reference/new/operator%20new[]/) (for arrays), e.g. -```c++ -int * myDynamicIntArray = new int[10]; // In case of allocation failure THROWS! Avoid using this. -int * myDynamicIntArray = new (std::nothrow) int[10]; // In case of allocation failure returns the nullptr. Consider this first. -``` +On the other hand, exceptions are a natural part of the C++ standard. It is virtually impossible to use +the standard library (STL, std namespace) and not to use exceptions. All _exceptional_ situations are +reported by using exceptions (such as out_of_range or invalid_argument to name a few). So it is safe to assume +that the C++ code we are developing will throw exceptions even if they aren't thrown right in the code we write. + +Recommendation is to use std namespace and exceptions in C++ code **only where appropriate**. Many recommendations +exist on how to use exceptions properly and minimize performace penalties. This section will describe only exceptions +with regards to the runtime API. + +* Do not handle hardware exceptions and out-of-memory exception + +It is not recommended to catch asynchronous harware exceptions, this is sometimes called +[Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160). +An example of a hardware exception is a segmentation fault. If such exceptional situation arises, application should +fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with +regards to the host OS. NOTE: MSVC compiler accepts the [`/EHs`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) switch to disable hardware exception handing in catch() blocks. + +It is also not recommended to handle out-of-memory exception as there's a very little chance of handling it right. +For such handling to work correctly there shouldn't be any memory allocation from the point of exception, in the stack +unwinding process, till the handling of exception and in the handling of exception until the out-of-memory situation +is resolved. Just let the application fail. For the same reason, using non-throwing version of operator new is not recommended. + +* Mark interface functions with noexcept + +If you implement an interface function mark it with [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec): + +> void interface_func() **noexcept** + +If exception is thrown (and not caught) within the noexcept function, the application will terminate. Termination will +ensure that exceptions will never cross the API boundaries. An overhead is incurred if a noexcept function +calls functions that can throw exceptions, so consider marking all functions that shouldn't throw exceptions as noexcept. +If you are calling functions that can throw exceptions, make sure to handle them properly. + +extern "C" functions aren't considered noexcept by default. Consider marking them noexcept, but only when they are +compiled by the C++ compiler (and not by a pure C compiler). NOTE: MSVC compiler accepts +[`/EHsc`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) +flag to treat extern "C" functions as not throwing. + * If using the [`dynamic_cast<>()`](https://en.cppreference.com/w/cpp/language/dynamic_cast), consider casting the _pointers_ rather than _references_, e.g. ```c++ @@ -370,86 +398,7 @@ MyClass myInstance = .. // Create an instance of a class that may or may not imp IMyInterface & myItfRef = dynamic_cast( myInstance); // Casts the _reference_, in case of failure THROWS! Avoid using this. IMyInterface * myItfPtr = dynamic_cast(&myInstance); // Casts the _pointer_, in case of failure returns the nullptr. Consider this first. ``` - -#### The `noexcept` Specifier and Exception Specification - -At the moment of writing there is _no_ recommendation about using or avoiding the -[`noexcept` specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec) or -[exception specification](https://en.cppreference.com/w/cpp/language/except_spec) -(for the C++ code internal to your binary), e.g. -> void func() **noexcept** -void func2() **throw()** - -This absence of recommendation is based on the materials listed below. Parts of them are definitely out-of-date. -If you have a strong opinion (and, for example, can demonstrate in more details -why `noexcept` and/or `throw()` are better than not using them) -then you are more than welcome to share your knowledge. - -Materials: -* (Current state) The [`noexcept` specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec), -the fragments of a special interest: -> Non-throwing functions are permitted to call potentially-throwing functions .. -> Note that a `noexcept` specification on a function is not a compile-time check .. -> `void baz() noexcept { throw 42; }` - -* (1996) [[MEC++]](https://github.com/kuzminrobin/code_review_notes/blob/master/book_list.md#mec++) -"More Effective C++" by Scott Meyers, Item 14: Use exception specifications judiciously -* (2002.07) [[pl@es]](https://github.com/kuzminrobin/code_review_notes/blob/master/article_list.md#pl@es) -Herb Sutter. A Pragmatic Look at Exception Specifications -* (<=2004) [[eses]](https://github.com/kuzminrobin/code_review_notes/blob/master/article_list.md#eses) -Herb Sutter. Exception Safety and Exception Specifications: Are They Worth It? -Item 4. When is it worth it to write exception specifications on functions? Why would you choose to write one, or why not? -* (Current state) -[C++ Core Guidelines](https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Re-noexcept) -(search for "noexcept") - -### Let the User Decide Whether to Crash or Not - -In some scenarios it is reasonable for the application or algorithm to crash upon memory allocation failure. -But if the crash is silent then we are not sure what to do, to restart, or to chase and fix a bug, -or to run on a different machine with more memory, etc. - -We want at least a message in the console, or a pop-up window, telling the reason of a crash, -and even better providing other actionalble information, like a stack trace, values of the local variables and parameters -(and ideally an opportunity to break in the debugger and/or getting a core dump for the subsequent analysis). -Generating such an information may require from our application some extra memory which is already exhausted. -To work around this we may want our application to pre-allocate a resonable chunk of memory during the start (the _rescue chunk_), -and once our application hits the memory allocation failure, -the application will deallocate the rescue chunk and generate the premortal disgnostics. - -In a more strict enviroment we may want our application to run 24 hours a day, 365 days a year (as a part of a cloud service for example). -During such a lengthy run the memory can get extremely fragmented, but a significant part of it can still be availble in small pieces. -The attempt to allocate a resonably large piece can fail because of the fragmentation, but would succeed if the memory was not fragmented. -To work around, our application, upon memory allocation failure, may want to run the defragmentation algorithm, e.g. -* deallocate the rescue chunk, -* save the data to a file, -* delete the data from the memory (memory becomes nearly empty), -* pre-allocate the resue chunk again (for the next run of the defragmentation algorithm), -* read the data from the file back to the memory (memory becomes defragmented), - -Then the application will repeat the failed memory allocation operation, likely succeed, and continue -(or save the current state and clearly tell the user to run again (continue) on a machine with more memory). - -The same applies to the exhaustion of any other resourse, like a number of qubits, number of file handles, disk space, etc. - -To summarize, exhaustion of a resource is not necessarily a bug, and is not as severe as it might look. -It is something that can be worked around (or stopped and continued in a better environment). -And only the user (not runtime) knows the requirements and scenarios. -That is why it seems reasonable to let the _user_ decide whether to crash or not. - -**Take-away:** In case of resource axhaustion consider returning the failure to the user, rather than crashing. - -(From C/C++ runtime we don't expect -[`malloc()`](https://man7.org/linux/man-pages/man3/malloc.3.html), -[`fopen()`](https://en.cppreference.com/w/c/io/fopen), or -[`operator new()`](https://www.cplusplus.com/reference/new/operator%20new/) -to crash, right? -The users of QIR RT very likely don't expect the resource allocation functions to crash either) - -Some more details about handling the memory allocation failure can be found in -* [[EC++3]](https://github.com/kuzminrobin/code_review_notes/blob/master/book_list.md#ec++3) -Scott Meyers. _Effective C++: 55 Specific Ways to Improve Your Programs and Designs_ (3rd Edition). -Chapter 8: Customizing `new` and `delete`. +This way you can handle the erroneous situation without raising exceptions. ## Considerations Taken Into Account From c0b7fb5721e3755ff77dc011176d372e05e639b1 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Tue, 8 Jun 2021 14:20:37 -0700 Subject: [PATCH 02/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Robin Kuzmin --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index aefd81913f6..3f4c3ff8cdc 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -355,7 +355,7 @@ or [`abort()`](https://www.cplusplus.com/reference/cstdlib/abort) or other alter On the other hand, exceptions are a natural part of the C++ standard. It is virtually impossible to use the standard library (STL, std namespace) and not to use exceptions. All _exceptional_ situations are -reported by using exceptions (such as out_of_range or invalid_argument to name a few). So it is safe to assume +reported by using exceptions (such as [`out_of_range`](https://en.cppreference.com/w/cpp/error/out_of_range) or [`invalid_argument`](https://en.cppreference.com/w/cpp/error/invalid_argument) to name a few). So it is safe to assume that the C++ code we are developing will throw exceptions even if they aren't thrown right in the code we write. Recommendation is to use std namespace and exceptions in C++ code **only where appropriate**. Many recommendations From eb1682dbca6abe5fc07e37ce79b2d60f5493426d Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Tue, 8 Jun 2021 14:20:43 -0700 Subject: [PATCH 03/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Robin Kuzmin --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 3f4c3ff8cdc..7956ea350b1 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -359,7 +359,7 @@ reported by using exceptions (such as [`out_of_range`](https://en.cppreference.c that the C++ code we are developing will throw exceptions even if they aren't thrown right in the code we write. Recommendation is to use std namespace and exceptions in C++ code **only where appropriate**. Many recommendations -exist on how to use exceptions properly and minimize performace penalties. This section will describe only exceptions +exist on how to use exceptions properly and minimize performance penalties. This section will describe only exceptions with regards to the runtime API. * Do not handle hardware exceptions and out-of-memory exception From 7abf6a424819a32b4318345971fecba347f07c3f Mon Sep 17 00:00:00 2001 From: Dmitry Vasilevsky Date: Tue, 8 Jun 2021 14:40:52 -0700 Subject: [PATCH 04/13] List of recommendations --- src/Qir/QIR-RT-API-Design-Guidelines.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 7956ea350b1..986ab6c49c9 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -359,8 +359,13 @@ reported by using exceptions (such as [`out_of_range`](https://en.cppreference.c that the C++ code we are developing will throw exceptions even if they aren't thrown right in the code we write. Recommendation is to use std namespace and exceptions in C++ code **only where appropriate**. Many recommendations -exist on how to use exceptions properly and minimize performance penalties. This section will describe only exceptions -with regards to the runtime API. +exist on how to use exceptions properly and minimize performance penalties. +* As part of [C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). +* [MSVC Documentation](https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160). +* [Exceptions and Error Handling](https://isocpp.org/wiki/faq/exceptions) As part of Modern C++ FAQ. +* Google guidelines recommend against exceptions, but [allow them in windows code, especially STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). +* [Vishal Chovatiya Guidelines](http://www.vishalchovatiya.com/7-best-practices-for-exception-handling-in-cpp-with-example/), which may be easier to read. +This section will describe only exceptions with regards to the runtime API. * Do not handle hardware exceptions and out-of-memory exception From eccddccc787fe957721f4a3c6493d18fd0b72d07 Mon Sep 17 00:00:00 2001 From: Dmitry Vasilevsky Date: Tue, 8 Jun 2021 15:06:38 -0700 Subject: [PATCH 05/13] Added MSVC doc link --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 986ab6c49c9..9562021e57a 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -361,7 +361,7 @@ that the C++ code we are developing will throw exceptions even if they aren't th Recommendation is to use std namespace and exceptions in C++ code **only where appropriate**. Many recommendations exist on how to use exceptions properly and minimize performance penalties. * As part of [C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). -* [MSVC Documentation](https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160). +* MSVC Documentation: [Modern C++ best practices for exceptions and error handling](https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160) and [How to: Design for exception safety](https://docs.microsoft.com/en-us/cpp/cpp/how-to-design-for-exception-safety?view=msvc-160). * [Exceptions and Error Handling](https://isocpp.org/wiki/faq/exceptions) As part of Modern C++ FAQ. * Google guidelines recommend against exceptions, but [allow them in windows code, especially STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). * [Vishal Chovatiya Guidelines](http://www.vishalchovatiya.com/7-best-practices-for-exception-handling-in-cpp-with-example/), which may be easier to read. From ce895c069e39e4c88f4146fd3d6219ae2855965b Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Wed, 9 Jun 2021 10:11:33 -0700 Subject: [PATCH 06/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Mathias Soeken --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 9562021e57a..bbaa0195956 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -363,7 +363,7 @@ exist on how to use exceptions properly and minimize performance penalties. * As part of [C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). * MSVC Documentation: [Modern C++ best practices for exceptions and error handling](https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160) and [How to: Design for exception safety](https://docs.microsoft.com/en-us/cpp/cpp/how-to-design-for-exception-safety?view=msvc-160). * [Exceptions and Error Handling](https://isocpp.org/wiki/faq/exceptions) As part of Modern C++ FAQ. -* Google guidelines recommend against exceptions, but [allow them in windows code, especially STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). +* Google guidelines recommend against exceptions, but [allow them in Windows code, especially STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). * [Vishal Chovatiya Guidelines](http://www.vishalchovatiya.com/7-best-practices-for-exception-handling-in-cpp-with-example/), which may be easier to read. This section will describe only exceptions with regards to the runtime API. From 8b124e5da56452aa03285955fb980be337912b53 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Wed, 9 Jun 2021 10:12:01 -0700 Subject: [PATCH 07/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Mathias Soeken --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index bbaa0195956..88ea6d3df88 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -371,7 +371,7 @@ This section will describe only exceptions with regards to the runtime API. It is not recommended to catch asynchronous harware exceptions, this is sometimes called [Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160). -An example of a hardware exception is a segmentation fault. If such exceptional situation arises, application should +An example of a hardware exception is a segmentation fault. If such exceptional situation arises, the application should fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with regards to the host OS. NOTE: MSVC compiler accepts the [`/EHs`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) switch to disable hardware exception handing in catch() blocks. From 83fb5b91c614e17125f4d26e92435e081940b909 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Wed, 9 Jun 2021 10:12:19 -0700 Subject: [PATCH 08/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Mathias Soeken --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 88ea6d3df88..0c00706164d 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -373,7 +373,7 @@ It is not recommended to catch asynchronous harware exceptions, this is sometime [Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160). An example of a hardware exception is a segmentation fault. If such exceptional situation arises, the application should fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with -regards to the host OS. NOTE: MSVC compiler accepts the [`/EHs`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) switch to disable hardware exception handing in catch() blocks. +regards to the host OS. NOTE: MSVC compiler accepts the [`/EHs`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) switch to disable hardware exception handing in `catch` blocks. It is also not recommended to handle out-of-memory exception as there's a very little chance of handling it right. For such handling to work correctly there shouldn't be any memory allocation from the point of exception, in the stack From 307c30f8d3a1987602bacf795ff033b99d9fa736 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Wed, 9 Jun 2021 10:12:29 -0700 Subject: [PATCH 09/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Mathias Soeken --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 0c00706164d..61510d7be87 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -382,7 +382,7 @@ is resolved. Just let the application fail. For the same reason, using non-throw * Mark interface functions with noexcept -If you implement an interface function mark it with [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec): +If you implement an interface function mark it with the [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec): > void interface_func() **noexcept** From eec42e80ce4fb64cfd5c98b90135c9b72867c1e0 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Wed, 9 Jun 2021 10:12:39 -0700 Subject: [PATCH 10/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Mathias Soeken --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 61510d7be87..dd9c9d2e31c 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -386,7 +386,7 @@ If you implement an interface function mark it with the [noexcept specifier](htt > void interface_func() **noexcept** -If exception is thrown (and not caught) within the noexcept function, the application will terminate. Termination will +If an exception is thrown (and not caught) within the noexcept function, the application will terminate. Termination will ensure that exceptions will never cross the API boundaries. An overhead is incurred if a noexcept function calls functions that can throw exceptions, so consider marking all functions that shouldn't throw exceptions as noexcept. If you are calling functions that can throw exceptions, make sure to handle them properly. From 6b4f259a6963c9e4dc8aae9c9e96f8c3f3d1a5c9 Mon Sep 17 00:00:00 2001 From: DmitryVasilevsky <60718360+DmitryVasilevsky@users.noreply.github.com> Date: Thu, 10 Jun 2021 12:23:52 -0700 Subject: [PATCH 11/13] Update src/Qir/QIR-RT-API-Design-Guidelines.md Co-authored-by: Robin Kuzmin --- src/Qir/QIR-RT-API-Design-Guidelines.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index dd9c9d2e31c..f457cf9c245 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -380,7 +380,7 @@ For such handling to work correctly there shouldn't be any memory allocation fro unwinding process, till the handling of exception and in the handling of exception until the out-of-memory situation is resolved. Just let the application fail. For the same reason, using non-throwing version of operator new is not recommended. -* Mark interface functions with noexcept +* Mark interface functions with `noexcept` If you implement an interface function mark it with the [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec): From d418e09a35ea1ab7444ad11db7f5565bb55de6ee Mon Sep 17 00:00:00 2001 From: Dmitry Vasilevsky Date: Thu, 10 Jun 2021 18:09:14 -0700 Subject: [PATCH 12/13] CR feedback: Updated text about exceptions --- src/Qir/QIR-RT-API-Design-Guidelines.md | 36 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 9562021e57a..41adced17c4 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -363,7 +363,7 @@ exist on how to use exceptions properly and minimize performance penalties. * As part of [C++ core guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). * MSVC Documentation: [Modern C++ best practices for exceptions and error handling](https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-cpp?view=msvc-160) and [How to: Design for exception safety](https://docs.microsoft.com/en-us/cpp/cpp/how-to-design-for-exception-safety?view=msvc-160). * [Exceptions and Error Handling](https://isocpp.org/wiki/faq/exceptions) As part of Modern C++ FAQ. -* Google guidelines recommend against exceptions, but [allow them in windows code, especially STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). +* Google guidelines recommend against exceptions, but [allow them in windows code, especially while using STL](https://google.github.io/styleguide/cppguide.html#Windows_Code). * [Vishal Chovatiya Guidelines](http://www.vishalchovatiya.com/7-best-practices-for-exception-handling-in-cpp-with-example/), which may be easier to read. This section will describe only exceptions with regards to the runtime API. @@ -371,9 +371,8 @@ This section will describe only exceptions with regards to the runtime API. It is not recommended to catch asynchronous harware exceptions, this is sometimes called [Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160). -An example of a hardware exception is a segmentation fault. If such exceptional situation arises, application should -fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with -regards to the host OS. NOTE: MSVC compiler accepts the [`/EHs`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) switch to disable hardware exception handing in catch() blocks. +Examples of hardware exceptions are the exception thrown when accessing a forbidden memory location as a result of a null pointer access, stack overflow, corrupt pointer dereferencing, unaligned memory access, etc.. If such exceptional situation arises, application should fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with +regards to the host OS. NOTE: The [MSVC's default exception handling behavior](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160#default-exception-handling-behavior) does not conform to the C++ standard. Use the `/EHsc` flag to [conform to the standard](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160#standard-c-exception-handling). It is also not recommended to handle out-of-memory exception as there's a very little chance of handling it right. For such handling to work correctly there shouldn't be any memory allocation from the point of exception, in the stack @@ -384,18 +383,37 @@ is resolved. Just let the application fail. For the same reason, using non-throw If you implement an interface function mark it with [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec): +Inside of your binary if you implement a function that should not throw exceptions, then mark it with the [noexcept specifier](https://en.cppreference.com/w/cpp/language/noexcept_spec). + > void interface_func() **noexcept** +extern "C" functions aren't considered noexcept by default. Consider marking them noexcept. +Keep in mind that `noexcept` specifier is a C++ feature. If you need to add `noexcept` specifier +to a public header or any other header that should be compatible with a pure C compiler +make sure to use `__cplusplus` guards. For example: + +```c++ +#ifdef __cplusplus +#define NOEXCEPT noexcept // `noexcept` in C++ only. +extern "C" +{ +#else +#define NOEXCEPT // In C this macro is empty. +#endif + +.. // `#include`s +void f() NOEXCEPT; // Exposed function. It is `noexcept` if the header is included to the C++ source file. + +#ifdef __cplusplus +} // extern "C" +#endif +``` + If exception is thrown (and not caught) within the noexcept function, the application will terminate. Termination will ensure that exceptions will never cross the API boundaries. An overhead is incurred if a noexcept function calls functions that can throw exceptions, so consider marking all functions that shouldn't throw exceptions as noexcept. If you are calling functions that can throw exceptions, make sure to handle them properly. -extern "C" functions aren't considered noexcept by default. Consider marking them noexcept, but only when they are -compiled by the C++ compiler (and not by a pure C compiler). NOTE: MSVC compiler accepts -[`/EHsc`](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160) -flag to treat extern "C" functions as not throwing. - * If using the [`dynamic_cast<>()`](https://en.cppreference.com/w/cpp/language/dynamic_cast), consider casting the _pointers_ rather than _references_, e.g. ```c++ From 5d97d1b2eb799ad95e9617048cfd64fe172c84cb Mon Sep 17 00:00:00 2001 From: Dmitry Vasilevsky Date: Thu, 10 Jun 2021 18:25:37 -0700 Subject: [PATCH 13/13] CR feedback: SEH --- src/Qir/QIR-RT-API-Design-Guidelines.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Qir/QIR-RT-API-Design-Guidelines.md b/src/Qir/QIR-RT-API-Design-Guidelines.md index 1699837d7ac..f3f1492176f 100644 --- a/src/Qir/QIR-RT-API-Design-Guidelines.md +++ b/src/Qir/QIR-RT-API-Design-Guidelines.md @@ -369,9 +369,9 @@ This section will describe only exceptions with regards to the runtime API. * Do not handle hardware exceptions and out-of-memory exception -It is not recommended to catch asynchronous harware exceptions, this is sometimes called -[Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160). -Examples of hardware exceptions are the exception thrown when accessing a forbidden memory location as a result of a null pointer access, stack overflow, corrupt pointer dereferencing, unaligned memory access, etc.. If such exceptional situation arises, application should fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with +It is not recommended to catch asynchronous harware exceptions. (MSVC compiler calls this +[Structured Exception Handling](https://docs.microsoft.com/en-us/cpp/cpp/structured-exception-handling-c-cpp?view=msvc-160).) +Examples of hardware exceptions are the exceptions thrown when accessing a forbidden memory location as a result of a null pointer access, stack overflow, corrupt pointer dereferencing, unaligned memory access, etc.. If such exceptional situation arises, application should fail fast and quit. Typically hardware exceptions are handled in a system level code, and our runtime is an application with regards to the host OS. NOTE: The [MSVC's default exception handling behavior](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160#default-exception-handling-behavior) does not conform to the C++ standard. Use the `/EHsc` flag to [conform to the standard](https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=msvc-160#standard-c-exception-handling). It is also not recommended to handle out-of-memory exception as there's a very little chance of handling it right.