102 lines
3.4 KiB
Plaintext
102 lines
3.4 KiB
Plaintext
== Why is this an issue?
|
|
|
|
When an exception is a pointer, it is difficult for the code that catches the exception to determine whether or not it needs to delete the pointed-to object.
|
|
It is even more complicated than a traditional manual memory management scenario because the `throw` and the corresponding `catch` can be far apart.
|
|
|
|
== How to fix it
|
|
|
|
Throwing by value is more straightforward and less error-prone than using a pointer as an exception object.
|
|
|
|
=== Code examples
|
|
|
|
==== Noncompliant code example
|
|
|
|
[source,cpp,diff-id=1,diff-type=noncompliant]
|
|
----
|
|
std::out_of_range globalException("Index too high");
|
|
|
|
void fn(int i) {
|
|
// In this situation, the developer writing the "catch" has no way of knowing if the object pointed to by
|
|
// the exception should be deleted or not
|
|
if (i > 10) {
|
|
throw (&globalException); // Noncompliant: the catch is supposed not to delete the pointer
|
|
} else {
|
|
throw (new std::out_of_range{"Invalid index"}); // Noncompliant: the catch is supposed to delete the pointer
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
==== Compliant solution
|
|
|
|
[source,cpp,diff-id=1,diff-type=compliant]
|
|
----
|
|
std::out_of_range globalException("Index too high");
|
|
|
|
void fn(int i) {
|
|
if (i > 10) {
|
|
throw (globalException); // Compliant: it throws a copy of the global variable
|
|
} else {
|
|
throw (std::out_of_range{"Invalid index"}); // Compliant: it throws a new object
|
|
}
|
|
}
|
|
----
|
|
|
|
|
|
== Resources
|
|
|
|
=== External coding guidelines
|
|
|
|
* MISRA {cpp} 2008, 15-0-2 - An exception object should not have pointer type.
|
|
|
|
=== Related rules
|
|
|
|
* S1044 - Exception classes should be caught by reference
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
=== Message
|
|
|
|
Throw the exception by value.
|
|
|
|
|
|
'''
|
|
== Comments And Links
|
|
(visible only on this page)
|
|
|
|
=== on 14 Oct 2014, 17:51:53 Ann Campbell wrote:
|
|
\[~samuel.mercier] please correct the following
|
|
|
|
* Add a See section to the description listing the appropriate MISRA number
|
|
* Fill in Applicability.
|
|
* Make sure the appropriate MISRA C and MISRA {cpp} fields on the references tab are filled in
|
|
|
|
|
|
=== on 14 Oct 2014, 18:34:18 Ann Campbell wrote:
|
|
Also [~samuel.mercier] I don't think Maintainability is appropriate here. The risks are
|
|
|
|
* both caller and callee destroy the object - undefined behavior (likely runtime crash)
|
|
* neither caller nor callee destroys the object - memory leak
|
|
Since the worse outcome is a crash, I would associate this to Reliability
|
|
|
|
=== on 14 Oct 2014, 20:15:26 Freddy Mallet wrote:
|
|
And if this is associated to the Reliability category, then the tag 'pitfall' should be replaced by 'bug'
|
|
|
|
=== on 17 Oct 2014, 09:12:45 Samuel Mercier wrote:
|
|
\[~ann.campbell.2] caller cannot destroys the object, unless it also catches the exception it has thrown. But I agree about the memory leak, so I updated to Reliablity / Exception handling
|
|
|
|
=== on 20 Apr 2015, 10:00:42 Evgeny Mandrikov wrote:
|
|
\[~ann.campbell.2] this rule has tag "bug" and severity "critical", but not enabled by default. Is it on purpose?
|
|
|
|
=== on 20 Apr 2015, 10:09:05 Ann Campbell wrote:
|
|
It was on purpose [~evgeny.mandrikov], since this strikes me as potentially an issue of house style. If you think it is not, feel free to set it on by default.
|
|
|
|
=== on 11 May 2015, 20:24:44 Evgeny Mandrikov wrote:
|
|
\[~ann.campbell.2] I don't see any valid reason for catching/throwing an exception by pointer, , while opposite is highly recommended, so don't see any reason to not activate this rule by default.
|
|
|
|
endif::env-github,rspecator-view[]
|