Uncatchable crash with zero-size VBO

Started by Morin, June 22, 2013, 06:29:59

Previous topic - Next topic

Morin

Hi,

when trying to get started with VBOs, I made the same mistake that many probably made: I forgot to rewind the NIO buffer before passing it to glBufferData(). If my understanding of how these buffers are used by LWJGL is correct, this caused the VBO to be initialized with zero-sized data (the buffer pointer was at the end of the buffer). So it seems clear to me that I cannot properly draw primitives using such a buffer.

What does *not* seem right to me is that, when I try it anyway, LWJGL crashes so hard that not even a "catch (Throwable e)" can handle it. I would have expected either an IndexOutOfBoundsException or, if that condition is too hard to detect with reasonable performance, incorrect rendering output.

Side note: Please ignore the fact that the comments talk about quads but I'm rendering triangles, and not even meaningful ones. This is not about why the output is garbled, but about the uncatchable crash.

----- machine -----
Mac Mini
Mac OS X 10.6.8 (Snow Leopard)
Java 6
LWJGL 2.9.0

----- code -----

import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
import static org.lwjgl.opengl.GL11.GL_INT;
import static org.lwjgl.opengl.GL11.GL_MODELVIEW;
import static org.lwjgl.opengl.GL11.GL_PROJECTION;
import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
import static org.lwjgl.opengl.GL11.GL_VERTEX_ARRAY;
import static org.lwjgl.opengl.GL11.glClear;
import static org.lwjgl.opengl.GL11.glClearColor;
import static org.lwjgl.opengl.GL11.glDepthMask;
import static org.lwjgl.opengl.GL11.glDrawArrays;
import static org.lwjgl.opengl.GL11.glEnableClientState;
import static org.lwjgl.opengl.GL11.glFlush;
import static org.lwjgl.opengl.GL11.glLoadIdentity;
import static org.lwjgl.opengl.GL11.glMatrixMode;
import static org.lwjgl.opengl.GL11.glScalef;
import static org.lwjgl.opengl.GL11.glVertexPointer;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glGenBuffers;

import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;

/**
*
*/
public class VertexBufferBug {

   /**
    * The main method.
    * @param args command-line arguments (ignored)
    */
   public static void main(final String[] args) {
      try {

         // native library loading
         System.setProperty("java.library.path", "lib/native/macosx");
         final Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
         fieldSysPath.setAccessible(true);
         fieldSysPath.set(null, null);

         // initialize LWJGL
         Display.setDisplayMode(new DisplayMode(640, 480));
         Display.create();
         Mouse.create();
         Mouse.setGrabbed(true);
         Mouse.poll();
         Keyboard.create();

         // initialize OpenGL
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         
         // clear screen
         glDepthMask(true);
         glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         
         // prepare data (24 quads, 4 vertices each, 2 floats each, 4 bytes each)
         final IntBuffer buffer = ByteBuffer.allocateDirect(24 * 4 * 2 * 4).order(ByteOrder.nativeOrder()).asIntBuffer();
         for (int i = 0; i < 6; i++) {
            for (int j = 0; j < 4; j++) {
               buffer.put(2 * i);
               buffer.put(2 * j);
               buffer.put(2 * i + 1);
               buffer.put(2 * j);
               buffer.put(2 * i + 1);
               buffer.put(2 * j + 1);
               buffer.put(2 * i);
               buffer.put(2 * j + 1);
            }
         }
         
         // prepare OpenGL buffer
         int arrayBufferName = glGenBuffers();
         glBindBuffer(GL_ARRAY_BUFFER, arrayBufferName);
         buffer.rewind(); // <-- forget this and it crashes!
         glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);

         // set up OpenGL state
         glScalef(0.25f, 1.0f / 3.0f, 1.0f);
         glVertexPointer(2, GL_INT, 0, 0);
         glEnableClientState(GL_VERTEX_ARRAY);

         // draw the frame
         glDrawArrays(GL_TRIANGLES, 0, 24 * 4);
         glFlush();
         Display.swapBuffers();
         
         // wait for keypress
         while (!Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
            Keyboard.poll();
         }

         // clean up
         Keyboard.destroy();
         Mouse.destroy();
         Display.destroy();

      } catch (Throwable e) {
         System.err.println("got an exception");
         throw new RuntimeException(e);
      }
   }

}


----- console output when crashing -----

