summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorLemonBoy <LemonBoy@users.noreply.github.com>2018-10-18 14:30:31 +0200
committerAndreas Rumpf <rumpf_a@web.de>2018-10-18 14:30:31 +0200
commit1fe949b9d5f3b5128fe44fd566c434648e880eb1 (patch)
treede88d5a81130fef8827fd65d482b3c9e9cb31c5d
parente66b51eb16a38bc70e1bcf44071d2c380b956365 (diff)
downloadNim-1fe949b9d5f3b5128fe44fd566c434648e880eb1.tar.gz
Make the swap procs safe for unaligned input ptrs (#9210)
* Make the swap procs safe for unaligned input ptrs

The copy to a temporary local variable is often elided by a sufficiently
smart compiler when it can prove the input pointer is aligned.

Refs #9206

* Explain why copyMem is used
-rw-r--r--lib/pure/endians.nim21
1 files changed, 12 insertions, 9 deletions
diff --git a/lib/pure/endians.nim b/lib/pure/endians.nim
index 6f80d56ef..771ecaaca 100644
--- a/lib/pure/endians.nim
+++ b/lib/pure/endians.nim
@@ -44,20 +44,23 @@ else:
   const useBuiltinSwap = false
 
 when useBuiltinSwap:
+  template swapOpImpl(T: typedesc, op: untyped) =
+    ## We have to use `copyMem` here instead of a simple deference because they
+    ## may point to a unaligned address. A sufficiently smart compiler _should_
+    ## be able to elide them when they're not necessary.
+    var tmp: T
+    copyMem(addr tmp, inp, sizeOf(T))
+    tmp = op(tmp)
+    copyMem(outp, addr tmp, sizeOf(T))
+
   proc swapEndian64*(outp, inp: pointer) {.inline, nosideeffect.}=
-    var i = cast[ptr uint64](inp)
-    var o = cast[ptr uint64](outp)
-    o[] = builtin_bswap64(i[])
+    swapOpImpl(uint64, builtin_bswap64)
 
   proc swapEndian32*(outp, inp: pointer) {.inline, nosideeffect.}=
-    var i = cast[ptr uint32](inp)
-    var o = cast[ptr uint32](outp)
-    o[] = builtin_bswap32(i[])
+    swapOpImpl(uint32, builtin_bswap32)
 
   proc swapEndian16*(outp, inp: pointer) {.inline, nosideeffect.}=
-    var i = cast[ptr uint16](inp)
-    var o = cast[ptr uint16](outp)
-    o[] = builtin_bswap16(i[])
+    swapOpImpl(uint16, builtin_bswap16)
 
 else:
   proc swapEndian64*(outp, inp: pointer) =