Skip to content

Commit

Permalink
getbits*,setbits*: rewrite to better handle and report edge cases
Browse files Browse the repository at this point in the history
Change the bit position and lengths to be unsigned values. This avoids
having to check if they are negative, and makes it clear that these
functions are only intended to be used with non-negative bit positions
and lengths.

Check and report bit lengths that are out of range.

Better handle some edge cases, such as lengths being zero.

Avoid left shits of unsigned integers which is 'undefined behaviour'.
  • Loading branch information
ourairquality committed May 15, 2024
1 parent 2eaba97 commit 6f37fd3
Show file tree
Hide file tree
Showing 3 changed files with 189 additions and 93 deletions.
116 changes: 87 additions & 29 deletions src/rcvraw.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,49 +69,107 @@

#define SQR(x) ((x)*(x))

/* get two component bits ----------------------------------------------------*/
static uint32_t getbitu2(const uint8_t *buff, int p1, int l1, int p2, int l2)
/* Get two component bits ----------------------------------------------------*/
static uint32_t getbitu2(const uint8_t *buff, unsigned p1, unsigned l1,
unsigned p2, unsigned l2)
{
return (getbitu(buff,p1,l1)<<l2)+getbitu(buff,p2,l2);
if (l2>=32) return getbitu(buff,p2,l2);
if (l1+l2>32) trace(0,"getbitu2: l1=%u + l2=%u out of range\n",l1,l2);
return (getbitu(buff,p1,l1)<<l2) | getbitu(buff,p2,l2);
}
static int32_t getbits2(const uint8_t *buff, int p1, int l1, int p2, int l2)
static int32_t getbits2(const uint8_t *buff, unsigned p1, unsigned l1,
unsigned p2, unsigned l2)
{
if (getbitu(buff,p1,1))
return (int32_t)((getbits(buff,p1,l1)<<l2)+getbitu(buff,p2,l2));
else
return (int32_t)getbitu2(buff,p1,l1,p2,l2);
uint32_t bits=getbitu2(buff,p1,l1,p2,l2);
unsigned len=l1+l2;
if (len==0) {
/* Would need at least one bit for a sign, so emit a warning. */
trace(0,"getbits2: l1=%u + l2=%u out of range\n",l1,l2);
return 0;
}
if (len>=32) {
if (len>32) trace(0,"getbits2: len=%u out of range\n",len);
return (int32_t)bits;
}
/* Check the sign bit */
if (!(bits&(1u<<(len-1)))) return (int32_t)bits;
return (int32_t)(bits | (~0u<<len)); /* Extend sign */
}
/* get three component bits --------------------------------------------------*/
static uint32_t getbitu3(const uint8_t *buff, int p1, int l1, int p2, int l2,
int p3, int l3)

/* Get three component bits --------------------------------------------------*/
static uint32_t getbitu3(const uint8_t *buff, int p1, unsigned l1,
int p2, unsigned l2, int p3, unsigned l3)
{
return (getbitu(buff,p1,l1)<<(l2+l3))+(getbitu(buff,p2,l2)<<l3)+
getbitu(buff,p3,l3);
if (l3>=32) return getbitu(buff,p3,l3);

if (l2+l3>=32) {
if (l2+l3>32) trace(0,"getbitu3: l2=%u + l3=%u out of range\n",l2,l3);
return (getbitu(buff,p2,l2)<<l3) | getbitu(buff,p3,l3);
}

if (l1+l2+l3>32) trace(0,"getbitu3: l1=%u + l2=%u + l3=%u out of range\n",l1,l2,l3);

return (getbitu(buff,p1,l1)<<(l2+l3)) | (getbitu(buff,p2,l2)<<l3) |
getbitu(buff,p3,l3);
}
static int32_t getbits3(const uint8_t *buff, int p1, int l1, int p2, int l2,
int p3, int l3)