[LWJGL] Failed to load 64 bit library: no lwjgl64 in java.library.path
[LWJGL] Initial mode: 1680 x 1050 x 32 @60Hz
[LWJGL] MemoryUtil Accessor: AccessorUnsafe
Could not locate symbol glGetStringi
Could not locate symbol glClientAttribDefaultEXT
Could not locate symbol glPushClientAttribDefaultEXT
Could not locate symbol glMatrixLoadfEXT
Could not locate symbol glMatrixLoaddEXT
Could not locate symbol glMatrixMultfEXT
Could not locate symbol glMatrixMultdEXT
Could not locate symbol glMatrixLoadIdentityEXT
Could not locate symbol glMatrixRotatefEXT
Could not locate symbol glMatrixRotatedEXT
Could not locate symbol glMatrixScalefEXT
Could not locate symbol glMatrixScaledEXT
Could not locate symbol glMatrixTranslatefEXT
Could not locate symbol glMatrixTranslatedEXT
Could not locate symbol glMatrixOrthoEXT
Could not locate symbol glMatrixFrustumEXT
Could not locate symbol glMatrixPushEXT
Could not locate symbol glMatrixPopEXT
Could not locate symbol glTextureParameteriEXT
Could not locate symbol glTextureParameterivEXT
Could not locate symbol glTextureParameterfEXT
Could not locate symbol glTextureParameterfvEXT
Could not locate symbol glTextureImage1DEXT
Could not locate symbol glTextureImage2DEXT
Could not locate symbol glTextureSubImage1DEXT
Could not locate symbol glTextureSubImage2DEXT
Could not locate symbol glCopyTextureImage1DEXT
Could not locate symbol glCopyTextureImage2DEXT
Could not locate symbol glCopyTextureSubImage1DEXT
Could not locate symbol glCopyTextureSubImage2DEXT
Could not locate symbol glGetTextureImageEXT
Could not locate symbol glGetTextureParameterfvEXT
Could not locate symbol glGetTextureParameterivEXT
Could not locate symbol glGetTextureLevelParameterfvEXT
Could not locate symbol glGetTextureLevelParameterivEXT
Could not locate symbol glTextureImage3DEXT
Could not locate symbol glTextureSubImage3DEXT
Could not locate symbol glCopyTextureSubImage3DEXT
Could not locate symbol glBindMultiTextureEXT
Could not locate symbol glMultiTexCoordPointerEXT
Could not locate symbol glMultiTexEnvfEXT
Could not locate symbol glMultiTexEnvfvEXT
Could not locate symbol glMultiTexEnviEXT
Could not locate symbol glMultiTexEnvivEXT
Could not locate symbol glMultiTexGendEXT
Could not locate symbol glMultiTexGendvEXT
Could not locate symbol glMultiTexGenfEXT
Could not locate symbol glMultiTexGenfvEXT
Could not locate symbol glMultiTexGeniEXT
Could not locate symbol glMultiTexGenivEXT
Could not locate symbol glGetMultiTexEnvfvEXT
Could not locate symbol glGetMultiTexEnvivEXT
Could not locate symbol glGetMultiTexGendvEXT
Could not locate symbol glGetMultiTexGenfvEXT
Could not locate symbol glGetMultiTexGenivEXT
Could not locate symbol glMultiTexParameteriEXT
Could not locate symbol glMultiTexParameterivEXT
Could not locate symbol glMultiTexParameterfEXT
Could not locate symbol glMultiTexParameterfvEXT
Could not locate symbol glMultiTexImage1DEXT
Could not locate symbol glMultiTexImage2DEXT
Could not locate symbol glMultiTexSubImage1DEXT
Could not locate symbol glMultiTexSubImage2DEXT
Could not locate symbol glCopyMultiTexImage1DEXT
Could not locate symbol glCopyMultiTexImage2DEXT
Could not locate symbol glCopyMultiTexSubImage1DEXT
Could not locate symbol glCopyMultiTexSubImage2DEXT
Could not locate symbol glGetMultiTexImageEXT
Could not locate symbol glGetMultiTexParameterfvEXT
Could not locate symbol glGetMultiTexParameterivEXT
Could not locate symbol glGetMultiTexLevelParameterfvEXT
Could not locate symbol glGetMultiTexLevelParameterivEXT
Could not locate symbol glMultiTexImage3DEXT
Could not locate symbol glMultiTexSubImage3DEXT
Could not locate symbol glCopyMultiTexSubImage3DEXT
Could not locate symbol glEnableClientStateIndexedEXT
Could not locate symbol glDisableClientStateIndexedEXT
Could not locate symbol glGetFloatIndexedvEXT
Could not locate symbol glGetDoubleIndexedvEXT
Could not locate symbol glGetPointerIndexedvEXT
Could not locate symbol glNamedProgramStringEXT
Could not locate symbol glNamedProgramLocalParameter4dEXT
Could not locate symbol glNamedProgramLocalParameter4dvEXT
Could not locate symbol glNamedProgramLocalParameter4fEXT
Could not locate symbol glNamedProgramLocalParameter4fvEXT
Could not locate symbol glGetNamedProgramLocalParameterdvEXT
Could not locate symbol glGetNamedProgramLocalParameterfvEXT
Could not locate symbol glGetNamedProgramivEXT
Could not locate symbol glGetNamedProgramStringEXT
Could not locate symbol glCompressedTextureImage3DEXT
Could not locate symbol glCompressedTextureImage2DEXT
Could not locate symbol glCompressedTextureImage1DEXT
Could not locate symbol glCompressedTextureSubImage3DEXT
Could not locate symbol glCompressedTextureSubImage2DEXT
Could not locate symbol glCompressedTextureSubImage1DEXT
Could not locate symbol glGetCompressedTextureImageEXT
Could not locate symbol glCompressedMultiTexImage3DEXT
Could not locate symbol glCompressedMultiTexImage2DEXT
Could not locate symbol glCompressedMultiTexImage1DEXT
Could not locate symbol glCompressedMultiTexSubImage3DEXT
Could not locate symbol glCompressedMultiTexSubImage2DEXT
Could not locate symbol glCompressedMultiTexSubImage1DEXT
Could not locate symbol glGetCompressedMultiTexImageEXT
Could not locate symbol glMatrixLoadTransposefEXT
Could not locate symbol glMatrixLoadTransposedEXT
Could not locate symbol glMatrixMultTransposefEXT
Could not locate symbol glMatrixMultTransposedEXT
Could not locate symbol glNamedBufferDataEXT
Could not locate symbol glNamedBufferSubDataEXT
Could not locate symbol glMapNamedBufferEXT
Could not locate symbol glUnmapNamedBufferEXT
Could not locate symbol glGetNamedBufferParameterivEXT
Could not locate symbol glGetNamedBufferPointervEXT
Could not locate symbol glGetNamedBufferSubDataEXT
Could not locate symbol glProgramUniform1fEXT
Could not locate symbol glProgramUniform2fEXT
Could not locate symbol glProgramUniform3fEXT
Could not locate symbol glProgramUniform4fEXT
Could not locate symbol glProgramUniform1iEXT
Could not locate symbol glProgramUniform2iEXT
Could not locate symbol glProgramUniform3iEXT
Could not locate symbol glProgramUniform4iEXT
Could not locate symbol glProgramUniform1fvEXT
Could not locate symbol glProgramUniform2fvEXT
Could not locate symbol glProgramUniform3fvEXT
Could not locate symbol glProgramUniform4fvEXT
Could not locate symbol glProgramUniform1ivEXT
Could not locate symbol glProgramUniform2ivEXT
Could not locate symbol glProgramUniform3ivEXT
Could not locate symbol glProgramUniform4ivEXT
Could not locate symbol glProgramUniformMatrix2fvEXT
Could not locate symbol glProgramUniformMatrix3fvEXT
Could not locate symbol glProgramUniformMatrix4fvEXT
Could not locate symbol glProgramUniformMatrix2x3fvEXT
Could not locate symbol glProgramUniformMatrix3x2fvEXT
Could not locate symbol glProgramUniformMatrix2x4fvEXT
Could not locate symbol glProgramUniformMatrix4x2fvEXT
Could not locate symbol glProgramUniformMatrix3x4fvEXT
Could not locate symbol glProgramUniformMatrix4x3fvEXT
Could not locate symbol glTextureParameterIivEXT
Could not locate symbol glTextureParameterIuivEXT
Could not locate symbol glGetTextureParameterIivEXT
Could not locate symbol glGetTextureParameterIuivEXT
Could not locate symbol glMultiTexParameterIivEXT
Could not locate symbol glMultiTexParameterIuivEXT
Could not locate symbol glGetMultiTexParameterIivEXT
Could not locate symbol glGetMultiTexParameterIuivEXT
Could not locate symbol glProgramUniform1uiEXT
Could not locate symbol glProgramUniform2uiEXT
Could not locate symbol glProgramUniform3uiEXT
Could not locate symbol glProgramUniform4uiEXT
Could not locate symbol glProgramUniform1uivEXT
Could not locate symbol glProgramUniform2uivEXT
Could not locate symbol glProgramUniform3uivEXT
Could not locate symbol glProgramUniform4uivEXT
Could not locate symbol glNamedProgramLocalParameters4fvEXT
Could not locate symbol glNamedRenderbufferStorageEXT
Could not locate symbol glGetNamedRenderbufferParameterivEXT
Could not locate symbol glNamedRenderbufferStorageMultisampleEXT
Could not locate symbol glCheckNamedFramebufferStatusEXT
Could not locate symbol glNamedFramebufferTexture1DEXT
Could not locate symbol glNamedFramebufferTexture2DEXT
Could not locate symbol glNamedFramebufferTexture3DEXT
Could not locate symbol glNamedFramebufferRenderbufferEXT
Could not locate symbol glGetNamedFramebufferAttachmentParameterivEXT
Could not locate symbol glGenerateTextureMipmapEXT
Could not locate symbol glGenerateMultiTexMipmapEXT
Could not locate symbol glFramebufferDrawBufferEXT
Could not locate symbol glFramebufferDrawBuffersEXT
Could not locate symbol glFramebufferReadBufferEXT
Could not locate symbol glGetFramebufferParameterivEXT
Could not locate symbol glNamedFramebufferTextureEXT
Could not locate symbol glNamedFramebufferTextureLayerEXT
Could not locate symbol glNamedFramebufferTextureFaceEXT
[LWJGL] GL_EXT_direct_state_access was reported as available but an entry point is missing
Could not locate symbol glPrimitiveRestartNV
Could not locate symbol glPrimitiveRestartIndexNV
[LWJGL] GL_NV_primitive_restart was reported as available but an entry point is missing
Invalid memory access of location 0x0 rip=0x11c354685


