I cannot get rid of the urge to sell a PVS-Studio license to the developer team of Intel Performance Primitives Library.

Of course, I'd like to have some sales in other Intel departments too, but the IPP developers seem closer to us. First, some of them live in Russia. Second, they are already using static analyzers in their work. Third, we already have some groundwork in this area. I mean that we already checked the IPP Samples project twice (first check, second check). It would be, of course, much more interesting to test the IPP library itself instead of the samples, but we don't have access to its source codes.

So, I'll resort to the standard method of advertising ourselves. We will continue to reanalyze IPP Samples from time to time to find new errors. It indicates that the PVS-Studio code analyzer is actively developing. But the greatest profit can be, of course, obtained through regular use of the analyzer, not single runs. Do not forget the capabilities of night runs and background analysis after compilation.

I will cite some of the errors detected by PVS-Studio v4.60. These are, of course, not all the odd fragments we've found. There are much more of them, but I cannot tell for sure if they have errors or not. At the same time, let it be the reason for IPP developers to install and try our tool. We have changed the trial model so that the tool now possesses its full functionality. So, you are welcome to try it.

Let's have a look at odd fragments in the IPP Samples code.

Case N1. Meaningless statement

AACStatus bsacdecSetNumChannels(Ipp32s channelConfiguration, AACDec *state) { state->com.m_channel_number = channelConfiguration; if (channelConfiguration == 7) { state->com.m_channel_number; } return AAC_OK; }

PVS-Studio's diagnostic message: V607 Ownerless expression 'state->com.m_channel_number'. aac_dec aac_dec_api_fp.c 1404

The "state->com.m_channel_number;" statement is very odd. An assignment or something else must be missing here.

Case N2. Filling the virtual method table

There are rather many places in IPP Samples where memory is allocated for classes through the malloc() function and initialized through the memset() function. Maybe there's nothing bad about it, but I'm discomforted by the fact that these classes have virtual methods. Thus, I suspect that the virtual method table might be spoiled and something will go wrong.

For example, the _MediaDataEx class contains virtual functions:

virtual bool TryStrongCasting(....) const; virtual bool TryWeakCasting(....) const;

And this is how an object of this class is created:

Status VC1Splitter::Init(SplitterParams& rInit) { MediaDataEx::_MediaDataEx *m_stCodes; ... m_stCodes = (MediaDataEx::_MediaDataEx *) ippsMalloc_8u( START_CODE_NUMBER*2*sizeof(Ipp32s)+ sizeof(MediaDataEx::_MediaDataEx)); ... memset(m_stCodes, 0, (START_CODE_NUMBER*2*sizeof(Ipp32s)+ sizeof(MediaDataEx::_MediaDataEx))); ... }

PVS-Studio's diagnostic message: V598 The 'memset' function is used to nullify the fields of '_MediaDataEx' class. Virtual method table will be damaged by this. vc1_spl umc_vc1_spl.cpp 131

I don't know if there is a problem here, but we'd better warn about it.

The same thing can be seen in the following places:

V598 The 'memset' function is used to nullify the fields of '_MediaDataEx' class. Virtual method table will be damaged by this. vc1_dec umc_vc1_video_decoder.cpp 641 False

V598 The 'memset' function is used to nullify the fields of 'AVS_DISASSEMBLING_CONTEXT' class. Virtual method table will be damaged by this. avs_enc umc_avs_enc_slice.cpp 45

V598 The 'memset' function is used to nullify the fields of 'AVS_DISASSEMBLING_CONTEXT' class. Virtual method table will be damaged by this. avs_enc umc_avs_enc_slice.cpp 29

V598 The 'memset' function is used to nullify the fields of 'AVS_DISASSEMBLING_CONTEXT' class. Virtual method table will be damaged by this. avs_enc umc_avs_enc_slice.cpp 22

V598 The 'memcpy' function is used to copy the fields of 'AVSVideoEncoderParams' class. Virtual method table will be damaged by this. avs_enc umc_avs_enc.cpp 115

V598 The 'memset' function is used to nullify the fields of 'AVS_DECODING_CONTEXT' class. Virtual method table will be damaged by this. avs_dec umc_avs_dec_slice_init.cpp 65

V598 The 'memset' function is used to nullify the fields of 'AVS_DEBLOCKING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 153

V598 The 'memset' function is used to nullify the fields of 'AVS_RECONSTRUCTING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 133

V598 The 'memset' function is used to nullify the fields of 'AVS_DEBLOCKING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 43

V598 The 'memset' function is used to nullify the fields of 'AVS_RECONSTRUCTING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 42

V598 The 'memset' function is used to nullify the fields of 'AVS_DECODING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 41

