Эх сурвалжийг харах

docs: bound the array index parse, so a long digit run cannot kill the runner

fszontagh 1 сар өмнө
parent
commit
e75cd9b3ea

+ 23 - 8
docs/superpowers/plans/2026-08-04-tier-1-nodes.md

@@ -557,6 +557,23 @@ Insert after the closing `}, "pick", 2));` at line 1550, before the `// utils.om
             return JS_DupValue(ctx, argv[0]);
         }
 
+        // An array index has to fit a uint32_t. A longer run of digits is not a
+        // valid index, and std::stoll would throw std::out_of_range on it - a
+        // C++ exception unwinding through QuickJS C frames takes the runner
+        // process with it, so the parse is bounded rather than guarded after
+        // the fact.
+        auto parseIndex = [](const std::string& text, uint32_t& out) -> bool {
+            if (text.empty() || text.size() > 10) return false;
+            if (text.find_first_not_of("0123456789") != std::string::npos) return false;
+            uint64_t value = 0;
+            for (char c : text) {
+                value = value * 10 + (uint64_t)(c - '0');
+            }
+            if (value > 0xFFFFFFFFull) return false;
+            out = (uint32_t)value;
+            return true;
+        };
+
         std::vector<std::string> keys;
         size_t start = 0;
         while (true) {
@@ -589,22 +606,20 @@ Insert after the closing `}, "pick", 2));` at line 1550, before the `// utils.om
             // key[3] - step into the property, then index it
             std::string key = raw_key;
             bool has_index = false;
-            int64_t index = 0;
+            uint32_t index = 0;
             size_t bracket = raw_key.find('[');
             if (bracket != std::string::npos && raw_key.back() == ']') {
                 std::string index_text = raw_key.substr(bracket + 1, raw_key.size() - bracket - 2);
-                if (!index_text.empty() &&
-                    index_text.find_first_not_of("0123456789") == std::string::npos) {
+                if (parseIndex(index_text, index)) {
                     key = raw_key.substr(0, bracket);
-                    index = std::stoll(index_text);
                     has_index = true;
                 }
             }
 
             if (!key.empty()) {
-                bool numeric = key.find_first_not_of("0123456789") == std::string::npos;
-                if (numeric && is_array) {
-                    JSValue element = JS_GetPropertyUint32(ctx, current, (uint32_t)std::stoll(key));
+                uint32_t bare_index = 0;
+                if (is_array && parseIndex(key, bare_index)) {
+                    JSValue element = JS_GetPropertyUint32(ctx, current, bare_index);
                     JS_FreeValue(ctx, current);
                     current = element;
                 } else {
@@ -623,7 +638,7 @@ Insert after the closing `}, "pick", 2));` at line 1550, before the `// utils.om
                     JS_FreeValue(ctx, current);
                     return JS_UNDEFINED;
                 }
-                JSValue element = JS_GetPropertyUint32(ctx, current, (uint32_t)index);
+                JSValue element = JS_GetPropertyUint32(ctx, current, index);
                 JS_FreeValue(ctx, current);
                 current = element;
             }