diff --git a/src/propeller/push/utils/globals.cljc b/src/propeller/push/utils/globals.cljc index 26c37f1..aad494b 100644 --- a/src/propeller/push/utils/globals.cljc +++ b/src/propeller/push/utils/globals.cljc @@ -8,4 +8,23 @@ ;; Limits the number of items that can be duplicated onto a stack at once. ;; We might want to extend this to limit all the different that things may be ;; placed on a stack. -(def max-stack-items 100) \ No newline at end of file +(def max-stack-items 100) + + + +;; ============================================================================= +;; Values used by the Push instructions to keep computed values within +;; reasonable size limits. +;; ============================================================================= + +;; Used by keep-number-reasonable as the maximum magnitude of any integer/float +(def max-number-magnitude 1.0E12) + +;; Used by keep-number-reasonable as the minimum magnitude of any float +(def min-number-magnitude 1.0E-10) + +;; Used by reasonable-string-length? to ensure that strings don't get too large +(def max-string-length 1000) + +;; Used by keep-vector-reasonable to ensure that vectors don't get too large +(def max-vector-length 1000) \ No newline at end of file diff --git a/src/propeller/push/utils/helpers.cljc b/src/propeller/push/utils/helpers.cljc index 4eccfb6..1596827 100755 --- a/src/propeller/push/utils/helpers.cljc +++ b/src/propeller/push/utils/helpers.cljc @@ -2,9 +2,40 @@ (:require [clojure.set] [propeller.push.core :as push] [propeller.push.state :as state] + [propeller.push.utils.globals :as globals] #?(:cljs [goog.string :as gstring]) #?(:cljs [goog.string.format]))) +;; Returns a version of the number n that is within reasonable size bounds +(defn keep-number-reasonable + [n] + (cond + (integer? n) + (cond + (> n globals/max-number-magnitude) (long globals/max-number-magnitude) + (< n (- globals/max-number-magnitude)) (long (- globals/max-number-magnitude)) + :else n) + :else + (cond + (Double/isNaN n) 0.0 + (or (= n Double/POSITIVE_INFINITY) + (> n globals/max-number-magnitude)) globals/max-number-magnitude + (or (= n Double/NEGATIVE_INFINITY) + (< n (- globals/max-number-magnitude))) (- globals/max-number-magnitude) + (< (- globals/min-number-magnitude) n globals/min-number-magnitude) 0.0 + :else n))) + +;; Returns true if the string is of a reasonable size +(defn reasonable-string-length? + [string] + (let [length (count string)] + (<= length globals/max-string-length))) + +;; Returns true if the vector is of a reasonable size +(defn reasonable-vector-length? + [vector] + (let [length (count vector)] + (<= length globals/max-vector-length))) ;; Takes a state and a collection of stacks to take args from. If there are ;; enough args on each of the desired stacks, returns a map with keys @@ -40,9 +71,23 @@ state (let [result (apply function (:args popped-args)) new-state (:state popped-args)] - (if (= result :ignore-instruction) + (cond + (number? result) + (state/push-to-stack new-state return-stack (keep-number-reasonable result)) + ;; + (and (string? result) + (not (reasonable-string-length? result))) state - (state/push-to-stack new-state return-stack result)))))) + ;; + (and (vector? result) + (not (reasonable-vector-length? result))) + state + ;; + (= result :ignore-instruction) + state + ;; + :else + (state/push-to-stack new-state return-stack result)))))) ;; Given a set of stacks, returns all instructions that operate on those stacks ;; only. Won't include random instructions unless :random is in the set as well