Created
October 15, 2016 10:28
-
-
Save RossBencina/3d75caa85293685eb3a55365b47954a5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// These are reduced test cases derived from a work-in-progress (non-production) code base. | |
// Can you spot the bugs that PVS-Studio found? | |
#include <atomic> | |
#include "catch.hpp" | |
/////////////////////////////////////////////////////////////////////////////// | |
// Bug #1 | |
class Test { // Dummy type for testing. | |
int x_; | |
public: | |
Test() : x_(0) {} | |
int x() const { return x_; } | |
}; | |
// The purpose of allocateObjectEtc() is to perform various initialization and | |
// allocate and return a Test instance (or return nullptr on error). | |
static Test *v688_allocateObjectEtc_BUG() | |
{ | |
// ... do work ... | |
Test *result = new Test(); | |
if( !result ){ | |
// ... cleanup work ... | |
return nullptr; | |
} | |
// ... do more work ... | |
return result; | |
} | |
TEST_CASE( "pvs-studio-eval/v688/bug", "[pvs-studio-eval] allocate an object" ) { | |
Test *t = v688_allocateObjectEtc_BUG(); | |
if (t) { | |
REQUIRE( t->x() == 0 ); | |
delete t; | |
} | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Bug #2 | |
// SharedDataBuffer is a header for buffers that are shared between threads | |
// with reference counting. Allocation is deferred via a lock-free queue. | |
// Note: In this test case the deallocation and refCount methods are not used. | |
struct SharedDataBuffer{ | |
typedef void (*DeallocateFunctionPtr)( SharedDataBuffer *buffer ); | |
union { | |
DeallocateFunctionPtr asyncDeallocFn; | |
void *next; // deallocted buffers get put on a lock-free queue | |
}; | |
std::atomic<std::size_t> refCount; | |
std::size_t dataCapacityBytes; // includes the entire allocated length of data | |
char data[1]; // data area. not necessarily null terminated | |
}; | |
struct ContainedType { | |
size_t field_a; | |
// ... | |
double field_z; | |
// ... | |
}; | |
// Allocate a SharedDataBuffer used to store ContainedType struct. | |
// You should call getContained_BUG() to extract a ContainedType ptr from a | |
// shared buffer allocated by this function. | |
static SharedDataBuffer *v119_compositeAllocation_BUG() | |
{ | |
size_t allocSize = sizeof(SharedDataBuffer) + sizeof(ContainedType); | |
SharedDataBuffer *result = reinterpret_cast<SharedDataBuffer*>(new (std::nothrow) char[allocSize]); | |
if (result) { | |
// ... init dealloc proc and refcount ... | |
result->dataCapacityBytes = sizeof(ContainedType); | |
} | |
return result; | |
} | |
ContainedType* getContained_BUG(SharedDataBuffer *buffer) | |
{ | |
return reinterpret_cast<ContainedType*>(&buffer->data[0]); | |
} | |
TEST_CASE( "pvs-studio-eval/v119", "[pvs-studio-eval] test composite allocation" ) { | |
SharedDataBuffer *b = v119_compositeAllocation_BUG(); | |
REQUIRE( b->dataCapacityBytes == sizeof(ContainedType) ); | |
ContainedType *c = getContained_BUG(b); | |
c->field_a = 0; | |
c->field_z = 1.0; | |
delete [] b; | |
} | |
/////////////////////////////////////////////////////////////////////////////// | |
// Bug #3 | |
void testFooFunction(int) | |
{ | |
// ... do stuff ... | |
} | |
TEST_CASE( "pvs-studio-eval/v524/test-foo-function", "[pvs-studio-eval] run parameterised tests on foo function" ) { | |
testFooFunction(1); | |
testFooFunction(2); | |
testFooFunction(3); | |
} | |
void testBarFunction(int) | |
{ | |
// ... do stuff ... | |
} | |
TEST_CASE( "pvs-studio-eval/v524/test-bar-function", "[pvs-studio-eval] run parameterised tests on bar function" ) { | |
testFooFunction(1); | |
testFooFunction(2); | |
testFooFunction(3); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment