cmsg.scm 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. ;; This file is part of scheme-GNUnet, a partial Scheme port of GNUnet.
  2. ;; Copyright (C) 2021 GNUnet e.V.
  3. ;;
  4. ;; GNUnet is free software: you can redistribute it and/or modify it
  5. ;; under the terms of the GNU Affero General Public License as published
  6. ;; by the Free Software Foundation, either version 3 of the License,
  7. ;; or (at your option) any later version.
  8. ;;
  9. ;; GNUnet is distributed in the hope that it will be useful, but
  10. ;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;; Affero General Public License for more details.
  13. ;;
  14. ;; You should have received a copy of the GNU Affero General Public License
  15. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. ;;
  17. ;; SPDX-License-Identifier: AGPL-3.0-or-later
  18. (import (quickcheck)
  19. (quickcheck property)
  20. (quickcheck arbitrary)
  21. (quickcheck generator)
  22. (bytestructures guile)
  23. (srfi srfi-1)
  24. (srfi srfi-26)
  25. (ice-9 binary-ports)
  26. (ice-9 control)
  27. (ice-9 receive)
  28. (rnrs bytevectors)
  29. (rnrs conditions)
  30. (gnu gnunet util cmsg)
  31. (gnu gnunet utils bv-slice))
  32. (define lcov? #f)
  33. (define (slice->bv x)
  34. (let ((new (make-bytevector (slice-length x))))
  35. (slice-copy! x (bv-slice/read-write new))
  36. new))
  37. (define (slice-contents-equal? x y)
  38. (bytevector=? (slice->bv x)
  39. (slice->bv y)))
  40. (define (a-equal? a b)
  41. (let-syntax ((tx (syntax-rules ()
  42. ((_ (eq proj) ...)
  43. (and (eq (proj a) (proj b))
  44. ...)))))
  45. (tx (= ancillary:protocol)
  46. (= ancillary:type)
  47. (slice-contents-equal? ancillary:data))))
  48. (define (al-equal? a b)
  49. (every a-equal? a b))
  50. (define (av-equal? a b)
  51. (al-equal? (vector->list a) (vector->list b)))
  52. (if lcov?
  53. ;; Less tests, so the tests don't take too long to finish.
  54. (configure-quickcheck
  55. (stop? (lambda (success-count _)
  56. (>= success-count 10)))
  57. (size (lambda (test-number)
  58. (if (zero? test-number) 0
  59. (+ 3 (quotient test-number 1))))))
  60. ;; Likewise
  61. (configure-quickcheck
  62. (stop? (lambda (success-count _)
  63. (>= success-count 100)))
  64. (size (lambda (test-number)
  65. (if (zero? test-number) 0 ; <-- I don't know what I'm doing
  66. (1+ (quotient test-number 6)))))))
  67. ;; Generate control data.
  68. (define choose-ancillary-slice-or-bogus
  69. (generator-let*
  70. ((len (choose-one/weighted
  71. ;; overly small
  72. `((1 . ,(choose-integer 0 (@@ (gnu gnunet util cmsg)
  73. cmsghdr:size)))
  74. ;; perfectly aligned
  75. (1 . ,(generator-lift
  76. (cute * (@@ (gnu gnunet util cmsg) cmsghdr:size) <>)
  77. (choose-integer 0 5)))
  78. ;; other
  79. (1 . ,(choose-integer (@@ (gnu gnunet util cmsg)
  80. cmsghdr:size)
  81. 90)))))
  82. ;; not very interesting
  83. (level choose-byte)
  84. (type choose-byte)
  85. ;; Apparently len can be shorter
  86. ;; than the control message and even shorter than the message header,
  87. ;; see comment in glibc. (Please do not spread this practice.)
  88. (padding (choose-one/weighted
  89. `((3 . ,(generator-return 0))
  90. (1 . ,(choose-integer (- len) 17)))))
  91. ;; ! there is no guarantee padding bytes will be zero.
  92. (padding-bytes (choose-bytevector (max padding 0))))
  93. (let* ((bv (make-bytevector (+ len (max padding 0))))
  94. (header (make-bytevector (@@ (gnu gnunet util cmsg)
  95. cmsghdr:size))))
  96. ;; ^ on some architectures, this may already contain some padding
  97. ;; zero bytes at the end due to alignment. These will be overwritten later.
  98. (let-syntax ((set (syntax-rules ()
  99. ((_ field val)
  100. (bytestructure-set!* header 0
  101. (@@ (gnu gnunet util cmsg)
  102. cmsghdr)
  103. 'field val)))))
  104. (set len len)
  105. (set level level)
  106. (set type type))
  107. (bytevector-copy! header 0
  108. bv 0
  109. (min (bytevector-length header)
  110. (bytevector-length bv)))
  111. (if (<= 0 padding)
  112. (bytevector-copy! padding-bytes 0
  113. bv len
  114. (bytevector-length padding-bytes)))
  115. (generator-return (bv-slice/read-write bv 0 (+ len padding))))))
  116. ;; Append multiple ancillary message slices into a single
  117. ;; control data
  118. (define choose-control-data-bv
  119. (sized-generator
  120. (lambda (n-parts)
  121. (generator-lift (lambda (parts)
  122. (receive (port get-bv)
  123. (open-bytevector-output-port)
  124. (for-each (lambda (part)
  125. (put-bytevector port
  126. (slice-bv part)
  127. (slice-offset part)
  128. (slice-length part)))
  129. parts)
  130. (get-bv)))
  131. (choose-list choose-ancillary-slice-or-bogus n-parts)))))
  132. (define choose-control-data
  133. (generator-lift (compose slice/read-only bv-slice/read-write)
  134. choose-control-data-bv))
  135. (define $control-data
  136. (arbitrary
  137. (gen choose-control-data)
  138. (xform (lambda _ (throw 'oops)))))
  139. (define choose-slice/read-only
  140. (generator-lift (compose slice/read-only bv-slice/read-write)
  141. (sized-generator choose-bytevector)))
  142. (define $ancillary
  143. (arbitrary
  144. (gen (generator-lift make-ancillary
  145. (choose-integer 0 65535)
  146. (choose-integer 0 65535)
  147. choose-slice/read-only))
  148. (xform #f)))
  149. ;; Tests
  150. ;; Overview:
  151. ;; * count-ancillaries is a morphism
  152. ;; * control->ancillary-list & control->ancillary-vector
  153. ;; only differ in typing
  154. ;; * FAILS
  155. ;; control->ancillary-vector after ancillary-vector->bytevector
  156. ;; is identity (up to freshness, aside from bv -> slice mapping)
  157. ;; * split-ancillary works as expected on a single, whole ancillary
  158. ;; * align-len (private) satisties many nice properties
  159. ;; (idempotence, some kind of morphism, monotonity,
  160. ;; an alternative definition ...)
  161. (define (call-with-maximum proc)
  162. (let ((n -1))
  163. (proc (lambda (x)
  164. (set! n (max x n))))
  165. n))
  166. (define-syntax-rule (with-maximum increment body body* ...)
  167. (call-with-maximum
  168. (lambda (increment) body body* ...)))
  169. (define-syntax-rule (false-if-assertion exp exp* ...)
  170. (with-exception-handler
  171. (lambda (e) #f)
  172. (lambda () exp exp* ...)
  173. #:unwind? #t
  174. #:unwind-for-type &assertion))
  175. (define (t)
  176. ;; Make sure we generate a few ancillary messages
  177. ;; and not just some random bytevectors.
  178. ;; (disabled as it is nondeterministic).
  179. #;
  180. (test-assert "test case generator is not horribly broken"
  181. (> (with-maximum consider
  182. (quickcheck
  183. (property ((cd $control-data))
  184. (consider (count-ancillaries cd))
  185. #t)))
  186. 2))
  187. ;; Verify count-ancillaries is a morphism,
  188. ;; and control->ancillary-list & control->ancillary-vector and
  189. ;; are more or less the same.
  190. (test-assert "[prop] count-ancillaries & control->ancillary-list"
  191. (quickcheck
  192. (property ((cd $control-data))
  193. (false-if-assertion
  194. (= (count-ancillaries cd)
  195. (length (control->ancillary-list cd)))))))
  196. (test-assert "[prop] count-ancillaries & control->ancillary-vector"
  197. (quickcheck
  198. (property ((cd $control-data))
  199. (false-if-assertion
  200. (= (count-ancillaries cd)
  201. (vector-length (control->ancillary-vector cd)))))))
  202. (test-assert "[prop] control->ancillary-list & vector->list"
  203. (quickcheck
  204. (property ((cd $control-data))
  205. (false-if-assertion
  206. (al-equal? (control->ancillary-list cd)
  207. (vector->list (control->ancillary-vector cd)))))))
  208. ;; ancillaries->bytevector & control->ancillary-list
  209. (test-assert "[prop] control->ancillary-vector after ancillary-vector->bytevector"
  210. (quickcheck
  211. (property ((acv ($vector $ancillary)))
  212. (false-if-assertion
  213. (av-equal? acv
  214. (control->ancillary-vector
  215. (slice/read-only
  216. (bv-slice/read-write
  217. (ancillary-vector->bytevector acv)))))))))
  218. (test-assert "[prop] split-ancillary on whole ancillary"
  219. (quickcheck
  220. (property ((ac $ancillary))
  221. (false-if-assertion
  222. (receive (protocol type slice rest)
  223. (split-ancillary (bv-slice/read-write
  224. (ancillary-vector->bytevector (vector ac))))
  225. (and (= (slice-length rest) 0)
  226. (slice-readable? rest)
  227. (a-equal? (make-ancillary protocol type slice) ac)))))))
  228. (define-syntax-rule (case-values exp case ...)
  229. (call-with-values (lambda () exp)
  230. (case-lambda case ...)))
  231. ;; Verify the alignment function works as expected.
  232. (define align-len (@@ (gnu gnunet util cmsg) align-len))
  233. (define (aligned? n)
  234. (= (align-len n) n))
  235. (test-assert "0 is aligned" (aligned? 0))
  236. (test-assert "size_t is aligned"
  237. (aligned? (bytestructure-descriptor-size size_t)))
  238. (test-assert "[prop] multiples of aligned data are aligned"
  239. (quickcheck
  240. (property ((n $natural)
  241. (m $natural))
  242. (aligned? (* n (align-len m))))))
  243. (test-assert "[prop] aligned -> positive"
  244. (quickcheck
  245. (property ((n $natural))
  246. (<= 0 (align-len n)))))
  247. (test-assert "[prop] aligning is monotonuous"
  248. (quickcheck
  249. (property ((n $natural)
  250. (delta $natural))
  251. (<= (align-len n)
  252. (align-len (+ n delta))))))
  253. (test-assert "[prop] aligned > unaligned"
  254. (quickcheck
  255. (property ((n $natural))
  256. (<= n (align-len n)))))
  257. (test-assert "[prop] align-len is idempotent"
  258. (quickcheck
  259. (property ((n $natural))
  260. (= (align-len (align-len n)) (align-len n)))))
  261. (test-assert "[prop] align-len & addition (one part aligned)"
  262. (quickcheck
  263. (property ((n $natural)
  264. (m $natural))
  265. (let ((n (align-len n)))
  266. (= (align-len (+ n m))
  267. (+ n (align-len m)))))))
  268. (test-assert "[prop] align-len in terms of modulo, + and min"
  269. (let ((s (bytestructure-descriptor-size size_t)))
  270. (quickcheck
  271. (property ((n $natural))
  272. (= (align-len n)
  273. (let ((m (modulo n s)))
  274. (if (= m 0)
  275. n ; <-- already aligned
  276. (+ s (- n m)))))))))
  277. ;; control-size is well-behaving
  278. (test-assert "[prop] control-size length is aligned"
  279. (quickcheck
  280. (property ((s ($list $natural)))
  281. (aligned? (apply control-size s)))))
  282. (test-equal "control-size of empty list"
  283. 0
  284. (control-size))
  285. (test-assert "[prop] control-size is a morphism (append & +)"
  286. (quickcheck
  287. (property ((n ($list ($list $natural))))
  288. (= (apply control-size (apply append n))
  289. (apply + (map (lambda (l) (apply control-size l)) n))))))
  290. ;; control-size is sufficient
  291. (test-assert "[prop] length of ancillary->bytevector is control-size"
  292. (quickcheck
  293. (property ((ac $ancillary))
  294. (let* ((bv (ancillary-vector->bytevector (vector ac)))
  295. (bv-len (bytevector-length bv)))
  296. (= bv-len (control-size (slice-length (ancillary:data ac))))))))
  297. (test-assert "[prop] data written by write-ancillary->control! is control-size"
  298. (quickcheck
  299. (property ((ac $ancillary))
  300. (let ((dest (make-slice/read-write
  301. (control-size (slice-length (ancillary:data ac))))))
  302. (case-values
  303. (write-ancillary->control! dest ac)
  304. (() #f) ; <-- there should be plenty of space
  305. ((n) (= n (slice-length dest))))))))
  306. (test-assert "[prop] ... even if more bytes are writable"
  307. (quickcheck
  308. (property ((ac $ancillary)
  309. (extra $byte))
  310. (let ((dest (make-slice/read-write
  311. (control-size (slice-length (ancillary:data ac))
  312. (floor/ extra 4)))))
  313. (case-values
  314. (write-ancillary->control! dest ac)
  315. (() #f) ; <-- there should be plenty of space (too much, actually)
  316. ((n) (= n (control-size (slice-length (ancillary:data ac))))))))))
  317. ;; control-size is required
  318. (test-assert "[prop] write-ancillary->control! fails when too little space (incl. unaligned)"
  319. (quickcheck
  320. (property ((ac $ancillary)
  321. (less $byte))
  322. (let* ((bv (ancillary-vector->bytevector (vector ac)))
  323. (plenty-of-space (bytevector-length bv))
  324. (less (floor/ less 16)) ; Otherwise we see ‘Gave up! Passed only 1 est’.
  325. (too-small (slice/write-only
  326. (make-slice/read-write
  327. (max 0 (min (- plenty-of-space 1) less))))))
  328. (test-when (< less plenty-of-space)
  329. (case-values
  330. (write-ancillary->control! too-small ac)
  331. (() #t)
  332. ((n) #f)))))))
  333. (test-assert "[prop] write-ancillary-vector->control! fails when too little space is passed"
  334. (quickcheck
  335. (property ((ac ($vector $ancillary))
  336. (less $byte))
  337. (let* ((bv (ancillary-vector->bytevector ac))
  338. (plenty-of-space (bytevector-length bv))
  339. (less (floor/ less 16)) ; Otherwise we see ‘Gave up! Passed only 1 est’.
  340. (too-small (slice/write-only
  341. (make-slice/read-write
  342. (max 0 (min (- plenty-of-space 1) less))))))
  343. (test-when (< less plenty-of-space)
  344. (with-exception-handler
  345. (lambda (e) #t)
  346. (lambda ()
  347. (write-ancillary-vector->control! too-small ac)
  348. #f)
  349. #:unwind? #t
  350. #:unwind-for-type &control-data-too-small)))))))
  351. (use-modules (system vm coverage))
  352. (if lcov?
  353. (call-with-values (lambda () (with-code-coverage t))
  354. (lambda (data)
  355. (let ((port (open-output-file "lcov.info")))
  356. (coverage-data->lcov data port)
  357. (close port))))
  358. (t))