V598 The 'memset' function is used to nullify the fields of 'AVS_DEBLOCKING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 32

V598 The 'memset' function is used to nullify the fields of 'AVS_RECONSTRUCTING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 31

V598 The 'memset' function is used to nullify the fields of 'AVS_DECODING_CONTEXT' class. Virtual method table will be damaged by this. avs_common umc_avs_slice.cpp 30

Case N3. Checking pointers after use

We've found several fragments where a pointer is used first and then is checked for being a null pointer. Perhaps the pointer will never be null and the code works correctly all the time, but it's not good anyway.

For example:

VIDEO_DRV_CREATE_BUFFERS_FUNC(....) { ... VideoDrvVideoMemInfo* drv_vm = &(driver->m_VideoMemInfo); ... if ((NULL == driver) || (NULL == bufs)) { ERR_SET(VM_NULL_PTR, "null ptr"); } ... }

PVS-Studio's diagnostic message: V595 The 'driver' pointer was utilized before it was verified against nullptr. Check lines: 40, 46. video_renders drv.c 40

The pointer check here should be either moved up or removed at all if the "driver==NULL" condition is impossible.

Here are other identical code samples:

Ipp16s *pNewSpeech = encoderObj->stEncState.pSpeechPtrNew; if (NULL==encoderObj || NULL==src || NULL ==dst ) return APIGSMAMR_StsBadArgErr;

PVS-Studio's diagnostic message: V595 The 'encoderObj' pointer was utilized before it was verified against nullptr. Check lines: 296, 298. speech encgsmamr.c 296

m_pAVSCompressorParams = DynamicCast<AVSVideoEncoderParams> (pParams); ... m_qp = m_pAVSCompressorParams->m_iConstQuant; // check error(s) if (NULL == m_pAVSCompressorParams) return UMC_ERR_NULL_PTR;

PVS-Studio's diagnostic message: V595 The 'm_pAVSCompressorParams' pointer was utilized before it was verified against nullptr. Check lines: 88, 91. avs_enc umc_avs_enc_fusion_core.cpp 88

Case N4. Odd expressions with commas

There are a couple of fragments with odd commas ','. The first sample:

void GetIntraDCPredictors(VC1Context* pContext) { DCPred.DC[13] = pC->DCBlkPred[5].DC,QurrQuant; ... }

PVS-Studio's diagnostic message: V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. vc1_dec umc_vc1_dec_mb_com.cpp 370

It might be a misprint, or something is missing here.

The second sample:

V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. speech usc_dtmf.c 309

static int DTMF_16s(....) { ... for (i = pIppTDParams->dtmf_fs, j = 0; i < dtmf_frame_size+pIppTDParams->dtmf_fs, j < nbytes; i++, j++) }

PVS-Studio's diagnostic message: V521 Such expressions using the ',' operator are dangerous. Make sure the expression is correct. speech usc_dtmf.c 309

This is a more interesting example than the previous one. The logical condition seems to be written incorrectly. The condition must have looked as follows:

i < dtmf_frame_size+pIppTDParams->dtmf_fs && j < nbytes

Case N5. Odd implicit type conversion

class MeMV { public: MeMV(){}; MeMV(int a0){x = (Ipp16s)a0; y=(Ipp16s)a0;}; MeMV(int a0, int a1){x = (Ipp16s)a0; y=(Ipp16s)a1;}; ... } MeMV MePredictCalculatorVC1::GetPrediction8x8() { ... default: return false; ... }

PVS-Studio's diagnostic message: V601 The 'false' value becomes a class object. me umc_vec_prediction.cpp 754

The GetPrediction8x8() function returns the MeMV type. But in one branch, it returns the 'false' value. This value is implicitly cast to 'int' and the MeMV(int a0) constructor is called. I'm not sure, but there is something else to be returned in this code, or an exception should be thrown.

An identical implicit type conversion can be found here:

V601 The 'false' value becomes a class object. me umc_vec_prediction.cpp 717

Case N6. Undefined behavior

In very many places of IPP Samples, you can find constructs that cause undefined or unspecified behavior. I wrote about some of them in the previous post. Now we have found a whole lot of negative value shifts. I cannot tell for sure that it may cause some troubles, but I recommend considering this article: "Wade not in unknown waters. Part three" just in case.

In this file - ipp-samples-ub.txt - you can see where the potentially dangerous code is located.

Conclusion

Dear IPP and IPP Samples developers, we're waiting for your letters. We are ready to discuss and implement missing functionality in the PVS-Studio tool that prevents you from using it. We are also ready to implement diagnostic rules relevant to your project.

And all the rest I wish bugless code and invite to our twitter @Code_Analysis where we post links to interesting articles on C++, programming, static code analysis and the PVS-Studio tool.