5

It seems unclear, but there are claims that dereferencing a nullpointer is undefined behavior:

A comment by M.M.

This note was in fact removed as the result of DR 1102 with the stated reasoning being that it was not undefined behaviour to dereference a null pointer.

indicates that it might be defined behavior.

General agreement seems to be that it is undefined behavior.

So. Is it fine to call cv::setBreakOnError(true), which is supposed to cause raising an Access Violation on error()? Its implementation is as follows:

    if(breakOnError)
    {
        static volatile int* p = 0;
        *p = 0;
    }

Or does calling this function mean, that due to undefined behavior, anything could now happen when my program is compiled and run?

My own best guess is that it is technically undefined but happens to always(?) do the right thing on windows and linux

11
  • 3
    Dereferencing a nullptr is undefined behavior for the C++ standard and the C++ abstract machine. Due to undefined behavior, anything could now happen when the program is compiled and run. If lucky, it will crash. If unlucky, it may appear to work as expected (unless what is expected is that it crashes). If extraordinarily unlucky, it may email your browser history to your grandmother, and then format your hard drive. Commented Mar 4 at 12:44
  • 1
    Since your intent appears to be to break into the debugger programmatically, you might want to use std::breakpoint (C++26 onward), or boost::debug::debugger_break. Commented Mar 4 at 13:50
  • 1
    I think the point DR1102 tried to make was that the wording of the note was confusing and suggested that it was not the dereferencing as such but the effect of it that was undefined, and that the example should be replaced with a less confusing one. Commented Mar 4 at 14:54
  • 1
    don't blame OP for the title. the title was my attempt to purify the question by stripping the OpenCV baggage. -- what's lazy about it? Commented Mar 4 at 23:56
  • 1
    If you follow the link to issue 232 in your linked page, you see what they are talking about is that &*p (where p has a null pointer value) is not undefined because it does not actually fetch from memory or typeid(*p), which is defined to throw an exception. So it is not merely having the lvalue *p in an expression that is undefined, and hence merely notionally dereferencing the null pointer value is not undefined. However, actually dereferencing the value in the sense many people might think, turning the pointer into a value (lvalue-to-rvalue conversion), is undefined. Commented Mar 5 at 0:48

2 Answers 2

8

The reason dereferencing a null pointer value is said not to be undefined is they are using “dereferenced” to mean the * operator is applied to the pointer, not that there is actually an attempt to access a pointed-to-object.

The DR 1102 you link to further links to issue 232, where we can see one of the examples given is typeid(*p). Evaluation of this when *p is a polymorphic class type is defined to throw the exception bad_typeid. That is a definition of behavior, so the behavior is not undefined.

Actually attempting to access the dereferenced pointer would be undefined; foo = *p or *p = 0 would be undefined.

Sign up to request clarification or add additional context in comments.

6 Comments

typeid(*p) has been specified, since C++98, as throwing an exception if p is a null pointer - an implementation would only need to check the value of p, not necessarily evaluate *p, to meet that requirement. It strikes me as insanity (by the links you reference, not you) that this is now being used to justify a position that dereferencing a null pointer does not give undefined behaviour, and needing to shore up that position by (now) distinguishing between the act of evaluating *p if p is a null pointer and accessing the object that p points at.
@EricPostpischil Thanks for the additional context! Am I missing something or does this mean that this openCV function (cv::setBreakOnError(true)) should never be used, because it will lead to undefined behavior on .error()? My thinking is, if it is UB, it could do anything and then it seems silly to even exist in openCV so I must be missing something...
there's two kinds of people: those that go strictly by the book, and then there's pragmatists. OpenCV is pragmatic about things.
@lucidbrot: It is important to stop thinking of undefined behavior as a thing. When the C++ standard says something is undefined, that does not mean it is always undefined in every context. It only means the C++ standard does not provide a definition. It is silence or dark. Silence or dark can be changed by a different source that provides a statement or light. The C++ standard does not cast a “dark beam” that forces there to be darkness on behavior. It merely does not provide light. In setBreakOnError, OpenCV is relying on there being an access violation when it accesses a null pointer…
… It can do that if it knows the platforms it is targeted for will generate an access violation. It ought to document that clearly. One way it can know this is if the compilers it is intended for use only the zero address for null pointer values and the operating systems it is targeted for reserve the page at that address and generate exceptions when it is accessed. If those conditions are met, the behavior of setBreakOnError is not undefined to OpenCV users; it is defined to generate an exception…
|
0

Edit: according to Eric in the comments it is still undefined behavior because dereferencing a nullptr is different than accessing the underlying object, regardless of volatile existence, the rest of the answer is my original (questionable) interpretation of the standard.


the main point here is that it is a pointer to a volatile object, which is underspecified by the standard. it is up to the compiler how to implement it.

[decl.type.cv.5] The semantics of an access through a volatile glvalue are implementation-defined.

on systems with no memory protection (some embedded devices) you can write to address zero, and the system won't (immediately) crash.

you cannot use the standard to reason about this code, only the compiler/OS docs. and it seems to work fine on the target OS/compilers, which is the whole reason why volatile is underspecified by the standard.


If the pointer wasn't to a volatile then it would be undefined behavior, and the compiler would be allowed to do anything, including removing this memory access, or breaking the code before it.

9 Comments

@lucidbrot yes, most interactions with volatile are unspecified, the standard makes no guarantees on it.
How is volatile relevant? Do you mean the pointer is volatile or the pointed-to type is volatile? If you mean the pointer is volatile and p = nullptr; foo = *p; is not necessarily undefined because p might be non-null when *p is evaluated, that is not relevant to the question, as it is not an instance of dereferencing a null pointer. If you mean some C++ implementations might define *p to access address zero, that may be a conforming extension, but it does not render foo = *p defined in the C++ standard.
@EricPostpischil see dcl.type.cv The semantics of an access through a volatile glvalue are implementation-defined.
@AhmedAEK: That says the semantics of an access are implementation-defined. As my comment on the question notes, accessing an object is different from dereferencing an object. Further, it does not speak to attempting to access a dereferenced null pointer value; it speaks to accessing an object, which applies when there actually is an object being accessed…
… Following the links in OP’s post to issue 232 reveals the reason dereferencing a null pointer value is not said to be undefined is there are certain dereferences (&*p and typeid(*p) in their examples) that do not access an object and that do have defined behavior. While dereferences that do actually access the object, as in foo = *p; or *p = 0;, are undefined. And those are true regardless of whether the pointed-to type is volatile or not.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.