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

fix: check that we receive a scalar when expecting a scalar in C code #1051

Merged
merged 4 commits into from
Jan 1, 2024

Conversation

szhorvat
Copy link
Member

@szhorvat szhorvat commented Dec 30, 2023

This is experimental. It is not completely clear to me if calling the error function directly at this point is fine ... there needs to be clarity about IGRAPH_CHECK vs IGRAPH_R_CHECK and where each is allowed to be used.

This fixes a potential crash in code such as sample_pref(c(), 3). Here c() is a zero-length vector which means that the C code would do an out-of-bounds access. This may or may not crash depending on your luck.

The behaviour is now like this:

> sample_pref(c(10,20), 3)
Error in sample_pref(c(10, 20), 3) : 
  At rinterface.c:1211 : Expecting a scalar but received a vector of length 2. Invalid value
> sample_pref(c(), 3)
Error in sample_pref(c(), 3) : 
  At rinterface.c:1211 : Expecting a scalar but received a vector of length 0. Invalid value

This is likely to cause revdepcheck failures. @krlmlr It would actually be worth doing a revdepcheck with this soon, as it may reveal graph bugs as well.

EDIT: Now it also checks for non-integer values (including NaN and infinities) when an integer is expected.

> sample_pref(1.23, 3)
Error in sample_pref(1.23, 3) : 
  At rinterface.c:1366 : The value 1.23 is not representable as an integer. Invalid value
> sample_pref(NA, 3)
Error in sample_pref(NA, 3) : 
  At rinterface.c:1366 : The value nan is not representable as an integer. Invalid value

Copy link
Contributor

aviator-app bot commented Dec 30, 2023

Current Aviator status

Aviator will automatically update this comment as the status of the PR changes.
Comment /aviator refresh to force Aviator to re-examine your PR (or learn about other /aviator commands).

This PR was merged using Aviator.


See the real-time status of this PR on the Aviator webapp.

Use the Aviator Chrome Extension to see the status of your PR within GitHub.

@szhorvat
Copy link
Member Author

This already revealed an incorrect usage in an example, which I just fixed. See e44efad

@szhorvat szhorvat force-pushed the fix/check-scalar-conversion-to-c branch 5 times, most recently from 959bda8 to 3aa8a68 Compare December 30, 2023 13:21
Copy link
Contributor

@krlmlr krlmlr left a comment

Choose a reason for hiding this comment

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

Good idea, thanks!

tools/stimulus/types-RC.yaml Outdated Show resolved Hide resolved
tools/stimulus/types-RC.yaml Outdated Show resolved Hide resolved
@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

The coverage checks take a hit here. I wonder if we should extract this conversion into a function, I suspect we won't add invalid argument checks for each and every function.

@szhorvat
Copy link
Member Author

I also wonder if this should use Rf_error() instead.

I don't think so because memory is then not freed.

Error handling in R/igraph is still a bit of a mess. We don't have clear guidelines, and I don't have a full understanding of how this work or should work. This should really be figured out before 2.0. Otherwise making changes like this one is stressful and risky.

I wrote down my current understanding in a wiki page. Can you take a look? https://github.com/igraph/rigraph/wiki/Error-handling-in-C

If what I wrote is correct then igraph functions cannot be called from a callback. If they are called anyway, things will go wrong. Is this accurate?

Let's figure out how this should work, and continue afterwards.

CC @ntamas

@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

What memory is there to free during argument checks? Do we need to separate argument checking from conversion?

@szhorvat
Copy link
Member Author

What memory is there to free during argument checks? Do we need to separate argument checking from conversion?

Some arguments may be vector-valued. These may get converted to igraph vectors, which will need to be freed if there is a failure.

@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

Is this still a problem if we first check arguments and then convert them?

@szhorvat
Copy link
Member Author

Is this still a problem if we first check arguments and then convert them?

No, that is not possible. Suppose there are two vector arguments. First construct one, then the other. If the second construction fails, the first needs to be freed. This will always be a problem in some form.

