diff options
author | LemonBoy <LemonBoy@users.noreply.github.com> | 2018-10-18 14:30:31 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-10-18 14:30:31 +0200 |
commit | 1fe949b9d5f3b5128fe44fd566c434648e880eb1 (patch) | |
tree | de88d5a81130fef8827fd65d482b3c9e9cb31c5d | |
parent | e66b51eb16a38bc70e1bcf44071d2c380b956365 (diff) | |
download | Nim-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.nim | 21 |
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) = |