diff options
author | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2020-05-23 18:17:19 +0700 |
---|---|---|
committer | Vadim Yanitskiy <vyanitskiy@sysmocom.de> | 2020-05-23 19:26:58 +0700 |
commit | 93ad3fd9b9aed26a609551c06a80db0e276eb4f1 (patch) | |
tree | 10e66f12cd5093a32bc407d6be510b08f8af8b0a /src | |
parent | 0614e9333fb5072640ba9939a28ffc1588cfe5bd (diff) |
csn1: fix: never use enumerated types in codec structures
I faced a problem while working on EGPRS Packet Channel Request
coding support: the unit test I wrote for it was passing when
compiled with AddressSanitizer, but failing when compiled
without it o_O. Somehow this was observed only with GCC 10.
Here is a part the standard output diff for that unit test:
*** testEGPRSPktChReq ***
decode_egprs_pkt_ch_req(0x2b5) returns 0
- ==> One Phase Access
+ ==> unknown 0xdd5f4e00
decode_egprs_pkt_ch_req(0x14a) returns 0
- ==> One Phase Access
+ ==> unknown 0xdd5f4e00
decode_egprs_pkt_ch_req(0x428) returns 0
- ==> Short Access
+ ==> unknown 0xdd5f4e01
At the same time, debug output of the CSN.1 decoder looked fine.
So WYSINWYG (What You See Is *NOT* What You Get)! As it turned
out, this was happening because I used an enumerated type to
represent the sub-type of EGPRS Packet Channel Request.
typedef struct
{
EGPRS_PacketChannelRequestType_t Type; // <-- enum
EGPRS_PacketChannelRequestContent_t Content;
} EGPRS_PacketChannelRequest_t;
The problem is that length of an enumerated field, more precisely
the amount of bytes it takes in the memory, is compiler/machine
dependent. While the CSN.1 decoder assumes that the field holding
sequential number of the chosen element is one octet long, so its
address is getting casted to (guint8 *) and the value is written
to the first MSB.
// csnStreamDecoder(), case CSN_CHOICE:
pui8 = pui8DATA(data, pDescr->offset);
*pui8 = i; // [ --> xx .. .. .. ]
Let's make sure that none of the existing RLC/MAC definitions is
using enumerated types, and add a warning comment to CSN_CHOICE.
Affected CSN.1 definitions (unit test output adjusted):
- Additional_access_technologies_struct_t,
- Channel_Request_Description_t.
Change-Id: I917a40647480c6f6f3b0e68674ce9894379a9e7f
Diffstat (limited to 'src')
-rw-r--r-- | src/csn1.h | 6 | ||||
-rw-r--r-- | src/gsm_rlcmac.h | 4 |
2 files changed, 6 insertions, 4 deletions
@@ -493,9 +493,11 @@ gint16 csnStreamEncoder(csnStream_t* ar, const CSN_DESCR* pDescr, struct bitvec * The value of the address is called a selector. Up to 256 (UCHAR_MAX) unique * selectors can be handled, longer choice list would cause CSN_ERROR_IN_SCRIPT. * After unpacking, this value is then converted to the sequential number of the - * element in the union and stored in the UnionType variable. + * element in the union and stored in the UnionType variable (Par2). * Par1: C structure name - * Par2: C structure element name + * Par2: C structure field name holding sequential number of the chosen element. + * BEWARE! Never use an enumerated type here, because its length is + * compiler/machine dependent, while decoder would cast it to guint8. * Par3: address of an array of type CSN_ChoiceElement_t where all possible * values of the selector are provided, together with the selector * length expressed in bits and the address of the CSN_DESCR type diff --git a/src/gsm_rlcmac.h b/src/gsm_rlcmac.h index e9ae20ae..9d859f33 100644 --- a/src/gsm_rlcmac.h +++ b/src/gsm_rlcmac.h @@ -158,7 +158,7 @@ typedef struct { guint8 PEAK_THROUGHPUT_CLASS; guint8 RADIO_PRIORITY; - RLC_MODE_t RLC_MODE; + guint8 RLC_MODE; guint8 LLC_PDU_TYPE; guint16 RLC_OCTET_COUNT; } Channel_Request_Description_t; @@ -1245,7 +1245,7 @@ typedef enum typedef struct { - AccessTechnology_t Access_Technology_Type; + guint8 Access_Technology_Type; guint8 GMSK_Power_class; guint8 Eight_PSK_Power_class; } Additional_access_technologies_struct_t; |