New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ARROW-4520: [C++] use voidified expr to ignore DCHECK() custom messages in NDEBUG #3599
ARROW-4520: [C++] use voidified expr to ignore DCHECK() custom messages in NDEBUG #3599
Conversation
Is it a warning or an error? I think we should try to follow closely what's in glog https://github.com/google/glog/blob/master/src/glog/logging.h.in#L1004 |
Is the PR missing something? AFAICT it's only replacing a |
@pitrou Sorry, I didn't rename the PR after changing my approach |
So unreachability wasn't the issue? |
Apparently the warning (error with -Werror) isn't emitted if the unreachable expression is cast to |
Isn't it what |
|
We can't pass that to |
Another suggestion: could we simply use |
How about the following: #define DCHECK(condition) \
ARROW_IGNORE_EXPR(condition); \
ARROW_CHECK(true)
#define DCHECK_EQ(val1, val2) \
ARROW_IGNORE_EXPR(val1); \
ARROW_IGNORE_EXPR(val2); \
ARROW_CHECK(true)
// [etc.] Hopefully that can please all compilers. |
I'm fine with it; I was just following @wesm's recommendation to use glog's solution |
@pitrou your proposed solution seems OK, might want to run a benchmark that involves DCHECK in debug builds to make sure the compiler is optimizing away the dead code. I was thinking there's no reason to deviate strongly from what is in glog since someone at Google would have noticed if it was wrong by now |
No strong opinion. We can go with this and revisit another time if another compiler complains. |
That said, it seems the manylinux crash is specific to this PR. It's also one of the rare CI entries that compiles in release mode... |
1ca97cf
to
c0a2121
Compare
@pitrou rebased and I still get the segfault in release mode. truncated stack trace:
full stack trace:
|
@bkietz Do you want me to take a look? You can also try to debug this in debug mode simply by tweaking the You may also want to look what happens to the DCHECK macro in |
@pitrou That would be appreciated, thanks. I'll try tweaking |
@bkietz Looks like my intuition was right. I fixed the issue here with the following diff: diff --git a/cpp/src/arrow/util/logging.h b/cpp/src/arrow/util/logging.h
index dfdfc71d..38ada2fd 100644
--- a/cpp/src/arrow/util/logging.h
+++ b/cpp/src/arrow/util/logging.h
@@ -80,22 +80,24 @@ enum class ArrowLogLevel : int {
#ifdef NDEBUG
#define ARROW_DFATAL ::arrow::util::ArrowLogLevel::ARROW_WARNING
-#define DCHECK(condition) \
- while (false) ARROW_CHECK(condition)
-#define DCHECK_OK(status) \
- while (false) ARROW_CHECK_OK(status)
+#define DCHECK(condition) \
+ ARROW_IGNORE_EXPR(condition); \
+ ARROW_CHECK(true)
+
+#define DCHECK_OK(status) \
+ ARROW_IGNORE_EXPR(status); \
+ ARROW_CHECK(true)
+
#define DCHECK_EQ(val1, val2) \
- while (false) ARROW_CHECK((val1) == (val2))
-#define DCHECK_NE(val1, val2) \
- while (false) ARROW_CHECK((val1) != (val2))
-#define DCHECK_LE(val1, val2) \
- while (false) ARROW_CHECK((val1) <= (val2))
-#define DCHECK_LT(val1, val2) \
- while (false) ARROW_CHECK((val1) < (val2))
-#define DCHECK_GE(val1, val2) \
- while (false) ARROW_CHECK((val1) >= (val2))
-#define DCHECK_GT(val1, val2) \
- while (false) ARROW_CHECK((val1) > (val2))
+ ARROW_IGNORE_EXPR(val1); \
+ ARROW_IGNORE_EXPR(val2); \
+ ARROW_CHECK(true)
+
+#define DCHECK_NE DCHECK_EQ
+#define DCHECK_LE DCHECK_EQ
+#define DCHECK_LT DCHECK_EQ
+#define DCHECK_GE DCHECK_EQ
+#define DCHECK_GT DCHECK_EQ
#else
#define ARROW_DFATAL ::arrow::util::ArrowLogLevel::ARROW_FATAL |
c0a2121
to
ce91f53
Compare
@wesm @pitrou |
@bkietz these cases should not abort in release builds. I think what can be done in such cases is this:
|
I do think they should either bubble an error, or abort. If we are not bubbling an error, it's usually because the function doesn't return an error code, so we have to abort. Ignoring errors is extremely bad. |
Also I have no opinion on whether expressions in debug checks should be always evaluated or not. |
Well, I think the idea here is that these particular function calls "can't fail" unless something is implemented wrong by an Arrow developer. It might be a good idea to refactor the code that is being used into two variants:
|
The way that DCHECK is used in practice, it is expected that the statements inside have no cost in release builds. I think that |
We could use |
Here's the code
If either of these cases occurs, there is a flaw in the implementation that can be caught by DCHECK in debug builds. It should not be possible to trigger these error conditions in release builds if the tests pass in debug builds |
Right, so either we don't check at all, or we abort on error (since it's a critical error). I don't think warning makes sense at all. |
cpp/src/arrow/util/logging.h
Outdated
ARROW_IGNORE_EXPR(val1); \ | ||
while (false) ::arrow::util::ArrowLogBase() | ||
while (false) ARROW_CHECK((val1) > (val2)) | ||
#define DABORT_NOT_OK(expr) ARROW_IGNORE_EXPR(expr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems this does not guarantee that the statements are executed in release builds
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ARROW_IGNORE_EXPR(expr)
evaluates the expression but cast it to void, so the compiler won't warn against a Status return which isn't examined
Yes, I think the correct option is:
So the implementation of
If STATEMENT has side effects then it will be executed in both debug and release builds |
also: what happened with appveyor? It shows green here on the PR (for me at least) but MinGW seems to have failed |
@bkietz The MinGW 32-bit failures are expected for now, that's why they don't fail the build ;-) |
I find this solution confusing. If I'm not strongly attached to one or the other alternative (either we check in release mode or not), but it should be consistent accross the board. |
But, really, since this PR started from the desire to fix a compilation failure, I think the simplest thing is to fix the compilation failure without changing the current semantics. We can revise the semantics in another JIRA / PR but that sounds a bit low-priority to me. |
72d0930
to
455ac88
Compare
This seems spurious: https://travis-ci.org/apache/arrow/jobs/497095148#L3065 |
455ac88
to
e508537
Compare
rebased |
@wesm the CI failure is unrelated to this PR, see ARROW-4684 |
For release builds
DCHECK( x ) << y << z;
currently expands toThis is unreachable which is an error using clang-7