Protect array-based put! and get! from overflow, where possible. · uncomplicate/clojure-cpp@c02f2ce · GitHub
Skip to content

Commit c02f2ce

Browse files
committed
Protect array-based put! and get! from overflow, where possible.
1 parent 6de3b6c commit c02f2ce

3 files changed

Lines changed: 112 additions & 52 deletions

File tree

‎project.clj‎

Lines changed: 4 additions & 2 deletions

‎src/clojure/uncomplicate/clojure_cpp.clj‎

Lines changed: 94 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,20 @@
151151
^long []
152152
(Pointer/totalCount))
153153

154+
(defn safe
155+
"If pointer `p` is neither `nil` nor `NULL`, returns `p`. Otherwise, throws an `IllegalArgumentexception`."
156+
^Pointer [^Pointer p]
157+
(if-not (Pointer/isNull p)
158+
p
159+
(throw (IllegalArgumentException. "Neither nil nor NULL pointer is allowed in this part of code. Please do not use non-initialized pointers here."))))
160+
161+
(defn safe2
162+
"If pointer `p` is not `NULL`, returns `p`. Otherwise, throws an `IllegalArgumentexception`."
163+
^Pointer [^Pointer p]
164+
(if (or (nil? p) (< 0 (.address p)))
165+
p
166+
(throw (IllegalArgumentException. "NULL pointer is not allowed in this part of code. Please do not use non-initialized pointers here."))))
167+
154168
;; ================= A set of standard C functions =================================
155169

