From 2eaa2dc807733c626f217f8b3254ee456cd3c2b9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 8 Apr 2026 12:07:07 +0000 Subject: [PATCH] :bug: Handle corrupted PathData segments gracefully instead of crashing Add nil defaults to all case expressions that match binary segment type codes so that corrupted/unknown values are skipped instead of throwing 'No matching clause'. This prevents a React render crash (triggered via shape-with-open-path? -> get-subpaths -> reduce) when a PathData buffer contains invalid bytes, e.g. from a WASM data transfer or deserialization of damaged stored data. Affected functions: read-segment, impl-walk, impl-reduce, impl-lookup, to-string-segment*, and the seq/reduce protocol implementations on both JVM and CLJS PathData types. Signed-off-by: Andrey Antukh --- common/src/app/common/types/path/impl.cljc | 61 ++++++++++++++++------ 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/common/src/app/common/types/path/impl.cljc b/common/src/app/common/types/path/impl.cljc index ecdd7ddb09..f15840719f 100644 --- a/common/src/app/common/types/path/impl.cljc +++ b/common/src/app/common/types/path/impl.cljc @@ -131,8 +131,10 @@ 1 :move-to 2 :line-to 3 :curve-to - 4 :close-path) - res (f type c1x c1y c2x c2y x y)] + 4 :close-path + nil) + res (when (some? type) + (f type c1x c1y c2x c2y x y))] (recur (inc index) (if (some? res) (conj! result res) @@ -156,8 +158,11 @@ 1 :move-to 2 :line-to 3 :curve-to - 4 :close-path) - result (f result index type c1x c1y c2x c2y x y)] + 4 :close-path + nil) + result (if (some? type) + (f result index type c1x c1y c2x c2y x y) + result)] (if (reduced? result) result (recur (inc index) result))) @@ -177,9 +182,11 @@ 1 :move-to 2 :line-to 3 :curve-to - 4 :close-path)] - #?(:clj (f type c1x c1y c2x c2y x y) - :cljs (^function f type c1x c1y c2x c2y x y)))) + 4 :close-path + nil)] + (when (some? type) + #?(:clj (f type c1x c1y c2x c2y x y) + :cljs (^function f type c1x c1y c2x c2y x y))))) (defn- to-string-segment* [buffer offset type ^StringBuilder builder] @@ -219,7 +226,10 @@ (.append ",") (.append y))) 4 (doto builder - (.append "Z")))) + (.append "Z")) + + ;; Skip corrupted/unknown segment types + nil)) (defn- to-string "Format the path data structure to string" @@ -236,7 +246,8 @@ (.toString builder))) (defn- read-segment - "Read segment from binary buffer at specified index" + "Read segment from binary buffer at specified index. Returns nil for + corrupted/invalid segment types." [buffer index] (let [offset (* index SEGMENT-U8-SIZE) type (buf/read-short buffer offset)] @@ -268,7 +279,10 @@ :c2y (double c2y)}}) 4 {:command :close-path - :params {}}))) + :params {}} + + ;; Return nil for corrupted/unknown segment types + nil))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; TYPE: PATH-DATA @@ -320,8 +334,10 @@ (when (pos? size) ((fn next-seq [i] (when (< i size) - (cons (read-segment buffer i) - (lazy-seq (next-seq (inc i)))))) + (let [segment (read-segment buffer i)] + (if (some? segment) + (cons segment (lazy-seq (next-seq (inc i)))) + (next-seq (inc i)))))) 0))) clojure.lang.IReduceInit @@ -329,7 +345,10 @@ (loop [index 0 result start] (if (< index size) - (let [result (f result (read-segment buffer index))] + (let [segment (read-segment buffer index) + result (if (some? segment) + (f result segment) + result)] (if (reduced? result) @result (recur (inc index) result))) @@ -407,7 +426,10 @@ (read-segment buffer 0) nil)] (if (< index size) - (let [result (f result (read-segment buffer index))] + (let [segment (read-segment buffer index) + result (if (some? segment) + (f result segment) + result)] (if (reduced? result) @result (recur (inc index) result))) @@ -417,7 +439,10 @@ (loop [index 0 result start] (if (< index size) - (let [result (f result (read-segment buffer index))] + (let [segment (read-segment buffer index) + result (if (some? segment) + (f result segment) + result)] (if (reduced? result) @result (recur (inc index) result))) @@ -446,8 +471,10 @@ (when (pos? size) ((fn next-seq [i] (when (< i size) - (cons (read-segment buffer i) - (lazy-seq (next-seq (inc i)))))) + (let [segment (read-segment buffer i)] + (if (some? segment) + (cons segment (lazy-seq (next-seq (inc i)))) + (next-seq (inc i)))))) 0))) cljs.core/IPrintWithWriter