title: OpenGL crashes at glTexImage2D(...)
body: <p>I wrote an image viewer in OpenGL (+GLEW and GLFW) to learn how to handle textures etc. but the program keeps crashing when I feed it certain jpeg files (most of them work). I tried using SOIL, libjpeg and jpgd, but it crashes anyway so it's not the decompressor's fault.</p>
  
  <p>I checked (using output_* jpg decompressor variables) the file data after decompressing it (height, width, channels) and they are correct. I also dumped both of them to .raw file and opened them in Photoshop and they load without any problems (though I had to enter number of channels, dimensions and check interleaved). It's not a problem with the size because 3000x2800 jpg loads normally and 667x1111 crashes OpenGL. Comparing color hex values and file loaded in hex editor gave the same result in both cases - it's a pure RGB 8 bits per channel image data.</p>
  
  <p>Here's my jpeg decompressin code (byte is just an unsigned int):</p>
  
  <pre><code>inline bool loadTexture(byte *&amp;texture, const char *fName, int &amp;width, int &amp;height, int &amp;actualComp, int reqComp)
  {
      texture = decompressJpeg(fName, width, height, actualComp, reqComp);
      if(texture == nullptr)
      {
          std::cout&lt;&lt;"SOIL decoded\n";
          texture = SOIL_load_image(fName, &amp;width, &amp;height, &amp;actualComp, reqComp);
          if(texture == nullptr)
              return GL_FALSE;
      }
      return GL_TRUE;
  }
  
  unsigned char* decompressJpeg(const char *fName, int &amp;width, int &amp;height, int &amp;actualComp, int reqComp)
  {
      std::ifstream f(fName, std::ios::binary);
      if(!f.is_open())
          return nullptr;
      struct jpeg_decompress_struct cinfo;
      struct jpeg_error_mgr errManager;
      cinfo.err = jpeg_std_error(&amp;errManager);
      jpeg_create_decompress(&amp;cinfo);
  
      f.seekg(0, f.end);
      size_t length(f.tellg());
      f.seekg(0, f.beg);
      byte *data(new byte[length]);
      f.read((char*)data, length);
      f.close();
  
      jpeg_mem_src(&amp;cinfo, data, length);
      jpeg_read_header(&amp;cinfo, TRUE);
      cinfo.out_color_space = JCS_RGB;
  
      jpeg_start_decompress(&amp;cinfo);
  
      height = cinfo.output_height;
      width = cinfo.output_width;
      actualComp = cinfo.output_components;
      unsigned char **tempVal(new unsigned char*[cinfo.output_height]);
      for(int i(cinfo.output_height); i&gt;0; --i)
      {
          *tempVal = new unsigned char[cinfo.output_width*cinfo.output_components];
          ++tempVal;
      }
      tempVal -= cinfo.output_height;
  
      while(cinfo.output_height &gt; cinfo.output_scanline)
      {
          jpeg_read_scanlines(&amp;cinfo, tempVal, 1);
          ++tempVal;
      }
      tempVal -= cinfo.output_height;
  
      jpeg_finish_decompress(&amp;cinfo);
      delete[] data;
  
      unsigned char *retVal(new unsigned char[actualComp*height*width]);
      for(int i(height); i&gt;0; --i)
      {
          for(int j(width*actualComp); j&gt;0; --j)
          {
              *retVal = **tempVal;
              ++retVal;
              ++(*tempVal);
          }
          (*tempVal) -= width*actualComp;
          delete[] *tempVal;
          ++tempVal;
      }
      tempVal -= height;
      delete[] tempVal;
      jpeg_destroy_decompress(&amp;cinfo);
      retVal -= height*width*actualComp;
      return retVal;
  }
  </code></pre>
  
  <p>And here's the rest of the code:</p>
  
  <pre><code>#include &lt;glew.h&gt;
  #include &lt;glfw3.h&gt;
  #include &lt;SOIL.h&gt;
  #include &lt;iostream&gt;
  #include &lt;ctime&gt;
  #include &lt;conio.h&gt;
  #include &lt;fstream&gt;
  #include &lt;cmath&gt;
  #include &lt;jpeglib.h&gt;
  
  #define HEIGHT  1024
  #define WIDTH   1280
  
  typedef unsigned char byte;
  
  void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode);
  inline void writeErrLog(const GLchar *log);
  inline const bool loadShader(const GLuint shader, const char *sourceFile);
  inline bool loadTexture(byte *&amp;texture ,const char *fName, int &amp;width, int &amp;height, int &amp;actualComp, int reqComp);
  unsigned char* decompressJpeg(const char *fName, int &amp;width, int &amp;height, int &amp;actualComp, int reqComp);
  
  struct bitmap
  {
  public:
      bitmap() : width(0), height(0), data(nullptr) {}
      int width, height;
      byte *data;
  };
  
  std::string programPath;
  
  int main(int argc, char **argv)
  {
      if(argc&lt;2)
          return -1;
  
      programPath = *argv;
      programPath.erase(programPath.rfind('\\')+1);
  
      glfwInit();
      glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
      glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
      glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
      GLFWwindow *window(glfwCreateWindow(WIDTH, HEIGHT, "Okienko", nullptr, nullptr) );
      if(window == nullptr)
      {
          std::cout&lt;&lt;"Failed to create window\n\n";
          glfwTerminate();
          getch();
          return -1;
      }
      glfwMakeContextCurrent(window);
      glfwSetKeyCallback(window, key_callback);
  
      glewExperimental = GL_TRUE;
      if(glewInit() != GLEW_OK)
      {
          std::cout&lt;&lt;"Failed to initialize GLEW\n\n";
          glfwTerminate();
          getch();
          return -1;
      }
      glViewport(0, 0, WIDTH, HEIGHT);
  
      unsigned long long int frame_time(0);
  
      const GLuint    vertexShader(glCreateShader(GL_VERTEX_SHADER)),
              fragmentShader(glCreateShader(GL_FRAGMENT_SHADER)),
              shaderProgram(glCreateProgram());
      GLint   operationStatus;
  
      std::string shaderPath(programPath);
      shaderPath.append("shaders\\vertex shader.glsl");
      if(loadShader(vertexShader, shaderPath.c_str()) == GL_FALSE)
      {
          glfwTerminate();
          getch();
          return -1;
      }
      shaderPath = programPath;
      shaderPath.append("shaders\\fragment shader.glsl");
      if(loadShader(fragmentShader, shaderPath.c_str()) == GL_FALSE)
      {
          glfwTerminate();
          getch();
          return -1;
      }
      shaderPath.clear();
  
      glAttachShader(shaderProgram, vertexShader);
      glAttachShader(shaderProgram, fragmentShader);
      glLinkProgram(shaderProgram);
      glGetProgramiv(shaderProgram, GL_LINK_STATUS, &amp;operationStatus);
      if(operationStatus == 0)
      {
          GLchar log[2048];
          glGetProgramInfoLog(shaderProgram, 2048, nullptr, log);
          glfwTerminate();
          writeErrLog(log);
          return -1;
      }
      glDeleteShader(vertexShader);
      glDeleteShader(fragmentShader);
  
      bitmap texture;
      int comp;
      if(loadTexture(texture.data, *(argv+1), texture.width, texture.height, comp, 3) == GL_FALSE)
      {
          std::string errLog("Failed to read texture. (");
          errLog.append(*(argv+1));
          errLog.append(")");
          writeErrLog(errLog.c_str());
          errLog.clear();
      }
      std::cout&lt;&lt;"channels:\t"&lt;&lt;comp&lt;&lt;'\n';
  
      std::ofstream nam("image.raw", std::ios::binary);
      nam.write((char*)texture.data, texture.width*texture.height*comp);
      nam.close();
  
      //GLint inColorUni(glGetUniformLocation(shaderProgram, "inColor"));
      int newWidth, newHeight;
      if( (float(texture.width)/float(texture.height)) / (float(WIDTH)/float(HEIGHT)) &gt; 1.0f)
      {
          newWidth = std::min(texture.width, WIDTH);
          newHeight = round(float(newWidth) / (float(texture.width)/float(texture.height)));
      }
      else
      {
          newHeight = std::min(texture.height, HEIGHT);
          newWidth = round(float(newHeight) *     (float(texture.width)/float(texture.height)));
      }
      // normalize
      GLfloat x(GLfloat(newWidth)/GLfloat(WIDTH)*2.0f),
              y(GLfloat(newHeight)/GLfloat(HEIGHT)*2.0f);
  
      GLsizei vertices_len(20);
      GLfloat *vertices(new GLfloat[vertices_len]);
      GLfloat diffX((2.0f-x)/2.0f), diffY((2.0f-y)/2.0f);
  
      std::cout   &lt;&lt;"Resolution:\t"&lt;&lt;texture.width&lt;&lt;'x'&lt;&lt;texture.height&lt;&lt;"px"
                  &lt;&lt;"\nScaled:\t"&lt;&lt;newWidth&lt;&lt;'x'&lt;&lt;newHeight&lt;&lt;"px"
                  &lt;&lt;"\nNormalized:\t";
  
      *vertices = -1.0f+diffX;        //X
      *++vertices = 1.0f-diffY;       //Y
      *++vertices = 0.0f;     //Z
      *++vertices = 0.0f;     //S
      *++vertices = 1.0f;     //T
  
      *++vertices = -1.0f+diffX;  //X
      *++vertices = -1.0f+diffY;  //Y
      *++vertices = 0.0f;     //Z
      *++vertices = 0.0f;     //S
      *++vertices = 0.0f;     //T
  
      *++vertices = 1.0f-diffX;       //X
      *++vertices = -1.0f+diffY;  //Y
      *++vertices = 0.0f;     //Z
      *++vertices = 1.0f;     //S
      *++vertices = 0.0f;     //T
  
      *++vertices = 1.0f-diffX;       //X
      *++vertices = 1.0f-diffY;       //Y
      *++vertices = 0.0f;     //Z
      *++vertices = 1.0f;     //S
      *++vertices = 1.0f;     //T
      vertices -= vertices_len-1;
  
      GLsizei indices_len(6);
      GLuint *indices(new GLuint[indices_len]);
      *indices = 0;
      *++indices = 1;
      *++indices = 3;
      *++indices = 1;
      *++indices = 2;
      *++indices = 3;
      indices -= 5;
  
      GLsizei color_len(4);
      GLfloat *color(new GLfloat[color_len]);
      *color = 0.5f;
      *++color = 0.0f;
      *++color = 1.0f;
      *++color = 1.0f;
      color -= 3;
  
      GLuint triangleVBO, triangleObjectVAO, triangleEBO;
      glGenVertexArrays(1, &amp;triangleObjectVAO);
      glGenBuffers(1, &amp;triangleVBO);
      glGenBuffers(1, &amp;triangleEBO);
  
      glBindVertexArray(triangleObjectVAO);
  
      glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*vertices_len, vertices, GL_STATIC_DRAW);
  
      glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleEBO);
      glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*indices_len, indices, GL_STATIC_DRAW);
  
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)0);
      glEnableVertexAttribArray(0);
  
      glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)) );
      glEnableVertexAttribArray(1);
  
      glBindVertexArray(0);
  
      delete[] vertices;
      delete[] indices;
  
      #define OKRES 7000.0
      GLfloat timePoint(0.0f);
  
      glUseProgram(shaderProgram);
  
      GLuint tex;
      glGenTextures(1, &amp;tex);
      glBindTexture(GL_TEXTURE_2D, tex);
          glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture.width, texture.height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture.data);
          GLfloat bgColor[] = {0.0f, 0.0f, 0.0f, 0.0f};
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
          glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, bgColor);
          glGenerateMipmap(GL_TEXTURE_2D);
      glBindTexture(GL_TEXTURE_2D, 0);
      //SOIL_free_image_data(texture.data);
  
      while(!glfwWindowShouldClose(window))
      {
          glfwPollEvents();
  
          if(clock()-frame_time &gt; 16) /* max 60 fps */
          {
              glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
              glClear(GL_COLOR_BUFFER_BIT);
  
              /*timePoint += clock()-frame_time;
              if(timePoint&gt;OKRES)
                  timePoint -= OKRES;
              glUniform4f(inColorUni, 0.0f, 0.0f, sinf(3.1415926f * (timePoint/OKRES)), 1.0f);*/
  
              glBindTexture(GL_TEXTURE_2D, tex);
              glBindVertexArray(triangleObjectVAO);
  
              //glDrawArrays(GL_TRIANGLES, 0, 3);
  
              glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
              glBindVertexArray(0);
              glBindTexture(GL_TEXTURE_2D, 0);
  
              glfwSwapBuffers(window);
              frame_time = clock();
          }
      }
  
      glDeleteVertexArrays(1, &amp;triangleObjectVAO);
      glDeleteBuffers(1, &amp;triangleEBO);
      glDeleteBuffers(1, &amp;triangleVBO);
      glfwTerminate();
      return 0;
  }
  </code></pre>
  
  <p>Don't tell me how to optimize my code (except it's about handling an jpg, as it's just a kind of tutorial project. I didn't care about optimizations and stuff. I just want my jpeg to load and not crash the OpenGL.</p>
  
  <p>It crashes at</p>
  
  <pre><code>glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texture.width, texture.height, 0, GL_RGB, GL_UNSIGNED_BYTE, texture.data);
  </code></pre>
  
  <p>I think that shaders, key callback, loadShaders and writeErrLog are irrelevant since they are as basic as they can be (vertex shader actually does nothing, and fragment shader only uses texture() ) but I'll post them if needed. Also don't ask me why I assign vertices that way.</p>
  
  <p>Both of the tested jpegs don't seem to be progressive.
  It seems that I gave glTexImage2D() incorrect values. Could endianness cause it or something? (I don't know much about how to write endianness-safe code) Also, how does OGL determine if the given array is bad (other than size != channels x height x width)?</p>