static int32_t getbits3(const uint8_t *buff, unsigned p1, unsigned l1,
unsigned p2, unsigned l2, unsigned p3, unsigned l3)
{
if (getbitu(buff,p1,1))
return (int32_t)((getbits(buff,p1,l1)<<(l2+l3))+
(getbitu(buff,p2,l2)<<l3)+getbitu(buff,p3,l3));
else
return (int32_t)getbitu3(buff,p1,l1,p2,l2,p3,l3);
uint32_t bits=getbitu3(buff,p1,l1,p2,l2,p3,l3);
unsigned len=l1+l2+l3;
if (len==0) {
/* Would need at least one bit for a sign, so emit a warning. */
trace(0,"getbits3: l1=%u + l2=%u + l3=%u out of range\n",l1,l2,l3);
return 0;
}
if (len>=32) {
if (len>32) trace(0,"getbits3: len=%u out of range\n",len);
return (int32_t)bits;
}
/* Check the sign bit */
if (!(bits&(1u<<(len-1)))) return (int32_t)bits;
return (int32_t)(bits|(~0u<<len)); /* Extend sign */
}
/* merge two components ------------------------------------------------------*/
static uint32_t merge_two_u(uint32_t a, uint32_t b, int n)

/* Merge two components ------------------------------------------------------*/
static uint32_t merge_two_u(uint32_t a, uint32_t b, unsigned n)
{
return (a<<n)+b;
if (n>=32) {
if (n>32) trace(0,"merge_two_u: n=%u out of range\n",n);
return b;
}
if (((a<<n)>>n)!=a) {
trace(0,"merge_two_u: a=%x n=%u overflow\n",a,n);
}
if (((b>>n)<<n)!=0) {
trace(0, "merge_two_u: b=%x n=%u overflow\n",b,n);
}
return (a<<n)|b;
}
static int32_t merge_two_s(int32_t a, uint32_t b, int n)
static int32_t merge_two_s(int32_t a, uint32_t b, unsigned n)
{
return (int32_t)((a<<n)+b);
if (n>=32) {
if (n>32) trace(0,"merge_two_s: n=%u out of range\n",n);
return b;
}
if (((int32_t)((uint32_t)a<<n)>>n)!=a) {
trace(0,"merge_two_s: a=%x n=%u overflow\n",a,n);
}
if ((((uint32_t)b>>n)<<n)!=0) {
trace(0, "merge_two_s: b=%x n=%u overflow\n",b,n);
}
return (int32_t)((uint32_t)a<<n)|b;
}
/* get sign-magnitude bits ---------------------------------------------------*/
static double getbitg(const uint8_t *buff, int pos, int len)

/* Get sign-magnitude bits ---------------------------------------------------*/
static double getbitg(const uint8_t *buff, unsigned pos, unsigned len)
{
double value=getbitu(buff,pos+1,len-1);
return getbitu(buff,pos,1)?-value:value;
if (len==0) return 0.0;
double value=getbitu(buff,pos+1,len-1);
return getbitu(buff,pos,1)?-value:value;
}

