summaryrefslogtreecommitdiff
path: root/driver_zodiac.c
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2014-08-21 07:41:56 -0400
committerEric S. Raymond <esr@thyrsus.com>2014-08-21 07:41:56 -0400
commit1e98a6b5a87db80f445f3c7a8322c9d30e7dc71d (patch)
treec3679383b5de6f3401a5456ef6be5be9d6ebe273 /driver_zodiac.c
parent517ac3dfb0934e1fa951c5a803069ff53f881726 (diff)
downloadgpsd-1e98a6b5a87db80f445f3c7a8322c9d30e7dc71d.tar.gz
Reimplement Zodiac control-send safely for word-oriented architectures.
This was a bug revealed by Debian porterbox testing. We used to use a cast from (char *) to (unsigned short *) that was problematic on word-oriented architectures like the PowerPC. Instead, memcpy the message data to a word array, which the compiler will create with correct alignment. All regression tests, cppcheck, and splint pass.
Diffstat (limited to 'driver_zodiac.c')
-rw-r--r--driver_zodiac.c11
1 files changed, 10 insertions, 1 deletions
diff --git a/driver_zodiac.c b/driver_zodiac.c
index 6c390b88..b1c9a966 100644
--- a/driver_zodiac.c
+++ b/driver_zodiac.c
@@ -396,11 +396,20 @@ static gps_mask_t zodiac_analyze(struct gps_device_t *session)
static ssize_t zodiac_control_send(struct gps_device_t *session,
char *msg, size_t len)
{
- unsigned short *shortwords = (unsigned short *)msg;
+ /*@-usedef -compdef@*/
+ unsigned short shortwords[256];
+
+#define min(x,y) ((x) < (y) ? x : y)
+ /*
+ * We used to just cast msg to an unsigned short pointer.
+ * This can fail on word-oriented achitectures like a SPARC.
+ */
+ memcpy((char *)shortwords, msg, min(sizeof(shortwords), len));
/* and if len isn't even, it's your own fault */
return zodiac_spew(session, shortwords[0], shortwords + 1,
(int)(len / 2 - 1));
+ /*@+usedef +compdef@*/
}
#endif /* CONTROLSEND_ENABLE */