{"record":{"id":"a6a9514dccf5760f","repo":"Yalantis/uCrop","slug":"cimgdisplay-assign-max-number-of-displays-512","errorCode":null,"errorMessage":"CImgDisplay::assign(): Max number of displays (512) already opened.","messagePattern":"CImgDisplay::assign\\(\\): Max number of displays \\(512\\) already opened\\.","errorType":"exception","errorClass":"CImgDisplayException","httpStatus":null,"severity":"error","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":10157,"sourceCode":"      }\n      if (!_shminfo)\n#endif\n        {\n          const cimg_ulong buf_size = (cimg_ulong)_width*_height*(X11_attr.nb_bits==8?1:\n                                                                  (X11_attr.nb_bits==16?2:4));\n          _data = std::malloc(buf_size);\n          _image = XCreateImage(dpy,DefaultVisual(dpy,DefaultScreen(dpy)),X11_attr.nb_bits,\n                                ZPixmap,0,(char*)_data,_width,_height,8,0);\n        }\n\n      _wm_window_atom = XInternAtom(dpy,\"WM_DELETE_WINDOW\",0);\n      _wm_protocol_atom = XInternAtom(dpy,\"WM_PROTOCOLS\",0);\n      XSetWMProtocols(dpy,_window,&_wm_window_atom,1);\n\n      if (_is_fullscreen) XGrabKeyboard(dpy,_window,1,GrabModeAsync,GrabModeAsync,CurrentTime);\n      if (X11_attr.nb_cimg_displays>=512) {\n        X11_attr.unlock();\n        throw CImgDisplayException(\"CImgDisplay::assign(): Max number of displays (512) already opened.\");\n      }\n      X11_attr.cimg_displays[X11_attr.nb_cimg_displays++] = this;\n      if (!_is_closed) _map_window(); else _window_x = _window_y = cimg::type<int>::min();\n      X11_attr.unlock();\n      cimg::mutex(14,0);\n    }\n\n    static int _assign_xshm(Display *dpy, XErrorEvent *error) {\n      cimg::unused(dpy,error);\n      cimg::X11_attr &X11_attr = cimg::X11_attr::ref();\n      X11_attr.is_shm_enabled = false;\n      return 0;\n    }\n\n    void _desinit_fullscreen() {\n      if (!_is_fullscreen) return;\n      cimg::X11_attr &X11_attr = cimg::X11_attr::ref();\n      Display *const dpy = X11_attr.display;","sourceCodeStart":10139,"sourceCodeEnd":10175,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L10139-L10175","documentation":"CImg tracks open CImgDisplay instances in a fixed table of 512 slots (X11_attr.cimg_displays). When assign() runs and nb_cimg_displays has already reached 512, it throws CImgDisplayException because no more displays can be registered. This almost always means displays were created but never closed, leaking the table.","triggerScenarios":"Opening more than 512 CImgDisplay objects without calling close()/the destructor — e.g. creating a new CImgDisplay per image/frame in a loop while only destroying some, or long-running apps that keep accumulating display objects.","commonSituations":"Image-viewer loops that spawn a window per image and rely on GC; event loops recreating displays each iteration; tools processing thousands of images each shown interactively.","solutions":["Close displays when done (call disp.close() and let it go out of scope / delete it)","Reuse a single CImgDisplay and call disp.assign(img,...)/disp.resize() instead of constructing new ones","Audit loops for CImgDisplay creation and ensure each iteration destroys the previous display"],"exampleFix":"// before\nfor (auto &img : images) { CImgDisplay d(img, \"v\"); while (!d.is_closed()) d.wait(); } // leaks table after 512\n// after\ncimg::CImgDisplay d; // reuse one display\nfor (auto &img : images) {\n  if (d.is_empty()) d.assign(img, \"v\"); else d.assign(img);\n  while (!d.is_closed() && !d.is_keyESC()) d.wait();\n  if (d.is_closed()) d.assign(); // reset for next iteration\n}","handlingStrategy":"try-catch","validationCode":"// track your own active display count and reuse displays:\nif (activeDisplays >= 500) closeOldestDisplay();","typeGuard":null,"tryCatchPattern":"try { d.assign(img, \"win\"); } catch (const cimg_library::CImgDisplayException &e) { fprintf(stderr, \"Too many displays: %s\\n\", e.what()); d.assign(); // free a slot and retry\n}","preventionTips":["Reuse one CImgDisplay object with assign()/resize() instead of new displays per item","Ensure every display is closed/destroyed (RAII scopes, no leaks in loops)","Never allocate displays per frame in animation/render loops","Monitor nb_cimg_displays implicitly by keeping total lifetime displays per process far below 512"],"tags":["x11","display","resource-leak","limit-exceeded"],"backgroundTag":"resource-limit-exceeded","analyzedSha":"f788b534b48c144edf786c8cddbf0e029e637804","analyzedAt":"2026-09-08T08:36:04.887Z","contentChangedAt":"2026-09-08T08:36:04.887Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}