/* decode NavIC/IRNSS ephemeris ----------------------------------------------*/
static int decode_irn_eph(const uint8_t *buff, eph_t *eph)
{
Expand Down
152 changes: 95 additions & 57 deletions src/rtkcmn.c
Original file line number Diff line number Diff line change
Expand Up @@ -828,104 +828,142 @@ extern int getcodepri(int sys, uint8_t code, const char *opt)
/* search code priority */
return (p=strchr(codepris[i][j],obs[1]))?14-(int)(p-codepris[i][j]):0;
}
/* extract unsigned/signed bits ------------------------------------------------
/* Extract unsigned/signed bits ------------------------------------------------
* extract unsigned/signed bits from byte data
* args : uint8_t *buff I byte data
* int pos I bit position from start of data (bits)
* int len I bit length (bits) (len<=32)
* args : uint8_t *buff I byte data
* unsigned pos I bit position from start of data (bits)
* unsigned len I bit length (bits) (len<=32)
* return : extracted unsigned/signed bits
*-----------------------------------------------------------------------------*/
extern uint32_t getbitu(const uint8_t *buff, int pos, int len)
{
uint32_t bits=0;
int i;
for (i=pos;i<pos+len;i++) bits=(bits<<1)+((buff[i/8]>>(7-i%8))&1u);
return bits;
}
extern int32_t getbits(const uint8_t *buff, int pos, int len)
{
uint32_t bits=getbitu(buff,pos,len);
if (len<=0||32<=len||!(bits&(1u<<(len-1)))) return (int32_t)bits;
return (int32_t)(bits|(~0u<<len)); /* extend sign */
}
/* set unsigned/signed bits ----------------------------------------------------
extern uint32_t getbitu(const uint8_t *buff, unsigned pos, unsigned len)
{
if (len > 32) trace(0, "getbitu: len=%u out of range\n", len);
uint32_t bits = 0;
for (unsigned i = pos; i < pos + len; i++)
bits = (bits << 1) | ((buff[i / 8] >> (7 - i % 8)) & 1u);
return bits;
}
extern int32_t getbits(const uint8_t *buff, unsigned pos, unsigned len)
{
uint32_t bits = getbitu(buff, pos, len);
if (len == 0) {
/* Would need at least one bit for a sign, so emit a warning. */
trace(0, "getbits: len=%u out of range\n", len);
return 0;
}
if (len >= 32) {
if (len > 32) trace(0, "getbits: len=%u out of range\n", len);
return (int32_t)bits;
}
/* Check the sign bit */
if (!(bits & (1u << (len - 1)))) return (int32_t)bits;
return (int32_t)(bits | (~0u << len)); /* Extend sign */
}
/* Set unsigned/signed bits ----------------------------------------------------
* set unsigned/signed bits to byte data
* args : uint8_t *buff IO byte data
* int pos I bit position from start of data (bits)
* int len I bit length (bits) (len<=32)
* args : uint8_t *buff IO byte data
* unsigned pos I bit position from start of data (bits)
* unsigned len I bit length (bits) (len<=32)
* [u]int32_t data I unsigned/signed data
* return : none
*-----------------------------------------------------------------------------*/
extern void setbitu(uint8_t *buff, int pos, int len, uint32_t data)
extern void setbitu(uint8_t *buff, unsigned pos, unsigned len, uint32_t data)
{
if (len==0||32<len) {
trace(2,"Warning setbitu len %u out of range for data %x\n",len,data);
return;
}
uint32_t mask=1u<<(len-1);
int i;
if (len<=0||32<len) return;
for (i=pos;i<pos+len;i++,mask>>=1) {
if (data&mask) buff[i/8]|=1u<<(7-i%8); else buff[i/8]&=~(1u<<(7-i%8));
for (int i=pos;i<pos+len;i++,mask>>=1) {
if (data&mask)
buff[i/8]|=1u<<(7-i%8);
else
buff[i/8]&=~(1u<<(7-i%8));
}
}
extern void setbits(uint8_t *buff, int pos, int len, int32_t data)
{
if (data<0) data|=1<<(len-1); else data&=~(1<<(len-1)); /* set sign bit */
setbitu(buff,pos,len,(uint32_t)data);
extern void setbits(uint8_t *buff, unsigned pos, unsigned len, int32_t data) {
if (len==0||32<len) {
trace(2,"Warning setbits len %u out of range for data %x\n",len,data);
return;
}

uint32_t limit=1u<<(len-1);
if (len<32) {
/* Clamp the data in the case it overflows the len */
if (data>=0) {
if ((uint32_t)data>=limit) {
trace(2,"Warning setbits overflow for data %x len %u\n",data,len);
/* Clamp */
data=limit-1;
trace(2," clamped to %x\n",data);
}
} else if ((uint32_t)(-data)>limit) {
trace(2,"Warning setbits underflow for data %x len %u\n",data,len);
/* Clamp */
data=-limit;
trace(2," clamped to %x\n",data);
}
}

uint32_t udata = data;
if (data<0)
udata|=limit; /* Set sign bit */
else
udata&=~limit; /* Clear sign bit */
setbitu(buff,pos,len,udata);
}
/* crc-32 parity ---------------------------------------------------------------
* compute crc-32 parity for novatel raw
* args : uint8_t *buff I data
* int len I data length (bytes)
* args : uint8_t *buff I data
* unsigned len I data length (bytes)
* return : crc-32 parity
* notes : see NovAtel OEMV firmware manual 1.7 32-bit CRC
*-----------------------------------------------------------------------------*/
extern uint32_t rtk_crc32(const uint8_t *buff, int len)
extern uint32_t rtk_crc32(const uint8_t *buff, unsigned len)
{
trace(4,"rtk_crc32: len=%u\n",len);
uint32_t crc=0;
int i,j;

trace(4,"rtk_crc32: len=%d\n",len);

for (i=0;i<len;i++) {
for (unsigned i=0;i<len;i++) {
crc^=buff[i];
for (j=0;j<8;j++) {
if (crc&1) crc=(crc>>1)^POLYCRC32; else crc>>=1;
for (int j=0;j<8;j++) {
if (crc&1)
crc=(crc>>1)^POLYCRC32;
else
crc>>=1;
}
}
return crc;
}
/* crc-24q parity --------------------------------------------------------------
* compute crc-24q parity for sbas, rtcm3
* args : uint8_t *buff I data
* int len I data length (bytes)
* args : uint8_t *buff I data
* unsigned len I data length (bytes)
* return : crc-24Q parity
* notes : see reference [2] A.4.3.3 Parity
*-----------------------------------------------------------------------------*/
extern uint32_t rtk_crc24q(const uint8_t *buff, int len)
extern uint32_t rtk_crc24q(const uint8_t *buff, unsigned len)
{
trace(4, "rtk_crc24q: len=%u\n",len);

uint32_t crc=0;
int i;

trace(4,"rtk_crc24q: len=%d\n",len);

for (i=0;i<len;i++) crc=((crc<<8)&0xFFFFFF)^tbl_CRC24Q[(crc>>16)^buff[i]];
for (unsigned i=0;i<len;i++)
crc=((crc<<8)&0xFFFFFF)^tbl_CRC24Q[(crc>>16)^buff[i]];
return crc;
}
/* crc-16 parity ---------------------------------------------------------------
* compute crc-16 parity for binex, nvs
* args : uint8_t *buff I data
* int len I data length (bytes)
* args : uint8_t *buff I data
* unsigned len I data length (bytes)
* return : crc-16 parity
* notes : see reference [10] A.3.
*-----------------------------------------------------------------------------*/
extern uint16_t rtk_crc16(const uint8_t *buff, int len)
extern uint16_t rtk_crc16(const uint8_t *buff, unsigned len)
{
trace(4, "rtk_crc16: len=%d\n",len);

uint16_t crc=0;
int i;

trace(4,"rtk_crc16: len=%d\n",len);

for (i=0;i<len;i++) {
for (unsigned i=0;i<len;i++)
crc=(crc<<8)^tbl_CRC16[((crc>>8)^buff[i])&0xFF];
}
return crc;
}
/* decode navigation data word -------------------------------------------------
Expand Down
14 changes: 7 additions & 7 deletions src/rtklib.h
Original file line number Diff line number Diff line change
Expand Up @@ -1616,13 +1616,13 @@ EXPORT int tle_pos(gtime_t time, const char *name, const char *satno,
double *rs);

/* receiver raw data functions -----------------------------------------------*/
EXPORT uint32_t getbitu(const uint8_t *buff, int pos, int len);
EXPORT int32_t getbits(const uint8_t *buff, int pos, int len);
EXPORT void setbitu(uint8_t *buff, int pos, int len, uint32_t data);
EXPORT void setbits(uint8_t *buff, int pos, int len, int32_t data);
EXPORT uint32_t rtk_crc32 (const uint8_t *buff, int len);
EXPORT uint32_t rtk_crc24q(const uint8_t *buff, int len);
EXPORT uint16_t rtk_crc16 (const uint8_t *buff, int len);
EXPORT uint32_t getbitu(const uint8_t *buff, unsigned pos, unsigned len);
EXPORT int32_t getbits(const uint8_t *buff, unsigned pos, unsigned len);
EXPORT void setbitu(uint8_t *buff, unsigned pos, unsigned len, uint32_t data);
EXPORT void setbits(uint8_t *buff, unsigned pos, unsigned len, int32_t data);
EXPORT uint32_t rtk_crc32(const uint8_t *buff, unsigned len);
EXPORT uint32_t rtk_crc24q(const uint8_t *buff, unsigned len);
EXPORT uint16_t rtk_crc16(const uint8_t *buff, unsigned len);
EXPORT int decode_word (uint32_t word, uint8_t *data);
EXPORT int decode_frame(const uint8_t *buff, eph_t *eph, alm_t *alm,
double *ion, double *utc);
Expand Down

0 comments on commit 6f37fd3

Please sign in to comment.