Cornix

Did you even read the message?
Your program clearly didnt crash because of any buffers or wrong parameters. It can not find the native library:
QuoteFailed to load 64 bit library: no lwjgl64 in java.library.path
The very first line should make the problem pretty obvious.

Morin

Quote from: Cornix on June 22, 2013, 08:22:38
Did you even read the message?
Your program clearly didnt crash because of any buffers or wrong parameters. It can not find the native library:
QuoteFailed to load 64 bit library: no lwjgl64 in java.library.path
The very first line should make the problem pretty obvious.

Thanks for your reply. However, I was under the assumption that the native library was needed for *all* OpenGL operations and not just for zero-sized buffers (a pathological case anyway) -- Please remember that it works perfectly fine when I *do* rewind the NIO buffer. So the message that the native library could not be loaded did not make sense to me, and I rather explained the whole problem here than making assumptions.

Possibly related: I made another mistake when using glDrawArrays() -- I specified the number of floats, not the number of vertices, so the "count" argument was three times as large as would have been correct. This wrong count, however, caused funny screen artifacts *OUTSIDE* the OpenGL window (a growing and shrinking black area at the bottom of the screen). It also interfered with the system in a way that prevented me from switching away from my application (I had to turn off the computer). To sidestep the problem for my experiments, I used a kind of "dead man's switch" -- a shell script that kills (-9) the application after ten seconds. This did end the artifacts at the end of those ten seconds, but I still could not interact with the system's UI, and a few seconds later a got a kernel panic.

