/* gcc -o nvidia-glx-vm-leak nvidia-glx-vm-leak.c -L/usr/X11R6/lib -lX11 */ #define _ISOC99_SOURCE 1 #include #include #include #include #include #define GL_NAME "libGL.so.1" static void *glhandle = NULL; static GLXContext (*dynglXCreateContext)(Display *, XVisualInfo *, GLXContext, Bool) = NULL; static void (*dynglXDestroyContext)(Display *, GLXContext) = NULL; static XVisualInfo *(*dynglXChooseVisual)(Display *, int, int *) = NULL; static int load_dyn_gl(const char *); static void close_dyn_gl(void); int main(int argc, char *argv[]) { Display *dpy; XVisualInfo *visual; GLXContext glxctx; FILE *fd; char buf[512]; int screen, x; long vmsize; int attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None }; if (!(dpy = XOpenDisplay(NULL))) { fprintf(stderr, "XOpenDisplay() failed\n"); return 1; } screen = DefaultScreen(dpy); for (x = 0; x < 100; x++) { printf("Iteration %d:\n", x); if (load_dyn_gl(GL_NAME) < 0) { fprintf(stderr, "failed to load GL library\n"); XCloseDisplay(dpy); return 1; } if (!(visual = dynglXChooseVisual(dpy, screen, attribs))) { fprintf(stderr, "dynglXChooseVisual() failed\n"); close_dyn_gl(); XCloseDisplay(dpy); return 1; } if (!(glxctx = dynglXCreateContext(dpy, visual, NULL, True))) { fprintf(stderr, "dynglXCreateContext() failed\n"); /* * n.b. we'll likely crash here if we couldn't create the * context because we're out of VM (XCloseDisplay allocates) */ close_dyn_gl(); XCloseDisplay(dpy); return 1; } /* bleh. */ snprintf(buf, sizeof(buf), "/proc/%d/stat", getpid()); if ((fd = fopen(buf, "r")) != NULL) { if (fscanf(fd, "%*d %*s %*s %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %ld %*s\n", &vmsize) < 1) vmsize = -1; fclose(fd); } printf("\tContext created; VM usage: %.1fMiB\n", (float)vmsize / (1024.0 * 1024.0)); dynglXDestroyContext(dpy, glxctx); close_dyn_gl(); } XCloseDisplay(dpy); return 0; } static int load_dyn_gl(const char *fn) { char *err; if (!(glhandle = dlopen(fn, RTLD_LAZY))) { fprintf(stderr, "dlopen(): %s\n", dlerror()); return -1; } /* * ISO C says we need to cast dlsym from void *, but this is just * a proof-of-concept anyway, and I'm lazy. */ dynglXCreateContext = dlsym(glhandle, "glXCreateContext"); dynglXDestroyContext = dlsym(glhandle, "glXDestroyContext"); dynglXChooseVisual = dlsym(glhandle, "glXChooseVisual"); if ((err = dlerror()) != NULL) { fprintf(stderr, "dlsym(): %s\n", err); return -2; } return 0; } static void close_dyn_gl(void) { if (glhandle) dlclose(glhandle); dynglXCreateContext = NULL; dynglXDestroyContext = NULL; dynglXChooseVisual = NULL; }