Imagine, if you will, that you have 64-bits of data. From this 64-bits of data, you need to extract a nibble, which contains the value that you care about. Now, I’m sure you’re imagining an integer with some bitmasks to extract the data, which is a perfectly sane approach.

Tomasz inherited some code from his company’s German office. It took the approach of taking the 64-bits and storing the 64-bits in an eight element byte array. Then, it extracted the values from that array with code looking like this:

if ((app.xuc_Special_TRX[EMV_ADK_REFUND_BYTE] EMV_ADK_REFUND_NIBBLE) == EMV_ADK_REFUND_NO)
{
     ...
}

“What’s this?” Tomasz wondered. “This code couldn’t possibly compile… not unless the operator is hidden in the macro…”

#define  EMV_ADK_EMV_ADK_MANUAL_REVERSAL_BYTE         0   ///< byte   for configuration of manual reversal
#define  EMV_ADK_MANUAL_REVERSAL_NIBBLE       >> 4 & 0x0F ///< nibble for configuration of manual reversal
#define  EMV_ADK_REFUND_BYTE                  0           ///< byte   for configuration of refund
#define  EMV_ADK_REFUND_NIBBLE                & 0x0F      ///< nibble for configuration of refund

#define  EMV_ADK_EMV_ADK_RESERVATION_BYTE             1   ///< byte   for configuration of reservation
#define  EMV_ADK_RESERVATION_NIBBLE           >> 4 & 0x0F ///< nibble for configuration of reservation
#define  EMV_ADK_TIP_BYTE                     1           ///< byte   for configuration of tip (gratuity)
#define  EMV_ADK_TIP_NIBBLE                   & 0x0F      ///< nibble for configuration of tip (gratuity)

#define  EMV_ADK_REFERRAL_BYTE                2           ///< byte   for configuration of referral @n not used for contactless
#define  EMV_ADK_REFERRAL_NIBBLE              >> 4 & 0x0F ///< nibble for configuration of referral @n not used for contactless
#define  EMV_ADK_VOICEAUT_BYTE                2           ///< byte   for configuration of voice authorization @n not used for contactless
#define  EMV_ADK_VOICEAUT_NIBBLE              & 0x0F      ///< nibble for configuration of voice authorization @n not used for contactless

#define  EMV_ADK_RFU_MODE_BYTE                3           ///< byte   RFU
#define  EMV_ADK_RFU_MODE_NIBBLE              >> 4 & 0x0F ///< nibble RFU
#define  EMV_ADK_FALLBACK_AFTER_CVM_BYTE      3           ///< byte   for configuration of "fallback to magstripe after start of cardholder verification or early PIN entry allowed" @n not used for contactless
#define  EMV_ADK_FALLBACK_AFTER_CVM_NIBBLE    & 0x0F      ///< nibble for configuration of "fallback to magstripe after start of cardholder verification or early PIN entry allowed" @n not used for contactless

#define  EMV_ADK_IGNORE_CARD_ERROR_BYTE       4           ///< byte   for configuration of "ignore card error after issuer authorization"
#define  EMV_ADK_IGNORE_CARD_ERROR_NIBBLE     >> 4 & 0x0F ///< nibble for configuration of "ignore card error after issuer authorization"

The structure of the surrounding code makes it clear that there's no reason to store this data in an array- the offending developer chose an array over an integer. Further, we know that they know how to use bitmask operations and bitshift operations, so there's no reason to have written this code.

Since this is an array of bytes, each array index contains two values. Thus, EMV_ADK_REFUND_NIBBLE is but a bitshift away from EMV_ADK_MANUAL_RREVERSAL_NIBBLE. Just don’t try and understand what these macros do frrom where they’re used, and you’ll be fine. Oh, and also don’t accidentially mismatch them- if you use the wrong EMV_ADK_*_BYTE with the wrong EMV_ADK_*_NIBBLE you’ll get the wrong data back without any error. If you don’t do those two things, you’ll be fine.

[Advertisement] Manage IT infrastructure as code across all environments with Puppet. Puppet Enterprise now offers more control and insight, with role-based access control, activity logging and all-new Puppet Apps. Start your free trial today!