{"record":{"id":"0e878db1b222b8e5","repo":"Yalantis/uCrop","slug":"cimg-appname-math-parser-cimg-s-function-0e878d","errorCode":null,"errorMessage":"\"[\" cimg_appname \"_math_parser] CImg<%s>: Function 'swap()': Out-of-bounds offsets %ld and %ld (min offset: 0, max offset: %ld).\"","messagePattern":"\"\\[\" cimg_appname \"_math_parser\\] CImg<(.+?)>: Function 'swap\\(\\)': Out-of-bounds offsets %ld and %ld \\(min offset: 0, max offset: %ld\\)\\.\"","errorType":"exception","errorClass":"CImgArgumentException","httpStatus":null,"severity":"error","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":27372,"sourceCode":"\n      static double mp_image_swap(_cimg_math_parser& mp) {\n        unsigned int ind = (unsigned int)mp.opcode[2];\n        if (!mp.imglist.width()) return cimg::type<double>::nan();\n        ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width());\n        CImg<T> &img = mp.imglist[ind];\n        const longT\n          pos0 = (longT)_mp_arg(3),\n          pos1 = (longT)_mp_arg(4);\n        const bool is_vector = (bool)_mp_arg(5);\n        if (is_vector) {\n          const longT whd = (longT)img.size()/img.spectrum();\n          T *ptr0 = &img[pos0], *ptr1 = &img[pos1];\n          if (pos0>=0 && pos0<=whd && pos1>=0 && pos1<=whd)\n            for (unsigned int c = 0; c<img._spectrum; ++c) {\n              cimg::swap(*ptr0,*ptr1);\n              ptr0+=whd;\n              ptr1+=whd;\n            } else throw CImgArgumentException(\"[\" cimg_appname \"_math_parser] CImg<%s>: Function 'swap()': \"\n                                               \"Out-of-bounds offsets %ld and %ld (min offset: 0, max offset: %ld).\",\n                                               mp.imgin.pixel_type(),pos0,pos1,whd);\n        } else {\n          const longT whds = (longT)img.size();\n          if (pos0>=0 && pos0<=whds && pos1>=0 && pos1<=whds)\n            cimg::swap(img[pos0],img[pos1]);\n          else throw CImgArgumentException(\"[\" cimg_appname \"_math_parser] CImg<%s>: Function 'swap()': \"\n                                           \"Out-of-bounds offsets %ld and %ld (min offset: 0, max offset: %ld).\",\n                                           mp.imgin.pixel_type(),pos0,pos1,whds);\n        }\n        return cimg::type<double>::nan();\n      }\n\n      static double mp_image_w(_cimg_math_parser& mp) {\n        unsigned int ind = (unsigned int)mp.opcode[2];\n        if (ind!=~0U) {\n          if (!mp.imglist.width()) return cimg::type<double>::nan();\n          ind = (unsigned int)cimg::mod((int)_mp_arg(2),mp.imglist.width());","sourceCodeStart":27354,"sourceCodeEnd":27390,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L27354-L27390","documentation":"The CImg math parser 'swap()' function exchanges two pixel values inside the input image, addressed by linear offsets. Before swapping, it validates that both offsets fall within [0, whd] (whd = width*height*depth for the vectorized per-channel variant). If either offset is out of range, a CImgArgumentException is thrown instead of performing an out-of-bounds memory access.","triggerScenarios":"Executing a math expression like `swap(pos0,pos1)` (or the multi-channel form swap with channel loop) where pos0 or pos1 evaluates to a negative value or exceeds the image's width*height*depth bound, e.g. swap(0, w*h*d+5) on an image whose whd is smaller.","commonSituations":"Hand-written custom formulas that compute offsets from x,y,z,c coordinates and forget zero-based vs size-based indexing; formulas ported between images of different sizes; loop variables in math expressions running one step too far (i<=N instead of i<N).","solutions":["Print/inspect the image dimensions (width,height,depth,spectrum) and clamp both swap offsets to the range [0, w*h*d] before calling swap().","Fix off-by-one loop bounds in the math expression so offsets never reach size() inclusive of an extra element.","Use index expressions built from I[x,y,z,c]-style accessors rather than raw arithmetic offsets when possible.","Wrap the expression evaluation in a try/catch for CImgArgumentException and report the offending offsets to the user."],"exampleFix":"// before: swap(K, K + 10) with no bound check\n// after in math expression:\n// K < w*h*d - 10 ? swap(K, K + 10) : 0","handlingStrategy":"validation","validationCode":"// before evaluating: check offsets against image extent\nconst longT whd = img.width() * img.height() * img.depth();\nif (pos0 < 0 || pos0 > whd || pos1 < 0 || pos1 > whd)\n  throw std::runtime_error(\"swap offsets out of range\");","typeGuard":null,"tryCatchPattern":"try { img.evaluate(expr); } catch (const CImgArgumentException& e) { log(\"math parser swap out of bounds: \" << e.what()); }","preventionTips":["Build offsets from x,y,z,c accessor arithmetic validated against w*h*d","Beware off-by-one loop bounds (i<N, not i<=N)","Test formulas on the smallest image size you support"],"tags":["cimg","math-parser","index-out-of-bounds"],"backgroundTag":"index-out-of-bounds","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"}