Skip to content
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

Transform int to 0/1 before coercion to logical #398

Merged
merged 1 commit into from
Oct 20, 2017
Merged

Transform int to 0/1 before coercion to logical #398

merged 1 commit into from
Oct 20, 2017

Conversation

nacnudus
Copy link
Contributor

Fixes #385

The clue to solving this issue was in this twitter thread. Integers are coerced to logical in two places. One place does

SET_VECTOR_ELT(column, row, Rf_ScalarLogical(xcell->asInteger()));

where Rf_ScalarLogical transforms non-zero integers to 1 before coercing to logical. But the other place does

LOGICAL(column)[row] = xcell->asInteger();

Weirdly, the test passes even without this fix when run with testthat::test(). To get the test to fail (in fact, segfault), checkout the previous commit, install, and from within the project directory do

library(readxl)
library(testthat)
source("./tests/testthat/helper.R")
source("./tests/testthat/test-col-types.R")

Fixes #385

Weirdly, the test passes even without this fix when run with `testthat::test()`.  To get the test to fail, checkout the previous commit, install, and do

```r
library(readxl)
library(testthat)
source("./tests/testthat/helper.R")
source("./tests/testthat/test-col-types.R")
```

from within the project directory.  It will segfault.
@jennybc
Copy link
Member

jennybc commented Oct 20, 2017

Nice! Yes I had figured something like this was going on, but it's a big help to have it tracked down and fixed. Thanks!

I can reproduce almost everything you say, except this:

Weirdly, the test passes even without this fix when run with testthat::test().

I am running dev testthat and it does indeed catch it and correctly reports *** caught segfault ***. So that's good news too.

@jennybc
Copy link
Member

jennybc commented Oct 20, 2017

@jimhester I'm going to merge this. It's super small but important and a good lesson. Will you speak up if this is somehow not the correct fix? The linked issue will illustrate the problem this fixes.

@jennybc jennybc merged commit 411fda7 into tidyverse:master Oct 20, 2017
@jennybc
Copy link
Member

jennybc commented Oct 20, 2017

@nacnudus Will you make another PR with a bullet in NEWS?

@@ -256,7 +256,7 @@ class XlsxCell {
case CELL_NUMERIC:
{
rapidxml::xml_node<>* v = cell_->first_node("v");
return atoi(v->value());
return atoi(v->value()) != 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem correct, won't this convert any numeric value to 0 or 1? You only want to do this for the CELL_LOGICAL case, not both, no?

Also I think it is maybe clearer to be more explicit and use

return atoi(v->value()) != 0 ? 1 : 0;

But that is subjective.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct, in terms of how asInteger is actually used. It is only called when putting numeric data into logical cells.

But, yes, it suggests asInteger should perhaps be renamed to asLogical. Or I should have both. Or there should at least be a comment.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be asLogical and I would use Rf_LogicalFromReal() to do the conversion, which also handles the NaN case.

return Rf_LogicalFromReal(atoi(v->value()), nullptr);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

segfault when tabulating data incorrectly guessed as type "logical"
3 participants