{"record":{"id":"71b6b79733062259","repo":"Yalantis/uCrop","slug":"cimg-appname-math-parser-cimg-s-s-call-stac","errorCode":null,"errorMessage":"[cimg_appname_math_parser] CImg<%s>::%s: Call stack overflow (infinite recursion?), in expression '%s'.","messagePattern":"\\[cimg_appname_math_parser\\] CImg<(.+?)>::(.+?): Call stack overflow \\(infinite recursion\\?\\), in expression '(.+?)'\\.","errorType":"exception","errorClass":"CImgArgumentException","httpStatus":null,"severity":"error","filePath":"ucrop/src/main/jni/CImg.h","lineNumber":18098,"sourceCode":"        need_input_copy(mp.need_input_copy),\n        result(mem._data + (mp.result - mp.mem._data)),\n        result_end(mp.result_end?mem._data + (mp.result_end - mp.mem._data):0),\n        rng((cimg::_rand(),cimg::rng())),calling_function(0) {\n\n#if cimg_use_openmp!=0\n        mem[_cimg_mp_slot_t] = (double)omp_get_thread_num();\n        rng+=omp_get_thread_num();\n#endif\n        opcode.assign();\n        opcode._is_shared = true;\n      }\n\n      // Compilation procedure.\n      unsigned int compile(char *ss, char *se, const unsigned int depth, unsigned int *const p_ref,\n                           unsigned char block_flags) {\n        if (depth>256) {\n          cimg::strellipsize(expr,64);\n          throw CImgArgumentException(\"[\" cimg_appname \"_math_parser] \"\n                                      \"CImg<%s>::%s: Call stack overflow (infinite recursion?), \"\n                                      \"in expression '%s'.\",\n                                      pixel_type(),_cimg_mp_calling_function,\n                                      (ss - 4)>expr._data?ss - 4:expr._data);\n        }\n        char c1, c2;\n\n        // Simplify expression when possible.\n        do {\n          c2 = 0;\n          if (ss<se) {\n            while (*ss && (cimg::is_blank(*ss) || *ss==';')) ++ss; // Remove leading blanks and ';'\n            while (se>ss && (cimg::is_blank(c1 = *(se - 1)) || c1==';')) --se; // Remove trailing blanks and ';'\n          }\n          while (*ss=='(' && *(se - 1)==')' && std::strchr(ss,')')==se - 1) { // Remove useless start/end parentheses\n            ++ss; --se; c2 = 1;\n          }\n          if (*ss=='_' && ss + 1<se && ss[1]=='(') { // Remove leading '_(something)' comment","sourceCodeStart":18080,"sourceCodeEnd":18116,"githubUrl":"https://github.com/Yalantis/uCrop/blob/f788b534b48c144edf786c8cddbf0e029e637804/ucrop/src/main/jni/CImg.h#L18080-L18116","documentation":"During compilation of a math expression, the parser enforces a recursion depth limit of 256 nested call levels. Exceeding it means the expression recurses infinitely (e.g. a macro calling itself without a terminating condition), so CImgArgumentException is thrown with an excerpt of the offending expression.","triggerScenarios":"Defining a macro that calls itself unconditionally (e.g. foo() : foo()+1) or deeply/nested self-referencing expressions; mutual recursion between macros (a calls b, b calls a); extremely deep nesting of function calls beyond 256 levels.","commonSituations":"Translating recursive formulas (factorial, fractals) into CImg macros without a base case; copy-pasted expressions from other DSLs with unbounded recursion.","solutions":["Add a termination/base case to the recursive macro (use conditionals like if(cond, base, rec)).","Rewrite the recursion as an iterative loop construct (while()/for() in the expression language) or compute the value outside CImg.","Check for accidental self-reference/cyclic references between macro names.","Test complex expressions in a small tool (e.g. the CImg 'math' evaluator) before embedding them in the app."],"exampleFix":"// before\n\"fact(n) : fact(n-1)*n\" // infinite recursion\n// after\n\"fact(n) : if(n<=1,1,fact(n-1)*n)\" // base case stops recursion","handlingStrategy":"validation","validationCode":"// static check before evaluation: reject known-unbounded recursive macros\nif (expr_contains_unbounded_recursion(expr)) return ERR_INFINITE_RECURSION;\nimg.eval(expr);","typeGuard":null,"tryCatchPattern":"try {\n  img.eval(expr);\n} catch (const CImgArgumentException& e) {\n  if (strstr(e.what(), \"Call stack overflow\")) {\n    // mark expression as recursive/broken; disable feature or prompt user\n  }\n}","preventionTips":["Always give recursive macros a base case guarded by if().","Prefer iterative expressions (while/loop constructs) over deep recursion.","Check for accidental cyclic references between macro names.","Limit user-supplied expressions or lint them before evaluation."],"tags":["cimg","math-expression","recursion","stack-overflow"],"backgroundTag":"internal-invariant-violation","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"}