spasi

Ignore the "failed to load library" message, it's unrelated to the problem and expected when the LWJGL debug mode is enabled.

The behavior you're seeing is entirely implementation dependent. It all comes down to how much validation the OpenGL drivers does before rendering anything. On my setup (Windows + AMD GPU) I simply get an OUT_OF_MEMORY OpenGL error, when running your code without the rewind().

LWJGL does not perform any non-trivial checks when you call GL functions. Especially for DrawArrays (and other DrawX calls), validating state would be very complicated and expensive. At some point we had tried adding a simple 0-size buffer check (I agree that it's a very common source of user-error), but some users thought it was the wrong thing to do, since a 0-size VBO is valid state. So it was removed.

Keep in mind that LWJGL is a low-level library with simple bindings to the underlying C calls. State monitoring and validation is the job of engines built on top of LWJGL.

Morin

Thanks a lot. I'll have to be careful then.

Does anybody have a hint on how to implement a "dead man's switch" or similar to prevent crashing the OS? This is probably system-dependent, so as mentioned above I'm using Mac OS X 10.6. This is meant only for my setup so I don't have to reboot during some quick experiments.

spasi

There's an LWJGL user that has been working on code that guards against DrawArrays/DrawArraysInstanced/etc bugs/crashes and the plan is to add it to the LWJGL 3.0 utility package when it's ready. I could back-port it to 2.x if it turns out to be as useful as it sounds. Sadly, it will take a few months for this tool to be ready, so you may want to roll your own until then. You should be able to cover the most common cases without too much trouble.

Morin

Do you know if that package intercepts bad glDrawArrays() calls, or if it's "just" a bunch of utility classes that make sure only correct glDrawArrays() calls are issued? I'm asking because I already rolled my own buffer management classes, so it would indeed be easy to add  checks to that.

spasi

I haven't seen the code but I'm guessing it's something you call before DrawArrays to validate the current state and get an exception if something's wrong.