Merge "prevent memory corruption by calling erase on unallocated vector" into tizen
[platform/core/uifw/dali-core.git] / dali / public-api / common / dali-vector.cpp
1 /*
2  * Copyright (c) 2014 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/public-api/common/dali-vector.h>
20
21 // EXTERNAL INCLUDES
22 #include <stdlib.h>
23 #include <memory.h>
24
25 namespace Dali
26 {
27
28 VectorBase::VectorBase()
29   : mData( NULL )
30 {
31 }
32
33 VectorBase::~VectorBase()
34 {
35 }
36
37 VectorBase::SizeType VectorBase::Capacity() const
38 {
39   SizeType capacity = 0;
40   if( mData )
41   {
42     SizeType* metadata = reinterpret_cast< SizeType* >( mData );
43     capacity = *(metadata - 2);
44   }
45   return capacity;
46 }
47
48
49 void VectorBase::Release()
50 {
51   if( mData )
52   {
53     // adjust pointer to real beginning
54     SizeType* metadata = reinterpret_cast< SizeType* >( mData );
55     // TODO would be nice to memset to a bitpattern to catch illegal use of container after release
56     // but that would require knowledge of the itemsize
57     free( metadata - 2 );
58     mData = 0;
59   }
60 }
61
62 void VectorBase::SetCount( SizeType count )
63 {
64   // someone can call Resize( 0 ) before ever populating the vector
65   if( mData )
66   {
67     SizeType* metadata = reinterpret_cast< SizeType* >( mData );
68     *(metadata - 1) = count;
69   }
70 }
71
72 void VectorBase::Reserve( SizeType capacity, SizeType elementSize )
73 {
74   SizeType oldCapacity = Capacity();
75   SizeType oldCount = Count();
76   if( capacity > oldCapacity )
77   {
78     const SizeType wholeAllocation = sizeof(SizeType) * 2 + capacity * elementSize;
79     void* wholeData = (void*)malloc( wholeAllocation );
80 #if defined( DEBUG_ENABLED )
81     // in debug build this will help identify a vector of uninitialized data
82     memset( wholeData, 0xaa, wholeAllocation );
83 #endif
84     SizeType* metaData = reinterpret_cast< SizeType* >( wholeData );
85     *metaData++ = capacity;
86     *metaData++ = oldCount;
87     if( mData )
88     {
89       // copy over the old data
90       memcpy( metaData, mData, oldCount * elementSize );
91       // release old buffer
92       Release();
93     }
94     mData = metaData;
95   }
96 }
97
98 void VectorBase::Copy( const VectorBase& vector, SizeType elementSize )
99 {
100   if( this != &vector )
101   {
102     // release old data
103     Release();
104     // reserve space based on source capacity
105     const SizeType capacity = vector.Capacity();
106     Reserve( capacity, elementSize );
107     // copy over whole data
108     const SizeType wholeAllocation = sizeof(SizeType) * 2 + capacity * elementSize;
109     SizeType* srcData = reinterpret_cast< SizeType* >( vector.mData );
110     SizeType* dstData = reinterpret_cast< SizeType* >( mData );
111     memcpy( dstData - 2, srcData - 2, wholeAllocation );
112   }
113 }
114
115 void VectorBase::Swap( VectorBase& vector )
116 {
117   // just swap the data pointers, metadata will swap as side effect
118   std::swap( mData, vector.mData );
119 }
120
121 void VectorBase::Erase( char* address, SizeType elementSize )
122 {
123   // erase can be called on an unallocated vector
124   if( mData )
125   {
126     char* startAddress = address + elementSize;
127     const char* endAddress = reinterpret_cast< char* >( mData ) + Count() * elementSize;
128     SizeType numberOfBytes = endAddress - startAddress;
129     // addresses overlap so use memmove
130     memmove( address, startAddress, numberOfBytes );
131     SetCount( Count() - 1 );
132   }
133 }
134
135 } // namespace Dali
136