Open rstub opened 5 years ago
Hm. Is the mere presence of UB code sufficient to cause the segfault, even if it never gets executed? I will try to circumvent this at compile-time with by using an specialized template function for the shift that simply returns zero (or does nothing) for the most common (yet invalid) integer size/SHIFT
combinations.
I am not sure about the UB code causing these problems. My current theory is as follows:
convert_16(-1)
triggered the segfault. That is the first test that produces an error.std::out_of_range("...")
, but that particular constructor was only added in C++11, c.f. https://en.cppreference.com/w/cpp/error/out_of_range.So maybe it might be sufficient to add // [[Rcpp::plugins(cpp11)]]
to convert.cpp
. What do you think?
I thought we already had C++11 turned on in convert.cpp
. Hard to imagine anything compiling without it, given the constexpr
s in convert_seed.h
.
You are correct, C++11 is requested right in the first line of the file.
I still find it interesting that it fails for convert_16(-1)
, and that CRAN seems to use a different compiler than rhub.
I've been reading up about UB and it's pretty crazy. They weren't joking when they say that the compiler can do literally anything it wants. Possibly even more so if it knows that it's UB at compile time.
Getting rid of the UB may or may not fix it, but at least we don't have any warnings anymore. That's one less thing we need to argue about if we need to escalate this to the CRAN maintainers.
Interestingly, meanwhile MacOS also reports ERRORS:
Result: ERROR
Running ‘testthat.R’ [24s/24s]
Running the tests in ‘tests/testthat.R’ failed.
Last 13 lines of output:
`convert_64(c(1, 1, 0))` threw an error with unexpected message.
Expected match: "vector implies an out-of-range seed"
Actual message: "c++ exception (unknown reason)"
══ testthat results ═══════════════════════════════════════════════════════════
OK: 79 SKIPPED: 0 FAILED: 6
1. Failure: conversion to 16-bit integers works correctly (@test-convert.R#15)
2. Failure: conversion to 16-bit integers works correctly (@test-convert.R#16)
3. Failure: conversion to 16-bit integers works correctly (@test-convert.R#17)
4. Failure: conversion to 16-bit integers works correctly (@test-convert.R#18)
5. Failure: conversion to 32-bit integers works correctly (@test-convert.R#33)
6. Failure: conversion to 64-bit integers works correctly (@test-convert.R#55)
Error: testthat unit tests failed
Execution halted
This is odd, since MacOS is tested via Travis CI.
Anyway, the failed tests are all the ones that check for error conditions. So my suggestion would be to just skip those tests on CRAN. I don't like that, but I see no better immediate solution without the ability to reproduce the issues first.
Is this with the shift-avoiding code? Might be worth one last roll of the dice, especially if it is some UB. I suppose UBSan doesn't pick it up because it's not part of the dqrng shared library.
The tests on CRAN use the original version (it typically takes a few days for all CRAN machines to build a new or updated package). However, I have meanwhile been able to reproduce the MacOS failure with the most recent version. In addition, one of the failure happens for 64bit integers, where there is no UB.
That looks very relevant. And it fits to my recent experiences. Even the examples from http://gallery.rcpp.org/articles/intro-to-exceptions/ do not work properly on MacOS (CRAN build with matching clang). Only Rcpp::stop
does work properly. I guess a custom exception class derived from std::exception
would also work. So for MacOS I see four possibilities:
Rcpp::stop
in an otherwise Rcpp-independent piece of code.Introduce a custom exception class derived from std::exception
.
I don't like 2. and 3. The cleanest solution would b 4. (if it works). And 1. is the easiest solution, but also the one most likely to help with the Solaris ERROR. I am currently leaning towards 1.
Yes, agree that 1 is the best, if we can just do the skips on OSX. Alternatively, we could write a wrapper around expect_error
that just does 2 for OSX only, something like:
safe_expect_error <- function(..., msg) {
os.type <- Sys.info()["sysname"]
if (os.type=="Darwin") {
expect_error(...)
} else {
expect_error(..., msg)
}
}
Thanks, I like the safe_except_error
and put it into #17. I have also put in a skip_on_os("solaris")
for all the exception-triggering tests. I am not in the mood for gambling ... ;-)
Upload on Monday, since one build result is still missing and it avoids a NOTE.
Skipping on Solaris was successful. Whether it is necessary or merely sufficient is a different question. I meanwhile fear that it is some sort of ABI incompatibility triggered by compilation with the Oracle compiler instead of g++, c.f. https://stackoverflow.com/questions/54492667/segfault-when-throwing-stdruntime-error-on-ubuntu-xenial-with-rcpp.
Version 0.1.1 has been build on CRAN on all platforms. However, there are currently two limitations concerning the tests that deliberately throw a C++ exception:
It would be nice if a better solution could be found.
While everything works on
rhub
's Solaris machine, some of the new tests fail on CRAN's Solaris machine:CC: @LTLA