diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2011-03-28 05:35:30 -0400 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2011-03-28 05:35:30 -0400 |
commit | 3e7fb419ed47a875888461776c3f4b6c54a16660 (patch) | |
tree | e24e3aecb2bc62e648cd70c452e946698effe24c | |
parent | a46c1a3e1b4ce370ecb68b5b3afb7f76297a4fd4 (diff) | |
download | gpsd-3e7fb419ed47a875888461776c3f4b6c54a16660.tar.gz |
Double-buffer to prevent a corrupted shm read from clobbbering the user copy.
-rw-r--r-- | libgps_shm.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/libgps_shm.c b/libgps_shm.c index e4f861ba..7cb63c96 100644 --- a/libgps_shm.c +++ b/libgps_shm.c @@ -56,6 +56,7 @@ int gps_shm_read(struct gps_data_t *gpsdata) { int before, after; struct shmexport_t *shared = (struct shmexport_t *)gpsdata->privdata; + struct gps_data_t noclobber; /* * Following block of instructions must not be reordered, otherwise @@ -70,14 +71,21 @@ int gps_shm_read(struct gps_data_t *gpsdata) */ before = shared->bookend1; barrier(); - (void)memcpy((void *)gpsdata, + (void)memcpy((void *)&noclobber, (void *)&shared->gpsdata, sizeof(struct gps_data_t)); barrier(); after = shared->bookend2; - /*@i1@*/gpsdata->privdata = shared; - return (before == after) ? (int)sizeof(struct gps_data_t) : 0; + if (before != after) + return 0; + else { + (void)memcpy((void *)gpsdata, + (void *)&noclobber, + sizeof(struct gps_data_t)); + /*@i1@*/gpsdata->privdata = shared; + return (int)sizeof(struct gps_data_t); + } } } |