156170
(defn malloc!
@@ -216,7 +230,8 @@
216230
(memcmp (byte-pointer [1 2 3]) (byte-pointer [1 1 4]) 3) => 1
217231
"
218232
(^long [^Pointer p1 ^Pointer p2 ^long byte-size]
219-
(if (<= 0 byte-size (min (bytesize p1) (bytesize p2)))
233+
(if (and (not (Pointer/isNull p1) (not (Pointer/isNull p2)))
234+
(<= 0 byte-size (min (bytesize p1) (bytesize p2))))
220235
(Pointer/memcmp p1 p2 byte-size)
221236
(throw (IndexOutOfBoundsException.
222237
(format "You're trying to compare data outside the bounds of %s memory block."
@@ -229,7 +244,8 @@
229244
bounds of `src` and `dst`, throws `IndexOutOfBoundsException`.
230245
"
231246
([^Pointer src ^Pointer dst ^long byte-size]
232-
(if (<= 0 byte-size (min (bytesize src) (bytesize dst)))
247+
(if (and (not (Pointer/isNull src)) (not (Pointer/isNull dst))
248+
(<= 0 byte-size (min (bytesize src) (bytesize dst))))
233249
(Pointer/memcpy dst src byte-size)
234250
(throw (IndexOutOfBoundsException.
235251
(format "You're trying to copy outside the bounds of %s memory block."
@@ -243,7 +259,8 @@
243259
If `byte-size` is not within bounds of `src` and `dst`, throws `IndexOutOfBoundsException`.
244260
"
245261
([^Pointer src ^Pointer dst ^long byte-size]
246-
(if (<= 0 byte-size (min (bytesize src) (bytesize dst)))
262+
(if (and (not (Pointer/isNull src)) (not (Pointer/isNull dst))
263+
(<= 0 byte-size (min (bytesize src) (bytesize dst))))
247264
(Pointer/memmove dst src byte-size)
248265
(throw (IndexOutOfBoundsException.
249266
(format "You're trying to move data outside the bounds of %s memory block."
@@ -256,14 +273,16 @@
256273
If `byte-size` is not within bounds of `src` and `dst`, throws `IndexOutOfBoundsException`.
257274
"
258275
[^Pointer dst ^long value ^long byte-size]
259-
(if (<= 0 byte-size (bytesize dst))
276+
(if (and (not (Pointer/isNull dst)) (<= 0 byte-size (bytesize dst)))
260277
(Pointer/memset dst value byte-size)
261278
(throw (IndexOutOfBoundsException. "You're trying to set data outside the bounds of the destination memory block."))))
262279

263280
(defn zero!
264281
"Initializes all elements in the memory block managed by `p` to zero."
265282
[^Pointer p]
266-
(.zero p))
283+
(if-not (Pointer/isNull p)
284+
(.zero p)
285+
p))
267286

268287
;; ================= Pointer =================================
269288

@@ -377,20 +396,6 @@
377396
(throw (IndexOutOfBoundsException. (format "The requested position %d is larger than capacity %d."
378397
n (.capacity p))))))
379398

380-
(defn safe
381-
"If pointer `p` is neither `nil` nor `NULL`, returns `p`. Otherwise, throws an `IllegalArgumentexception`."
382-
^Pointer [^Pointer p]
383-
(if-not (null? p)
384-
p
385-
(throw (IllegalArgumentException. "Neither nil nor NULL pointer is allowed in this part of code. Please do not use non-initialized pointers here."))))
386-
387-
(defn safe2
388-
"If pointer `p` is not `NULL`, returns `p`. Otherwise, throws an `IllegalArgumentexception`."
389-
^Pointer [^Pointer p]
390-
(if (or (nil? p) (< 0 (.address p)))
391-
p
392-
(throw (IllegalArgumentException. "NULL pointer is not allowed in this part of code. Please do not use non-initialized pointers here."))))
393-
394399
(defn get-pointer
395400
"Returns a new pointer that manages the memory block managed by `p`, starting from element `i`,
396401
bounded by capacity `(capacity p)`. If provided with pointer's type, coerces the pointer to it
@@ -1726,32 +1731,50 @@
17261731
(.put this# i# (~entry-type value#))
17271732
this#))
17281733
(fill! [this# value#]
1729-
(let [v# (~entry-type value#)]
1730-
(if (~zero? v#)
1731-
(.zero this#)
1732-
(dotimes [i# (size this#)]
1733-
(.put this# i# (~entry-type value#)))))
1734+
(when-not (null? this#)
1735+
(let [v# (~entry-type value#)]
1736+
(if (~zero? v#)
1737+
(.zero this#)
1738+
(dotimes [i# (size this#)]
1739+
(.put this# i# (~entry-type value#))))))
17341740
this#)
17351741
(get!
17361742
([p# arr#]
1737-
(access* get ~pt p# ~array-type arr#)
1743+
(if (and (not (null? p#))
1744+
(<= 0 (alength (~array-type arr#)) (capacity p#)))
1745+
(access* get ~pt p# ~array-type arr#)
1746+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds")))
17381747
arr#)
17391748
([p# arr# offset# length#]
1740-
(access* get ~pt p# ~array-type arr# offset# length#)
1749+
(if (and (not (null? p#))
1750+
(<= 0 offset# (+ (long offset#) (long length#)) (capacity p#))
1751+
(<= 0 length# (alength (~array-type arr#))))
1752+
(access* get ~pt p# ~array-type arr# offset# length#)
1753+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds")))
17411754
arr#))
17421755
(put!
17431756
([p# obj#]
17441757
(if (sequential? obj#)
1745-
(.put p# (~array-type (~convert-fn obj#)))
1746-
(.put p# (~array-type obj#)))
1758+
(put! p# (~array-type (~convert-fn obj#)))
1759+
(if (and (not (null? p#))
1760+
(<= 0 (alength (~array-type obj#)) (capacity p#)))
1761+
(.put p# (~array-type obj#))
1762+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds"))))
17471763
p#)
17481764
([p# obj# offset# length#]
17491765
(if (sequential? obj#)
1750-
(.put p# (~array-type (~convert-fn (take length# (drop offset# obj#)))))
1751-
(.put p# obj# offset# length#))))
1766+
(put! p# (~array-type (~convert-fn (take length# (drop offset# obj#)))))
1767+
(if (and (not (null? p#))
1768+
(<= 0 offset# (+ (long offset#) (long length#)) (capacity p#))
1769+
(<= 0 length# (alength (~array-type obj#))))
1770+
(.put p# obj# offset# length#)
1771+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds"))))
1772+
p#))
17521773
PointerVec
17531774
(pointer-vec [this#]
1754-
(let [n# (size this#)]
1775+
(let [n# (if-not (null? this#)
1776+
(size this#)
1777+
0)]
17551778
(loop [res# (transient []) i# 0]
17561779
(if (< i# n#)
17571780
(recur (conj! res# (.get this# i#)) (inc i#))
@@ -1782,27 +1805,43 @@
17821805
(put-entry* value i this)
17831806
this))
17841807
(fill! [this value]
1785-
(if (zero? (byte value))
1786-
(.zero this)
1787-
(.fill this value))
1808+
(when-not (null? this)
1809+
(if (zero? (byte value))
1810+
(.zero this)
1811+
(.fill this value)))
17881812
this)
17891813
(get!
17901814
([p arr]
1791-
(.get p (bytes arr))
1815+
(if (and (not (null? p))
1816+
(<= 0 (alength (bytes arr)) (capacity p)))
1817+
(.get p (bytes arr))
1818+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds")))
17921819
arr)
17931820
([p arr offset length]
1794-
(.get p (bytes arr) offset length)
1821+
(if (and (not (null? p))
1822+
(<= 0 offset (+ (long offset) (long length)) (capacity p))
1823+
(<= 0 length (alength (bytes arr))))
1824+
(.get p (bytes arr) offset length)
1825+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds")))
17951826
arr))
17961827
(put!
17971828
([p obj]
17981829
(if (sequential? obj)
1799-
(.put p (byte-array obj))
1800-
(.put p (bytes obj)))
1830+
(put! p (byte-array obj))
1831+
(if (and (not (null? p))
1832+
(<= 0 (alength (bytes obj)) (capacity p)))
1833+
(.put p (bytes obj))
1834+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds"))))
18011835
p)
18021836
([p obj offset length]
18031837
(if (sequential? obj)
1804-
(.put p (byte-array (take length (drop offset obj))))
1805-
(.put p obj offset length)))))
1838+
(put! p (byte-array (take length (drop offset obj))))
1839+
(if (and (not (null? p))
1840+
(<= 0 offset (+ (long offset) (long length)) (capacity p))
1841+
(<= 0 length (alength (bytes obj))))
1842+
(.put p obj offset length)
1843+
(throw (ArrayIndexOutOfBoundsException. "Requested range is out of bounds"))))
1844+
p)))
18061845

18071846
(extend-type BoolPointer
18081847
PointerCreator
@@ -1828,12 +1867,15 @@
18281867
(.put this i (boolean value))
18291868
this))
18301869
(fill! [this value]
1831-
(dotimes [i (size this)]
1832-
(.put this i (boolean value)))
1870+
(when-not (null? this)
1871+
(dotimes [i (size this)]
1872+
(.put this i (boolean value))))
18331873
this)
18341874
PointerVec
18351875
(pointer-vec [this]
1836-
(let [n (size this)]
1876+
(let [n (if-not (null? this)
1877+
(size this)
1878+
0)]
18371879
(loop [res (transient []) i 0]
18381880
(if (< i n)
18391881
(recur (conj! res (.get this i)) (inc i))
@@ -1882,19 +1924,22 @@
18821924
(.put this i ^Pointer value)
18831925
this))
18841926
(fill! [this value]
1885-
(dotimes [i (size this)]
1886-
(.put this i ^Pointer value))
1927+
(when-not (null? this)
1928+
(dotimes [i (size this)]
1929+
(.put this i ^Pointer value)))
18871930
this)
18881931
(put!
1889-
([p obj]
1890-
(put-pointer-pointer* obj p)
1891-
p)
1932+
([this obj]
1933+
(put-pointer-pointer* obj this)
1934+
this)
18921935
([this src arg]
18931936
(put-pointer-pointer* arg src this)
18941937
this))
18951938
PointerVec
18961939
(pointer-vec [this#]
1897-
(let [n# (size this#)]
1940+
(let [n# (if-not (null? this#)
1941+
(size this#)
1942+
0)]
18981943
(loop [res# (transient []) i# 0]
18991944
(if (< i# n#)
19001945
(recur (conj! res# (.get this# i#)) (inc i#))

‎test/uncomplicate/clojure_cpp_test.clj‎

Lines changed: 14 additions & 1 deletion

0 commit comments

Comments
 (0)