[foreign] RFR 8212987 : Binder should allows negative values for native pointers

Jorn Vernee jbvernee at xs4all.nl
Thu Nov 1 16:18:56 UTC 2018


If we just use `length = 0 - min` then we get a negative length if `min` 
is positive. Or do you want to treat `length` as unsigned as well?

Jorn

Henry Jen schreef op 2018-11-01 17:06:
> max length 0 - min won’t work for min == 0, that’s everything. We need
> to use test again max address to be 0-min-1, then comparison with
> length and max address should be < 0. You got the idea.
> 
> Cheers,
> Henry
> 
>> On Nov 1, 2018, at 8:21 AM, Henry Jen <henry.jen at oracle.com> wrote:
>> 
>> I was hesitate to reply as the fix is kind of hackish, but not ready 
>> to suggest we go all the way to enable full range of 64-bit, after 
>> all, Long.MAX_VALUE is giving us 8EB and that’s seems way more than 
>> enough. But to completely address rather than simply make it work for 
>> special cases, we probably should just treat address as unsigned and 
>> use Long.compareUnsigned to do comparison.
>> 
>> Therefore, max length for a memory always 0 - min. The length should 
>> be Long.compareUnsigned(length, maxLength) <= 0, with all other offset 
>> operation compare against length established at construction time with 
>> Long.compareUnsigned, that should be enough to deal with this.
>> 
>> However, taking offset with large(negative) number seems really 
>> confusing.
>> 
>> What do you think?
>> 
>> Cheers,
>> Henry
>> 
>>> On Nov 1, 2018, at 6:02 AM, Maurizio Cimadamore 
>>> <maurizio.cimadamore at oracle.com> wrote:
>>> 
>>> 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