The error handling will need to be clarified either way, and it is completely doable. Trying to avoid error handling just for argument checks won't gain us anything. Am I missing something?

@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

We already agreed to use C++ and RAII for resource handling. Things will be much better once we have that. Right now, I'm focusing on releasing an update for the R package that will allow more frequent updates of the C core.

I'd like to postpone anything that's not moving us closer to that milestone. The checks in this PR are great, but I'd rather not open another can of worms here.

@szhorvat
Copy link
Member Author

OK, just let me know if you plan to merge this before 2.0. If yes, I'll address your comments.

@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

I'll run revdepchecks and push the results here. It's certainly good to have this in the code, an error (even with a memory leak) is better than undefined behavior.

@szhorvat szhorvat force-pushed the fix/check-scalar-conversion-to-c branch from bf5a6b9 to bc573e8 Compare December 30, 2023 21:06
@szhorvat szhorvat marked this pull request as ready for review December 30, 2023 21:07
@szhorvat
Copy link
Member Author

Stylistic changes committed and squashed, handing this off to you now.

@krlmlr
Copy link
Contributor

krlmlr commented Dec 30, 2023

Thanks. I still think length and integerness checks should live in their own functions, for more realistic coverage results. We can run revdepchecks on the current state, but now that #1055 is merged, we might as well extract the functions as part of this PR.

@Antonov548: can you please extract functions for checking length one and integerness, and use them for the generated code?

@Antonov548
Copy link
Contributor

Thanks. I still think length and integerness checks should live in their own functions, for more realistic coverage results. We can run revdepchecks on the current state, but now that #1055 is merged, we might as well extract the functions as part of this PR.

@Antonov548: can you please extract functions for checking length one and integerness, and use them for the generated code?

Yes, sure. I will take a look.

@krlmlr
Copy link
Contributor

krlmlr commented Dec 31, 2023

Only two failures, good to merge after extracting functions for the checks.

@krlmlr krlmlr marked this pull request as draft December 31, 2023 21:34
@Antonov548
Copy link
Contributor

Only two failures, good to merge after extracting functions for the checks.

Does it make sense to make it in the same pr?

@krlmlr krlmlr force-pushed the fix/check-scalar-conversion-to-c branch from b23f316 to 1fe583b Compare December 31, 2023 21:46
@krlmlr
Copy link
Contributor

krlmlr commented Dec 31, 2023

I think so, yes. This PR drops coverage, I'd like to get back to baseline before merging.

@szhorvat
Copy link
Member Author

szhorvat commented Jan 1, 2024

I think so, yes. This PR drops coverage, I'd like to get back to baseline before merging.

It doesn't truly reduce coverage. It only reduces the imperfect number that simple tools report. There are a lot of useful refactorings that drop that number, for example removing dead code often does.

@Antonov548
Copy link
Contributor

I think so, yes. This PR drops coverage, I'd like to get back to baseline before merging.

It's green now

Comment on lines +43 to +44
IGRAPH_R_CHECK_INT(%I%);
%C% = (igraph_integer_t) REAL(%I%)[0];
Copy link
Contributor

Choose a reason for hiding this comment

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

For the future: we could do something like

Suggested change
IGRAPH_R_CHECK_INT(%I%);
%C% = (igraph_integer_t) REAL(%I%)[0];
%C% = IGRAPH_R_CHECK_INT(%I%);

with a suitable implementation of IGRAPH_R_CHECK_INT() . It's good as is for now.

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for the other check functions.

Copy link
Contributor

aviator-app bot commented Jan 1, 2024

This pull request can't be queued because it's currently a draft.

@krlmlr krlmlr marked this pull request as ready for review January 1, 2024 13:45
@szhorvat
Copy link
Member Author

szhorvat commented Jan 3, 2024

@krlmlr What do you think about refactoring these functions to macros? The main advantage is that the line number in the error message would actually be useful for debugging. It would pinpoint where exactly the error came from. Doing this should not have an effect on coverage (assuming that coverage is measured in the same way as for the C core).

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

Successfully merging this pull request may close these issues.

3 participants