[foreign] RFR 8212987 : Binder should allows negative values for native pointers
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Thu Nov 1 13:02:15 UTC 2018
Well, it just makes it a bit harder, but still doable? What we are
saying is that it's ok to go from PLUS to MINUS but not viceversa.
That said, I guess there are tricky case where you can go from PLUS to
PLUS via overflow and this mechanism would not detect it (e.g. if length
is Long.MAX_VALUE).
Maurizio
On 01/11/2018 12:53, Jorn Vernee wrote:
> Actually, I realized that the sign bit check doesn't work since it
> prohibits the case where min is positive but min + length is negative,
> which should be allowed since that is just signed overflow, which we
> don't want to block.
>
> Jorn
>
> Jorn Vernee schreef op 2018-11-01 13:13:
>> I could check the sign with something like this:
>>
>> final long SIGN_BIT = Long.MIN_VALUE;
>> if((min & SIGN_BIT) == ((min + length) & SIGN_BIT)) {
>>
>> (`signum` actually does something else than just extracting the sign
>> bit [1, 2])
>>
>> But the way I do it right now there's also a short-circuit if min is
>> not less than 0:
>>
>> if(min < 0 && min + length > 0) {
>>
>> If the problem is clarity, I can factor this into a helper method and
>> end up with something like this:
>>
>> if(canLengthCauseOverflow(min, length)) {
>>
>> We want to disallow negative addresses overflowing to positive ones,
>> but allow positive addresses overflowing to negative ones, basically
>> treating the address as an unsigned integer. In unsigned land there is
>> only one kind of overflow, from FFFFFFFF (all 1s) to 0, which
>> translates into negative-to-positive overflow in signed land (assuming
>> 2's complement numbers), so we want to only disallow that one.
>> Actually, AFAICT the previous implementation already allowed
>> to-negative (i.e. signed) overflow since you could construct a memory
>> region with min = Long.MAX_VALUE and length = Long.MAX_VALUE.
>>
>> Cheers,
>> Jorn
>>
>> [1] : https://en.wikipedia.org/wiki/Sign_function
>> [2] :
>> https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Long.html#signum(long)
>>
>>
>> Maurizio Cimadamore schreef op 2018-11-01 12:07:
>>> After taking a fresh look at this - would it suffice to check that
>>>
>>> signum(min + length) = signum(min)
>>>
>>> I think that, since signum(0) == signum(x), where x > 0, that should
>>> cover for the FFFFFFFF case with length 1. And it also should prevent
>>> positive addresses turning into negative ones and viceversa?
>>>
>>> Maurizio
>>>
>>> On 31/10/2018 11:02, Jorn Vernee wrote:
>>>> Oh. I ran the tests, but I'm getting a pass there since Windows
>>>> does not use the direct invoker, which means a different factory
>>>> method on BoundedPointer is getting called, which doesn't offset
>>>> into EVERYTHING. I'm afraid that's not something I can test right
>>>> now by myself.
>>>>
>>>> I tried to fix it by removing EVERYTHING in favor of calling
>>>> BoundedMemoryRegion.of(offset). But when testing that I'm seeing a
>>>> bunch of crashes in `V ~BufferBlob::invoke_native_blob` [1]. I
>>>> think that is the generated downcall stub that's crashing right?
>>>> Not sure what that's about, but I guess maybe some objects are now
>>>> getting GC'd too early since the memory region is no longer saved
>>>> in a static field, or maybe I still have a bug in that stub
>>>> generation code :/ (I took another look, but everything looks OK to
>>>> me).
>>>>
>>>> So instead I've made EVERYTHING an anonymous subclass which
>>>> overrides checkBounds to be empty, since technically any offset is
>>>> in bounds.
>>>>
>>>> I also realized the calculation still needed a special case for
>>>> Long.MIN_VALUE since that can't be negated.
>>>>
>>>> Can you test the new webrev?
>>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8212987/webrev.05/
>>>>
>>>> Thanks,
>>>> Jorn
>>>>
>>>> [1] :
>>>> http://hg.openjdk.java.net/panama/dev/file/f1afd0ae2932/src/hotspot/share/prims/universalNativeInvoker.cpp#l44
>>>>
>>>> Henry Jen schreef op 2018-10-31 01:05:
>>>>> That looks good, but we still have a little issue to iron out.
>>>>>
>>>>> New test failed because of BoundedPointer is offsetting EVERYTHING
>>>>> region, where length set to Long.MAX_VALUE.
>>>>>
>>>>> Cheers,
>>>>> Henry
>>>>>
>>>>>> test PointerTest.test1ByteRegionAtMaxHeapOffset(): failure
>>>>>> java.lang.IndexOutOfBoundsException: offset=0xffffffffffffffff
>>>>>> length=0x7fffffffffffffff
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.memory.BoundedMemoryRegion.checkBounds(BoundedMemoryRegion.java:153)
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.memory.BoundedMemoryRegion.checkRange(BoundedMemoryRegion.java:158)
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.memory.BoundedPointer.<init>(BoundedPointer.java:77)
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.memory.BoundedPointer.<init>(BoundedPointer.java:68)
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.memory.BoundedPointer.createNativeVoidPointer(BoundedPointer.java:175)
>>>>>> at
>>>>>> java.base/jdk.internal.foreign.invokers.DirectSignatureShuffler.longToPointer(DirectSignatureShuffler.java:335)
>>>>>> at
>>>>>> PointerTest$pointers$Impl/0x00000007c035b440.get_1_byte_pointer(Unknown
>>>>>> Source)
>>>>>> at
>>>>>> PointerTest.test1ByteRegionAtMaxHeapOffset(PointerTest.java:297)
>>>>>> at
>>>>>> java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native
>>>>>> Metho
>>>>>
>>>>>> On Oct 30, 2018, at 11:52 AM, Jorn Vernee <jbvernee at xs4all.nl>
>>>>>> wrote:
>>>>>>
>>>>>> Henry Jen schreef op 2018-10-30 18:46:
>>>>>>> I wonder if it can be simplified a little bit, let’s say address is
>>>>>>> indeed 0xFFFFFFFF, we should be able to have a memory region of
>>>>>>> length
>>>>>>> 1.
>>>>>>
>>>>>> Yes, that's a good point. That will allow for a 1 byte memory
>>>>>> region at 0xFFFFFFFF.
>>>>>>
>>>>>> I've also added a test for that exact case.
>>>>>>
>>>>>>> When the min(real address) is negative, the cap of length for
>>>>>>> unknown
>>>>>>> is pretty much just to negate the value of min.
>>>>>>
>>>>>> Yes! And I think when min is positive the length maximum is
>>>>>> always Long.MAX_VALUE.
>>>>>>
>>>>>>> min + length should be <= 0. We can only access min + offset -
>>>>>>> 1, so
>>>>>>> that we won’t access 0x0 in negative case.
>>>>>>
>>>>>> That won't work for the case where min and length are both
>>>>>> positive, but min + length is also positive. In that case the
>>>>>> check should also pass.
>>>>>>
>>>>>> The way I have it right now, since length is always positive, min
>>>>>> + length can only overflow to positive if min is negative, so
>>>>>> that's also the check :) But I've changed it to check for min +
>>>>>> length > 0 to allow for a 1 byte region if min == -1L.
>>>>>>
>>>>>>> What do you think?
>>>>>>
>>>>>> Good suggestions, here is the updated webrev:
>>>>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8212987/webrev.04/index.html
>>>>>>
>>>>>> I've also removed the spurious import in PointerTest, which
>>>>>> auto-complete put in there when auto-completing to @Transient
>>>>>> instead of @Test :)
>>>>>>
>>>>>>> Cheers,
>>>>>>> Henry
>>>>>>
>>>>>> Thanks for the reviews,
>>>>>> Jorn
>>>>>>
>>>>>>>> On Oct 30, 2018, at 9:49 AM, Jorn Vernee <jbvernee at xs4all.nl>
>>>>>>>> wrote:
>>>>>>>> Updated webrev:
>>>>>>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8212987/webrev.03/
>>>>>>>>
>>>>>>>> (beware that the BoundedMemoryRegion diff turned out a bit
>>>>>>>> confusing)
>>>>>>>> - Changed BoundeMemoryRegion to use factory methods.
>>>>>>>> - Factories that don't take a length calculate a max length
>>>>>>>> that can not overflow (in the unsigned sense).
>>>>>>>> - Moved BoundedMemoryRegion anonymous class from Pointer to
>>>>>>>> BoundedMemoryRegion, since constructor is now private.
>>>>>>>> - Added one more test to check for the error in the case where
>>>>>>>> the automatic length calculated for a native pointer is shorter
>>>>>>>> than the length required by the carrier type.
>>>>>>>> - Switched PointerTest to TestNG, since that makes it easier to
>>>>>>>> test for exceptions.
>>>>>>>> I've added a check for the overflow to BoundedMemoryRegion, but
>>>>>>>> when trying to test for it it turned out that BoundedPointer
>>>>>>>> was already catching that case. I've left the check there as it
>>>>>>>> will still be useful to catch programming errors when an
>>>>>>>> explicit length is being passed.
>>>>>>>> Trying to treat a signed long as unsigned is somewhat
>>>>>>>> confusing, maybe we should add an UnsignedLong utility class
>>>>>>>> that abstracts this away in a later RFR, especially if we start
>>>>>>>> allowing 'unsigned' longs in more places.
>>>>>>>> Jorn
>>>>>>>> Jorn Vernee schreef op 2018-10-30 11:26:
>>>>>>>>> You're right about `toUnsignedString`. For some reason I thought
>>>>>>>>> `toHexString` had the `-` as a prefix if the argument is
>>>>>>>>> negative.
>>>>>>>>> About the length constraint; My initial thought was just to
>>>>>>>>> trust the
>>>>>>>>> pointer returned from native, but I guess we should do better.
>>>>>>>>> In the
>>>>>>>>> specific case I'm testing, void *, the length that is being
>>>>>>>>> used is
>>>>>>>>> Long.MAX_VALUE, basically the length is unknown, so I don't
>>>>>>>>> think I
>>>>>>>>> can do a range check on min + length in the constructor in
>>>>>>>>> that case.
>>>>>>>>> As far as I can see, the `min` value is only used in a few min +
>>>>>>>>> offset calculations before passing to Unsafe put/get routines,
>>>>>>>>> I think
>>>>>>>>> we'd want to allow overflow to negative there, but not
>>>>>>>>> overflow to
>>>>>>>>> positive, basically treating the long as if it was unsigned.
>>>>>>>>> I think I will switch BoundedMemoryRegion to having factory
>>>>>>>>> methods
>>>>>>>>> that do the validation, and then have ones where the length is
>>>>>>>>> known,
>>>>>>>>> which do a range check, and ones where the length is unknown,
>>>>>>>>> that cap
>>>>>>>>> the it to where it can not overflow. Then I can use the latter
>>>>>>>>> for
>>>>>>>>> void *. If a bad pointer is passed from native, the
>>>>>>>>> known-length case
>>>>>>>>> should fail on construction of the memory region, and the
>>>>>>>>> unknown-length case should fail when dereferencing (since
>>>>>>>>> there is
>>>>>>>>> already a bounds check being done).
>>>>>>>>> What do you think?
>>>>>>>>> Thanks,
>>>>>>>>> Jorn
>>>>>>>>> Henry Jen schreef op 2018-10-30 01:59:
>>>>>>>>>> BTW, the change in toString is not needed, as
>>>>>>>>>> toUnsignedString(l, 16)
>>>>>>>>>> is same as toHexString(l)?
>>>>>>>>>> Cheers,
>>>>>>>>>> Henry
>>>>>>>>>>> On Oct 29, 2018, at 5:56 PM, Henry Jen
>>>>>>>>>>> <henry.jen at oracle.com> wrote:
>>>>>>>>>>> I am afraid this is not that simple, we need to at least
>>>>>>>>>>> protect length from overflow the address to >= 0.
>>>>>>>>>>> I haven’t completely check the implementation, we need to
>>>>>>>>>>> make sure all other operation will not expand or shift the
>>>>>>>>>>> region, which I believe is the constraint of the design. If
>>>>>>>>>>> that’s indeed the case, guard at construction is probably
>>>>>>>>>>> good enough.
>>>>>>>>>>> Cheers,
>>>>>>>>>>> Henry
>>>>>>>>>>>> On Oct 29, 2018, at 10:04 AM, Jorn Vernee
>>>>>>>>>>>> <jbvernee at xs4all.nl> wrote:
>>>>>>>>>>>> Hello,
>>>>>>>>>>>> Please review this patch which tweaks the binder to allow
>>>>>>>>>>>> negative values for native pointers.
>>>>>>>>>>>> The problem was previously discussed here:
>>>>>>>>>>>> http://mail.openjdk.java.net/pipermail/panama-dev/2018-October/002994.html
>>>>>>>>>>>> Bug : https://bugs.openjdk.java.net/browse/JDK-8212987
>>>>>>>>>>>> Webrev :
>>>>>>>>>>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8212987/
>>>>>>>>>>>> As a reminder, I'm not a committer, so someone else will
>>>>>>>>>>>> have to push this.
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Jorn
More information about the panama-dev
mailing list