Bug 27542 - Windows: stack push/pop mismatch calling NoOpGeneric
Summary: Windows: stack push/pop mismatch calling NoOpGeneric
Status: RESOLVED MOVED
Alias: None
Product: Mesa
Classification: Unclassified
Component: Mesa core (show other bugs)
Version: 7.8
Hardware: x86-64 (AMD64) Windows (All)
: medium normal
Assignee: Kristian Høgsberg
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-04-08 14:01 UTC by Nicolas Coderre
Modified: 2019-09-18 20:22 UTC (History)
0 users

See Also:
i915 platform:
i915 features:


Attachments

Description Nicolas Coderre 2010-04-08 14:01:25 UTC
2010/4/7 Nicolas Coderre <nicolas.coderre@gmail.com>:
> Hello Kristian,

Hi Nicolas,

> I've just upgraded from Mesa 7.3 to version 7.8.1, and I'm having some
> issues on shutdown.
>
> I'm using Ogre v 1.6.4, and it has the nasty habit of calling some gl
> functions after the glcontext has been released. I know this is a bad
> API usage, but it seems that the above change replaced a benign noop
> function call with a bad stack corruption issue. The NoOpGeneric
> function doesn't pop the stack correctly.

Haven't heard of this one before now.  What do you mean it doesn't pop
the stack correctly?  Can you open a bug in bugs.freedesktop.org
assign it to me and attach a stack trace?

thanks,
Kristian

Popping the stack correctly: I should clarify.
Based on my debug run, I have observed in this piece of code in glapitemp.h:

KEYWORD1 void KEYWORD2 NAME(DeleteTextures)(GLsizei n, const GLuint * textures)
{
   DISPATCH(DeleteTextures, (n, textures), (F, "glDeleteTextures(%d, %p);\n", n, (const void *) textures));
}

The code pushes two arguments on the stack, then calls the function as specified in the function table. In this particular situation, the glcontext is closed, so the function table is pointing to NoOpGeneric.
NoOpGeneric takes no arguments, therefore fails to pop the 2 pushed arguments from the stack. 
On return of this function, I get a runtime warning that my stack is bad.

I can give more information if required.


