diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2014-08-21 07:41:56 -0400 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2014-08-21 07:41:56 -0400 |
commit | 1e98a6b5a87db80f445f3c7a8322c9d30e7dc71d (patch) | |
tree | c3679383b5de6f3401a5456ef6be5be9d6ebe273 /driver_zodiac.c | |
parent | 517ac3dfb0934e1fa951c5a803069ff53f881726 (diff) | |
download | gpsd-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.c | 11 |
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 */ |