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 is_null_terminated reading arbitrary memory (issue #1425) #1429

Merged
merged 8 commits into from
Nov 23, 2016
Merged

Fix is_null_terminated reading arbitrary memory (issue #1425) #1429

merged 8 commits into from
Nov 23, 2016

Conversation

Perelandric
Copy link
Contributor

@Perelandric Perelandric commented Nov 19, 2016

When _alloc is equal to _size, the is_null_terminated method will
point to arbitrary memory when checking for the 0 byte. This PR makes
that method first check that _alloc != _size before reading the
_size byte of the Pointer[U8].

Fixes #1425

When `_alloc` is equal to `_size` the `is_null_terminated` method will
point to arbitrary memory when checking for the `0` byte. This PR makes
that method first check that `_alloc != _size` before reading the
`_size` byte of the `Pointer[U8]`.
@Perelandric
Copy link
Contributor Author

It seems like there's an assumption in the library (at least sometimes) that the first _alloc byte that is greater than _size should be set to 0.

If this is consistent, then perhaps is_null_terminated can actually drop the (_ptr._apply(_size) == 0) check.

@jemc jemc added the changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge label Nov 21, 2016
@jemc
Copy link
Member

jemc commented Nov 21, 2016

Thank you! Can you also add a test case that highlights the fixed case?

@Perelandric
Copy link
Contributor Author

@jemc Tests added, though it occurs to me now that instead of this:

(_alloc > 0) and (_alloc != _size) and (_ptr._apply(_size) == 0)

we could probably do this:

(_alloc != _size) and (_ptr._apply(_size) == 0)

...since when they're not equal, _alloc should always be the greater of the two. I'll change it if it's deemed worthwhile and safe.

@Perelandric
Copy link
Contributor Author

Perelandric commented Nov 21, 2016

Appveyor has failed, travis is still running. The tests passed on my Linux box.

I changed the test case to no longer use a power of two length array. I don't know why that would make a difference, unless an array literal automatically allocates to the next power of two.

I'll add the power of two array test back in to see if it passes.


EDIT:

So it appears that an array literal does pre-allocate up to (presumably) the next power of two when it is not itself a power of two size. The tests have been updated to reflect this.


EDIT:

Well jeepers, this test fails no matter what I do...

    h.assert_true(String.from_iso_array(recover
      ['a', 'b', 'c']
    end).is_null_terminated())

Looks like I'm just born to lose. I'm going to reverse it back to h.assert_false and see what happens this time.

Tests that were previously added that create a String from a
non-power-of-two sized array literal were failing, so this adds a test
with a power-of-two sized array to see if it is not null termianted.
The `is_null_terminated` tests that test the from_iso_array strings have
been updated to reflect the apparent reality of preallocation that takes
place when the length of the length of the array literal is not a power
of two. It appears as though the array does get pre-allocated with zero
bytes up to the next power of two, and as such, is null-terminated.
@Perelandric
Copy link
Contributor Author

Well shucks. is_null_terminated returns neither true nor false for the same test.

**** FAILED: builtin/String.is_null_terminated
C:\projects\ponyc\packages\builtin_test\_test.pony:439: Assert true failed. 
**** FAILED: builtin/String.is_null_terminated
C:\projects\ponyc\packages\builtin_test\_test.pony:439: Assert false failed. 

I'm going to remove that test to see if it passes with only the one test. The test is in my comment above for quick reference.

@Praetonus
Copy link
Member

The test is inconsistent because allocated memory isn't set to zero in release mode.

@Perelandric
Copy link
Contributor Author

Perelandric commented Nov 22, 2016

Ah, I was going to ask if that preallocation was zeroed.

So then the only way that's going to work is if the first pre-allocated bit gets zeroed consistently. I have no idea how to do that for the literals. (EDIT: Oh wait, that's array literals. Nevermind.) Looks like that's missing in from_iso_array as well, which would've handled this case.

@Perelandric
Copy link
Contributor Author

PR #1436 sets the null byte in String.from_iso_array, so if that gets merged, I'll merge in that commit (if that's the right strategy) and redo the tests here.

@jemc
Copy link
Member

jemc commented Nov 22, 2016

It's been merged. Thanks!

This test was previously failing because of incorrect behavior of
`String.from_iso_array`, described in #1435, which has since been
fixed.
@Perelandric
Copy link
Contributor Author

Thanks @jemc, looks like everything passes.

@jemc jemc merged commit c54d46f into ponylang:master Nov 23, 2016
ponylang-main added a commit that referenced this pull request Nov 23, 2016
jemc pushed a commit that referenced this pull request Nov 23, 2016
The `space()` method assumes that the string is null termianted, and so
it always returns `_alloc - 1`. When not null terminated, the space
should return the full `_alloc`.

This PR assumes PR #1429 is correct and has been merged.

Fixes #1426
@Perelandric Perelandric deleted the fix_is_null_term branch November 24, 2016 00:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants