-
Notifications
You must be signed in to change notification settings - Fork 13
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
Error checks for malloc, calloc and write calls #17
Conversation
I don't think such blanket checks are a good issue. |
I don't think such blanket checks are a good issue.
I took
https://github.com/rdoeffinger/iec16022/blob/main/iec16022ecc200.c#L74
as an example and must admit my C-programming skills are very much
lacking.
More specific issues:
replacing calloc with malloc is not correct, these are not the same.
If anything, calloc should be used everywhere.
I get that but I don't known what to do about things like
https://github.com/rdoeffinger/iec16022/blob/main/image.c#L158 What has
a size 1? `sizeof(byte)` maybe?
Using size_t means behaviour is (more) architecture dependent.
Architecture-dependent behaviour makes checking and testing the code
harder. Ensuring the calling sites are restricted to int is better,
though could also use a 64-bit argument and check the value fits in
32-bit as an alternative if the former is too tricky.
So that's `unsigned int` for `size_t` and `int` for `ssize_t` and that
would work most of the time? I only have access to Linux and OpenBSD
environments to test, which both support `size_t` and friends.
The "safe" alloc wrappers are all buggy, a return value of NULL only
indicates an error if the size is not 0. Since they are duplicated,
such bugs are in multiple places, that is not good practice.
I did not realize this and I'm wondering what happens when you
`free(..)` a NULL pointer, that just works?
Some of this code is in library code, where just calling exit() is not
at all ok. These should likely call abort() instead - though whether
there is any value over just not checking at all and letting it crash
with a NULL pointer dereference is a question (whether any of those
cases would be exploitable or not may or may not be a relevant
question).
See comment about taking example from iec16022ecc200.c.
The unchecked writes are not good, however just blindly adding a check
and calling exit is not a good solution.
Since it's for PNG, a user concerned about robustness luckily can
easily verify the files are ok.
A more proper solution IMO would be to generate the data wholly in
memory and have a function return that. This can then in case of error
properly return NULL.
That's way out of my depth at this moment but I may look into that at
some later point in time.
Which would leave a single write() call afterwards, which can then be
properly checked and allows for more advanced and proper handling of
the error case (for interactive use, asking the user if we should try
again for example, otherwise deleting the incomplete/corrupted file
etc).
Not sure interactive use should be supported here as it brings in more
unwanted architecture dependencies (like checking if stdin is a tty for
instance). The inability to write should just result in a failure of
some kind, IMO.
Anyway.. I really appreciate your feedback and thank you for maintaining
this package. Please close this PR if you wish, I'll open an issue for
the unchecked [mc]alloc and write calls instead if you do and maybe have
another stab at fixing these issues when my C-programming skills have
improved.
Oh, and feedback on the remarks/questions in this comment are also
welcome! 😉
|
Yeah, there is some existing code that I think is not good. But for now I am primarily maintaining the code, i.e. fixing only things that actually cause issues.
If you mean "1" (as in neutral element of multiplication), just use 1.
It's not about supporting them.
Check "man 3 free". It says explicitly it does nothing is the argument is NULL.
No worries, there's a reason I've not done it myself, it's a bit much work without a concrete use-case showing its importance.
Yeah, I was just starting from the gut feeling that there likely is a more correct way to handle failures than exit (because there almost always is, which is why doing error handling right is so much effort, and doing it in a minimal effort way does not get good results).
I agree on the unchecked writes. For the unchecked [mc]alloc I am more tempted towards removing the existing checks, since I am not convinced checking won't always do more harm than good for those. |
Won't a ENOMEM cause a segfault then? Isn't attempting an error message I'll make an issue for the unchecked writes; #18 |
Sure.
In theory. Except for all the detail. As you hinted at though, if any printing even works if you were actually out of memory is questionable. |
Thx! |
IIRC, this is not the case on the Hurd, which Guix aims to support.
This program doesn't use much memory, but you can have another program running at the same time consuming much memory, possibly causing a malloc failure in iec16022.
If everyone does nothing because other people are doing nothing too, then we never get anything done. A small improvement is still an improvement, and with effort, lots of small improvements form a big improvement. And when reviewing source code of packages for Guix, I check for these kind of issues.
Proposal: ‘failed to allocate memory’? Then the user would know it's memory related -- segfaults can e.g. be caused by out-of-bounds reads as well, not only mere out of memory. (Or no message and only an abort.) |
For the unchecked [mc]alloc I am more tempted towards removing the
existing checks, since I am not convinced checking won't always do
more harm than good for those.
Won't a ENOMEM cause a segfault then? Isn't attempting an error message
and abort() nicer? If it gets through of course.. But removing the
existing safemalloc would be a good change because it sets the wrong
example. 🙂
I'll make an issue for the unchecked writes.
|
I'm not quite following what the positions are anymore, but 'abort on allocation failure' sounds good to me. However, writing error messages from a library can be potentially problematic (e.g. if the program was using fd 2 for their own error messages in some strict format and doesn't expect libraries to write their own things there, though that could perhaps be resolved by just noting in the |
Some error checking added on stdlib and stdio calls.