A bug in the 1.4.1_01 server vm!

Hurrah! I’ve always wanted to find one of these.

The following:


            int buttonFlags = (Mouse.isButtonDown(0) ? 1 : 0) |
                  (Mouse.isButtonDown(1) ? 2 : 0) |
                  (Mouse.isButtonDown(2) ? 4 : 0);
            
            assert buttonFlags >= 0;

produces an assertion error in the server VM (1.4.1_01, Win32, WinXP). The client VM is unaffected. Naughty naughty, as it is indeed impossible for that assertion to be thrown.

So, back to using the client VM then…

Cas :slight_smile:

By the way, what is the actual value buttonFlags has in each VM?

In other words? is this an assertion bug? or something really funny in the the way the server VM handles bit ORing.

Seb

Cool, what’s the value of buttonFlags when the assert fails?

Never mind, I just read your diary ;D

Seb

Something like -126 or -128. Most bizarre. Of course, when I try to chop it out and make a test case it won’t happen, but it happens without fail when I run the game. Ah well.

Cas :slight_smile:

In this case it looks more like the bug is somewhere else and appears just there by accident? Is it with LWJGL? Well, there’s plenty of native code in it…

Naaa, if you follow through the code path, the result should be in the range 0-7. The method that’s executing to provide the boolean test has no direct effect on the value of buttonFlags. If that line of code comes out with a value outside the range 0-7, there’s something decidedly fishy going on.

It’s definitely Hotspot. I had suspected the stack corruption was my fault somehow in the native libs but it doesn’t occur in client and doesn’t occur in server for quite some time. In fact, it takes about as much time as server does to think about doing a compile. And besides, a stack corruption is always followed by a crash, and this doesn’t crash, it just has a bizarre value in it at the end.

Cas :slight_smile:

No, it’s still the lwjgl lib’s fault!

At least that’s what I found out after running into a similar problem, namely the test

if (Mouse.isButtonDown(i) == buttons[i])

Sometimes (only on the win32 build of lwjgl) the Mouse.isButtonDown(i) and buttons[i] would both be true when I printed them, but the test actually failed!

To understand why, you have to look at the code that polls the mouse under win32:

            jbooleanArray buttonsArray = (jbooleanArray) env->GetStaticObjectField(clazz, fid_button);
            BYTE * buttons = (BYTE *) env->GetPrimitiveArrayCritical(buttonsArray, NULL);
            memcpy(buttons, diMouseState.rgbButtons, 4);
            env->ReleasePrimitiveArrayCritical(buttonsArray, buttons, 0);

Other than the fact that I think SetBooleanArrayRegion() should be used instead of GetPrimitiveArrayCritical/ReleasePrimitiveArrayCritical, there’s a problem with that code. diMouseState.rgbButtons contains the mouse button states as returned by DirectInput in an array of BYTEs, which corresponds to the jboolean datatype the java button array buttons contains. The problem is that directinput does not always return JNI_TRUE or JNI_FALSE, the only two values allowed to be in a jboolean data type! This is what makes the assumptions made by the VMs invalid (an == test between two jbooleans could fail in this case).

I fixed this in lwjgl CVS by setting the button array entries to JNI_TRUE if DirectInput returned something != 0, and JNI_FALSE otherwise. This makes the test first mentioned always do the right thing.

  • elias

Heh :slight_smile: It may be us that causes it but there seems to be a bit of a grey area in the spec doesn’t there? It works fine under the client VM, but it looks like the server VM relies on a more accurate representation of JNI_TRUE :slight_smile:

Interesting that this technically means we could compare a Java boolean value and have it both != false and != true :slight_smile:

Thanks for spotting it.

Cas :slight_smile:

You’re right - I can’t find that jbooleans have to be JNI_TRUE or JNI_FALSE either. But it’s clearly what the JNI API expects :slight_smile:

  • elias

;D

How could I know it was the native code…?

BTW, did you ever try -Xcheck:jni ??

For JXInput, this fails for some reason I never could find out…

-Xcheck:jni - never used it but I’ve heard of it before

And yes, it complains about lwjgl too, I’ll look into that.

  • elias

Hmm the -Xcheck:jni option makes a call to Mouse.poll puke with:

FATAL ERROR in native method: Field type (static) mismatch in JNI get/set field operations
at org.lwjgl.input.Mouse.nPoll(Native Method)
at org.lwjgl.input.Mouse.poll(Mouse.java:148)

Coming from a call in nPoll like this:
jbooleanArray buttonsArray = (jbooleanArray) env->GetStaticObjectField(clazz, fid_button);

I can’t really understand this. The fid_button id is fetched correctly with

fid_button = env->GetStaticFieldID(clazz, “button”, “[Z”);

And as there’s is no GetStaticArrayField, GetStaticObjectField seems like the correct way to get an array field, like String objects are fetched.

Someone?

  • elias

That’s what it complains about for me:


FATAL ERROR in native method: Field type (static) mismatch in JNI get/set field operations
   at de.hardcode.jxinput.directinput.DirectInputDriver.nativeupdate(Native
 Method)