Repro should be:
build mesa non-debug ( so that TABLE_ENTRY(name) is defined as NoOpGeneric)
init gl, shutdown glcontext, then call glDeleteTextures(1, &ptr);
Comment 1 Kristian Høgsberg 2010-04-08 17:39:18 UTC
What platform and hw is this happening on?
Comment 2 Nicolas Coderre 2010-04-08 18:53:38 UTC
(In reply to comment #1)
> What platform and hw is this happening on?

x86 64bit and windows Vista
Compiled with VisualStudio 2008
Comment 3 Nicolas Coderre 2010-04-08 19:15:11 UTC
(In reply to comment #2)
> (In reply to comment #1)
> > What platform and hw is this happening on?
> 
> x86 64bit and windows Vista
> Compiled with VisualStudio 2008

Let me be real specific here. I'm running on 64bit os, but I'm compiling and running all in 32bit.
Comment 4 dave 2010-11-07 07:01:23 UTC
I ran into a similar problem using Qt 4.6.1 (From Nokia formerly Trolltech)

When Qt is initializing their OpenGL class, they have code that looks like this:


static bool opengl32dll = false;

. . .

void QGLContext::reset()
{
    Q_D(QGLContext);
    // workaround for matrox driver:
    // make a cheap call to opengl to force loading of DLL
    if (!opengl32dll) {
        GLint params;
        glGetIntegerv(GL_DEPTH_BITS, &params);
        opengl32dll = true;
    }

Well, that cheap call to glGetIntegerv really calls:

static int
NoOpGeneric(void)


Visual Studio 2008 does a poor job of producing a stack trace when a return statement is issued and the stack is not correct...

The call statement below will be the first call to the opengl32.dll

        GLint params;
        glGetIntegerv(GL_DEPTH_BITS, &params);
6308342F  lea         ecx,[params] 
63083432  push        ecx  
63083433  push        0D56h 
63083438  call        dword ptr [__imp__glGetIntegerv@8 (630F2720h)] 


This is the assembly code of the dispatch to glGetIntegerv:
It pushes 2 parameters for the call at 1007D887

1007D870  push        ebp  
1007D871  mov         ebp,esp 
1007D873  mov         eax,dword ptr [ebp+0Ch] 
1007D876  push        eax  
1007D877  mov         ecx,dword ptr [ebp+8] 
1007D87A  push        ecx  
1007D87B  mov         edx,dword ptr ds:[1025A7F0h] 
1007D881  mov         eax,dword ptr [edx+41Ch] 
1007D887  call        eax  
1007D889  pop         ebp  
1007D88A  ret         8    


The call eax above call this: (Takes No parameters)

static int
NoOpGeneric(void)
{
#if !defined(_WIN32_WCE)
   if (getenv("MESA_DEBUG") || getenv("LIBGL_DEBUG")) {
      fprintf(stderr, "GL User Error: calling GL function without a rendering context\n");
   }
#endif
   return 0;
}


This is the assembly of the above:


10172670  push        ebp  
10172671  mov         ebp,esp 
10172673  push        1020C410h 
10172678  call        dword ptr ds:[10206108h] 
1017267E  add         esp,4 
10172681  test        eax,eax 
10172683  jne         10172697 
10172685  push        10244610h 
1017268A  call        dword ptr ds:[10206108h] 
10172690  add         esp,4 
10172693  test        eax,eax 
10172695  je          101726AF 
10172697  push        102445D0h 
1017269C  call        dword ptr ds:[102060DCh] 
101726A2  add         eax,40h 
101726A5  push        eax  
101726A6  call        dword ptr ds:[102060D8h] 
101726AC  add         esp,8 
101726AF  xor         eax,eax 
101726B1  pop         ebp  
101726B2  ret              

In the debugger, I make 2 calls to getenv, then skip the call to fprintf
Notice the return(0) at the bottom, the ret instruction has no parameters meaning is doesn't pop the two parameters passed in - even though the caller pushed 2 parameters.

We return to here (see the assembly code of the dispatch to glGetIntegerv above)

1007D889  pop         ebp  
1007D88A  ret         8    

Executing the above return statement takes you to "someplace else", not the instruction after the call at 63083438 (first batch of assembly above)

Here is where I ended up - some random address which happened to contain some executable code which crashes right away.

0027C2CC  int         3    
0027C2CD  aamb        2Eh  
0027C2CF  push        es   
0027C2D0  adc         ch,dl 
0027C2D2  push        es   

Continuing from this point crashes the app and Visual Studio reports the stack trace incorrectly!
Comment 5 dave 2010-11-07 07:05:19 UTC
This happens with 7.8.2.

I tried building 7.9 on Windows, but the Visual Studio solution files for some of the modules are out of date and it doesn't build.
Comment 6 dave 2010-11-07 07:10:53 UTC
Workaround: (In my Qt code that creates my first OpenGL Window)

    //Mesa3D workaround... call glutCreateWindow prior to any Qt OpenGL calls
        glutInitWindowSize(300, 300);
        static char *str = {"foo"};
        int argc=1;
        glutInit(&argc, &str);
        glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
        int win = glutCreateWindow("Gears");
        qDebug() << "glut win: " << win;
    //.. end Mesa3D workaround

        widget = new QGLWidget(format);
	widget->makeCurrent();

Possible solution:

  Have multiple versions of NoOp which take different parameters that match the intended API.
Comment 7 GitLab Migration User 2019-09-18 20:22:08 UTC
-- GitLab Migration Automatic Message --

This bug has been migrated to freedesktop.org's GitLab instance and has been closed from further activity.

You can subscribe and participate further through the new bug through this link to our GitLab instance: https://gitlab.freedesktop.org/mesa/mesa/issues/961.


Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.