| File: | src/air/heap.c |
| Location: | line 152, column 3 |
| Description: | Null pointer argument in call to memory copy function |
| 1 | /* | |||||
| 2 | Teem: Tools to process and visualize scientific data and images . | |||||
| 3 | Copyright (C) 2010 Thomas Schultz | |||||
| 4 | ||||||
| 5 | This library is free software; you can redistribute it and/or | |||||
| 6 | modify it under the terms of the GNU Lesser General Public License | |||||
| 7 | (LGPL) as published by the Free Software Foundation; either | |||||
| 8 | version 2.1 of the License, or (at your option) any later version. | |||||
| 9 | The terms of redistributing and/or modifying this software also | |||||
| 10 | include exceptions to the LGPL that facilitate static linking. | |||||
| 11 | ||||||
| 12 | This library is distributed in the hope that it will be useful, | |||||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| 15 | Lesser General Public License for more details. | |||||
| 16 | ||||||
| 17 | You should have received a copy of the GNU Lesser General Public License | |||||
| 18 | along with this library; if not, write to Free Software Foundation, Inc., | |||||
| 19 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| 20 | */ | |||||
| 21 | ||||||
| 22 | #include "air.h" | |||||
| 23 | #include <string.h> | |||||
| 24 | ||||||
| 25 | /* internal helper routines */ | |||||
| 26 | /* restore heap property by pulling a single node up the tree */ | |||||
| 27 | static void upheap(airHeap *h, unsigned int i) { | |||||
| 28 | while (i) { | |||||
| 29 | unsigned int parent = (i-1)/2; | |||||
| 30 | if (h->key[h->idx[parent]] > h->key[h->idx[i]]) { /* swap */ | |||||
| 31 | unsigned int tmp = h->idx[parent]; | |||||
| 32 | h->idx[parent] = h->idx[i]; | |||||
| 33 | h->idx[i] = tmp; | |||||
| 34 | h->invidx[h->idx[i]] = i; | |||||
| 35 | h->invidx[h->idx[parent]] = parent; | |||||
| 36 | i = parent; | |||||
| 37 | } else | |||||
| 38 | i = 0; /* break loop */ | |||||
| 39 | } | |||||
| 40 | } | |||||
| 41 | ||||||
| 42 | /* restore heap property by pushing a single node down the tree */ | |||||
| 43 | static void downheap (airHeap *h, unsigned int i) { | |||||
| 44 | unsigned int len = h->key_a->len; | |||||
| 45 | while (1) { | |||||
| 46 | unsigned int left = 2*i+1; | |||||
| 47 | unsigned int right = 2*i+2; | |||||
| 48 | unsigned int minidx = 0; | |||||
| 49 | double minval = 0; | |||||
| 50 | if (left>=len) | |||||
| 51 | return; | |||||
| 52 | if ((right>=len) || | |||||
| 53 | (h->key[h->idx[left]] < h->key[h->idx[right]])) { | |||||
| 54 | minidx = left; | |||||
| 55 | minval = h->key[h->idx[left]]; | |||||
| 56 | } else { | |||||
| 57 | minidx = right; | |||||
| 58 | minval = h->key[h->idx[right]]; | |||||
| 59 | } | |||||
| 60 | if (h->key[h->idx[i]] > minval) { /* swap */ | |||||
| 61 | unsigned int tmp = h->idx[i]; | |||||
| 62 | h->idx[i] = h->idx[minidx]; | |||||
| 63 | h->idx[minidx] = tmp; | |||||
| 64 | h->invidx[h->idx[i]] = i; | |||||
| 65 | h->invidx[h->idx[minidx]] = minidx; | |||||
| 66 | i = minidx; | |||||
| 67 | } else | |||||
| 68 | return; | |||||
| 69 | } | |||||
| 70 | } | |||||
| 71 | ||||||
| 72 | /* Restore heap property "from scratch" (without any prior assumptions). | |||||
| 73 | * Works in a bottom-up manner, which is more efficient than top-down */ | |||||
| 74 | static void heapify (airHeap *h) { | |||||
| 75 | unsigned int len = h->key_a->len; | |||||
| 76 | int maxi = len/2-1, i; /* above maxi, downheap has no effect */ | |||||
| 77 | for (i=maxi; i>=0; i--) { | |||||
| 78 | downheap(h, i); | |||||
| 79 | } | |||||
| 80 | } | |||||
| 81 | ||||||
| 82 | /* Tries to increase or decrease the length of h. returns 0 upon success. */ | |||||
| 83 | static int heapLenIncr (airHeap *h, int delta) { | |||||
| 84 | unsigned int oldlen=h->key_a->len; | |||||
| 85 | unsigned int newlen=oldlen+delta; | |||||
| 86 | if (delta==0) | |||||
| 87 | return 0; | |||||
| 88 | airArrayLenIncr(h->key_a, delta); | |||||
| 89 | if (h->data_a!=NULL((void*)0)) airArrayLenIncr(h->data_a, delta); | |||||
| 90 | airArrayLenIncr(h->idx_a, delta); | |||||
| 91 | airArrayLenIncr(h->invidx_a, delta); | |||||
| 92 | if (h->key_a->len<newlen || (h->data_a!=NULL((void*)0) && h->data_a->len<newlen) || | |||||
| 93 | h->idx_a->len<newlen || h->invidx_a->len<newlen) { | |||||
| 94 | /* Error. Try to undo changes and return error code. */ | |||||
| 95 | if (h->key_a->len>oldlen) airArrayLenSet(h->key_a, oldlen); | |||||
| 96 | if (h->data_a!=NULL((void*)0) && h->data_a->len>oldlen) | |||||
| 97 | airArrayLenSet(h->data_a, oldlen); | |||||
| 98 | if (h->idx_a->len>oldlen) airArrayLenSet(h->idx_a, oldlen); | |||||
| 99 | if (h->invidx_a->len>oldlen) airArrayLenSet(h->invidx_a, oldlen); | |||||
| 100 | return 1; | |||||
| 101 | } | |||||
| 102 | return 0; | |||||
| 103 | } | |||||
| 104 | ||||||
| 105 | /* Creates a new heap, returning NULL upon error. If additional data | |||||
| 106 | * is to be stored with each node, dataUnit needs to be set to the | |||||
| 107 | * number of data bytes needed per element. incr is used for dynamic | |||||
| 108 | * memory allocation (an additional number of incr elements are | |||||
| 109 | * allocated each time the heap grows past its current capacity). | |||||
| 110 | */ | |||||
| 111 | airHeap *airHeapNew(size_t dataUnit, unsigned int incr) { | |||||
| 112 | airHeap *h; | |||||
| 113 | airPtrPtrUnion appu; | |||||
| 114 | h = AIR_CALLOC(1, airHeap)(airHeap*)(calloc((1), sizeof(airHeap))); | |||||
| 115 | if (h==NULL((void*)0)) { | |||||
| 116 | return NULL((void*)0); | |||||
| 117 | } | |||||
| 118 | ||||||
| 119 | appu.d = &h->key; | |||||
| 120 | h->key_a = airArrayNew(appu.v, NULL((void*)0), sizeof(double), incr); | |||||
| 121 | if (dataUnit>0) { /* data is optional */ | |||||
| 122 | h->data_a = airArrayNew(&h->data, NULL((void*)0), dataUnit, incr); | |||||
| 123 | } | |||||
| 124 | appu.ui = &h->idx; | |||||
| 125 | h->idx_a = airArrayNew(appu.v, NULL((void*)0), sizeof(unsigned int), incr); | |||||
| 126 | appu.ui = &h->invidx; | |||||
| 127 | h->invidx_a = airArrayNew(appu.v, NULL((void*)0), sizeof(unsigned int), incr); | |||||
| 128 | ||||||
| 129 | if (h->key_a==NULL((void*)0) || (dataUnit>0 && h->data_a==NULL((void*)0)) || h->idx_a==NULL((void*)0) || | |||||
| 130 | h->invidx_a==NULL((void*)0)) { /* allocation failed (partly) */ | |||||
| 131 | airHeapNix(h); | |||||
| 132 | return NULL((void*)0); | |||||
| 133 | } | |||||
| 134 | return h; | |||||
| 135 | } | |||||
| 136 | ||||||
| 137 | /* Same as airHeapNew, but initializes the new heap with the keys from key | |||||
| 138 | * and the optional data from data. If data is non-NULL, it needs to | |||||
| 139 | * have the same length as key, or this function will fail. The incr | |||||
| 140 | * field of the heap is copied from key (rather than data). | |||||
| 141 | */ | |||||
| 142 | airHeap *airHeapFromArray(const airArray *key, const airArray *data) { | |||||
| 143 | airHeap *h; | |||||
| 144 | unsigned int i; | |||||
| 145 | if (key==NULL((void*)0) || (data!=NULL((void*)0) && data->len!=key->len)) | |||||
| ||||||
| 146 | return NULL((void*)0); /* unusable input */ | |||||
| 147 | h = airHeapNew((data==NULL((void*)0))?0:data->unit, key->incr); | |||||
| 148 | if (heapLenIncr (h, key->len)) { /* could not allocate memory */ | |||||
| 149 | airHeapNix(h); | |||||
| 150 | return NULL((void*)0); | |||||
| 151 | } | |||||
| 152 | memcpy(h->key, key->data, key->len*sizeof(double))__builtin___memcpy_chk (h->key, key->data, key->len* sizeof(double), __builtin_object_size (h->key, 0)); | |||||
| ||||||
| 153 | if (h->data_a!=NULL((void*)0)) memcpy(h->data, data->data, data->len*data->unit)__builtin___memcpy_chk (h->data, data->data, data->len *data->unit, __builtin_object_size (h->data, 0)); | |||||
| 154 | for (i=0; i<key->len; i++) { /* initialize indices to identity */ | |||||
| 155 | h->idx[i]=i; | |||||
| 156 | h->invidx[i]=i; | |||||
| 157 | } | |||||
| 158 | heapify(h); | |||||
| 159 | return h; | |||||
| 160 | } | |||||
| 161 | ||||||
| 162 | /* Frees all memory associated with the heap and its data */ | |||||
| 163 | airHeap *airHeapNix(airHeap *h) { | |||||
| 164 | if (h!=NULL((void*)0)) { | |||||
| 165 | airArrayNuke(h->key_a); | |||||
| 166 | if (h->data_a!=NULL((void*)0)) airArrayNuke(h->data_a); | |||||
| 167 | airArrayNuke(h->idx_a); | |||||
| 168 | airArrayNuke(h->invidx_a); | |||||
| 169 | free(h); | |||||
| 170 | } | |||||
| 171 | return NULL((void*)0); | |||||
| 172 | } | |||||
| 173 | ||||||
| 174 | /* Returns the number of elements that are currently in heap h | |||||
| 175 | * (or 0 if h==NULL) */ | |||||
| 176 | unsigned int airHeapLength(const airHeap *h) { | |||||
| 177 | if (h!=NULL((void*)0)) { | |||||
| 178 | return h->key_a->len; | |||||
| 179 | } else | |||||
| 180 | return 0; | |||||
| 181 | } | |||||
| 182 | ||||||
| 183 | /* Inserts a key into the heap. data is copied over (deep copy) when the | |||||
| 184 | * heap was initialized to hold additional data. Otherwise, it is ignored. | |||||
| 185 | * | |||||
| 186 | * Returns the new number of elements in h. | |||||
| 187 | * Upon error, this can be the same as the old length. */ | |||||
| 188 | unsigned int airHeapInsert(airHeap *h, double key, const void *data) { | |||||
| 189 | unsigned int oldlen; | |||||
| 190 | if (h==NULL((void*)0)) return 0; | |||||
| 191 | oldlen = h->key_a->len; | |||||
| 192 | /* make space for the new element */ | |||||
| 193 | if (heapLenIncr(h, 1)) | |||||
| 194 | return oldlen; | |||||
| 195 | h->key[oldlen]=key; | |||||
| 196 | if (h->data_a!=NULL((void*)0) && data!=NULL((void*)0)) { | |||||
| 197 | memcpy((char*)h->data_a->data+oldlen*h->data_a->unit, data,__builtin___memcpy_chk ((char*)h->data_a->data+oldlen*h ->data_a->unit, data, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+oldlen*h->data_a->unit, 0 )) | |||||
| 198 | h->data_a->unit)__builtin___memcpy_chk ((char*)h->data_a->data+oldlen*h ->data_a->unit, data, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+oldlen*h->data_a->unit, 0 )); | |||||
| 199 | } | |||||
| 200 | h->idx[oldlen]=oldlen; | |||||
| 201 | h->invidx[oldlen]=oldlen; | |||||
| 202 | upheap(h,oldlen); /* restore the heap property */ | |||||
| 203 | return oldlen+1; | |||||
| 204 | } | |||||
| 205 | ||||||
| 206 | /* Merges the second heap into the first. Returns the new length of first, | |||||
| 207 | * or zero upon error. */ | |||||
| 208 | unsigned int airHeapMerge(airHeap *first, const airHeap *second) { | |||||
| 209 | unsigned int first_len, second_len, i; | |||||
| 210 | if (first==NULL((void*)0) || second==NULL((void*)0)) | |||||
| 211 | return 0; | |||||
| 212 | if ((first->data_a==NULL((void*)0)) ^ (second->data_a==NULL((void*)0))) | |||||
| 213 | return 0; /* incompatible data */ | |||||
| 214 | if (first->data_a!=NULL((void*)0) && | |||||
| 215 | (first->data_a->unit!=second->data_a->unit)) | |||||
| 216 | return 0; /* incompatible data */ | |||||
| 217 | /* make sufficient space in first */ | |||||
| 218 | first_len = first->key_a->len; | |||||
| 219 | second_len = second->key_a->len; | |||||
| 220 | if (heapLenIncr(first, second_len)) | |||||
| 221 | return 0; | |||||
| 222 | /* concatenate and heapify */ | |||||
| 223 | memcpy(first->key+first_len, second->key, second_len*sizeof(double))__builtin___memcpy_chk (first->key+first_len, second->key , second_len*sizeof(double), __builtin_object_size (first-> key+first_len, 0)); | |||||
| 224 | if (first->data_a!=NULL((void*)0)) | |||||
| 225 | memcpy((char*)first->data_a->data+first_len*first->data_a->unit,__builtin___memcpy_chk ((char*)first->data_a->data+first_len *first->data_a->unit, second->data_a->data, second_len *second->data_a->unit, __builtin_object_size ((char*)first ->data_a->data+first_len*first->data_a->unit, 0)) | |||||
| 226 | second->data_a->data,second_len*second->data_a->unit)__builtin___memcpy_chk ((char*)first->data_a->data+first_len *first->data_a->unit, second->data_a->data, second_len *second->data_a->unit, __builtin_object_size ((char*)first ->data_a->data+first_len*first->data_a->unit, 0)); | |||||
| 227 | for (i=0; i<second_len; i++) { | |||||
| 228 | first->idx[first_len+i] = first_len+second->idx[i]; | |||||
| 229 | first->invidx[first->idx[first_len+i]]=first_len+i; | |||||
| 230 | } | |||||
| 231 | heapify(first); | |||||
| 232 | return first_len+second_len; | |||||
| 233 | } | |||||
| 234 | ||||||
| 235 | /* Returns the key of the front element in the heap and optionally copies the | |||||
| 236 | * associated data to *data. Does not modify the heap. */ | |||||
| 237 | double airHeapFrontPeek(const airHeap *h, void *data) { | |||||
| 238 | if (h==NULL((void*)0) || h->key_a->len==0) | |||||
| 239 | return 0.0; | |||||
| 240 | if (data!=NULL((void*)0) && h->data_a!=NULL((void*)0)) | |||||
| 241 | memcpy(data, (char*)h->data_a->data+h->idx[0]*h->data_a->unit,__builtin___memcpy_chk (data, (char*)h->data_a->data+h-> idx[0]*h->data_a->unit, h->data_a->unit, __builtin_object_size (data, 0)) | |||||
| 242 | h->data_a->unit)__builtin___memcpy_chk (data, (char*)h->data_a->data+h-> idx[0]*h->data_a->unit, h->data_a->unit, __builtin_object_size (data, 0)); | |||||
| 243 | return h->key[h->idx[0]]; | |||||
| 244 | } | |||||
| 245 | ||||||
| 246 | /* Same as airHeapFrontPeek, but additionally removes the front element. */ | |||||
| 247 | double airHeapFrontPop(airHeap *h, void *data) { | |||||
| 248 | double retval = airHeapFrontPeek(h, data); | |||||
| 249 | if (h!=NULL((void*)0) && h->key_a->len>0) { | |||||
| 250 | airHeapRemove(h, h->idx[0]); | |||||
| 251 | } | |||||
| 252 | return retval; | |||||
| 253 | } | |||||
| 254 | ||||||
| 255 | /* Assigns a new key (and optionally, new data) to the front element and | |||||
| 256 | * re-sorts the heap if necessary. */ | |||||
| 257 | int airHeapFrontUpdate(airHeap *h, double newKey, const void *newData) { | |||||
| 258 | if (h==NULL((void*)0) || h->key_a->len==0) | |||||
| 259 | return 1; | |||||
| 260 | if (newData!=NULL((void*)0) && h->data_a!=NULL((void*)0)) | |||||
| 261 | memcpy((char*)h->data_a->data+h->idx[0]*h->data_a->unit, newData,__builtin___memcpy_chk ((char*)h->data_a->data+h->idx [0]*h->data_a->unit, newData, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+h->idx[0]*h->data_a-> unit, 0)) | |||||
| 262 | h->data_a->unit)__builtin___memcpy_chk ((char*)h->data_a->data+h->idx [0]*h->data_a->unit, newData, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+h->idx[0]*h->data_a-> unit, 0)); | |||||
| 263 | h->key[h->idx[0]]=newKey; | |||||
| 264 | downheap(h, 0); | |||||
| 265 | return 0; | |||||
| 266 | } | |||||
| 267 | ||||||
| 268 | /* The following functions provide advanced functionality and should | |||||
| 269 | * not be required in most applications. */ | |||||
| 270 | ||||||
| 271 | /* airHeapFind returns 0 if an element is found whose data is bitwise | |||||
| 272 | * equal to the given data, and sets *ai to the index of this | |||||
| 273 | * element. If more than one element matches the data, an arbitrary | |||||
| 274 | * one of them is returned. The index can be used with airHeapRemove | |||||
| 275 | * or airHeapUpdate, but will become invalid as soon as any element is | |||||
| 276 | * removed from the heap. */ | |||||
| 277 | int airHeapFind(const airHeap *h, unsigned int *ai, const void *data) { | |||||
| 278 | unsigned int i; | |||||
| 279 | if (h==NULL((void*)0) || ai==NULL((void*)0) || data==NULL((void*)0) || h->data_a==NULL((void*)0)) | |||||
| 280 | return 1; | |||||
| 281 | for (i=0; i<h->key_a->len; i++) { | |||||
| 282 | if (!memcmp((char*)h->data_a->data+i*h->data_a->unit, data, | |||||
| 283 | h->data_a->unit)) { | |||||
| 284 | *ai = i; | |||||
| 285 | return 0; | |||||
| 286 | } | |||||
| 287 | } | |||||
| 288 | return 1; | |||||
| 289 | } | |||||
| 290 | ||||||
| 291 | /* Removes element ai from the heap, returns 0 upon success. */ | |||||
| 292 | int airHeapRemove(airHeap *h, unsigned int ai) { | |||||
| 293 | unsigned int old_invidx_ai; | |||||
| 294 | if (h==NULL((void*)0) || h->key_a->len<=ai) | |||||
| 295 | return 1; | |||||
| 296 | /* in the tree, replace ai with last element */ | |||||
| 297 | old_invidx_ai=h->invidx[ai]; | |||||
| 298 | h->idx[h->invidx[ai]]=h->idx[h->key_a->len-1]; | |||||
| 299 | h->invidx[h->idx[h->key_a->len-1]]=h->invidx[ai]; | |||||
| 300 | /* remove ai - copy last element over, then drop it */ | |||||
| 301 | if (ai!=h->key_a->len-1) { | |||||
| 302 | h->key[ai]=h->key[h->key_a->len-1]; | |||||
| 303 | if (h->data_a!=NULL((void*)0)) { | |||||
| 304 | memcpy((char*)h->data_a->data+ai*h->data_a->unit,__builtin___memcpy_chk ((char*)h->data_a->data+ai*h-> data_a->unit, (char*)h->data_a->data+(h->key_a-> len-1)*h->data_a->unit, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+ai*h->data_a->unit, 0)) | |||||
| 305 | (char*)h->data_a->data+(h->key_a->len-1)*h->data_a->unit,__builtin___memcpy_chk ((char*)h->data_a->data+ai*h-> data_a->unit, (char*)h->data_a->data+(h->key_a-> len-1)*h->data_a->unit, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+ai*h->data_a->unit, 0)) | |||||
| 306 | h->data_a->unit)__builtin___memcpy_chk ((char*)h->data_a->data+ai*h-> data_a->unit, (char*)h->data_a->data+(h->key_a-> len-1)*h->data_a->unit, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+ai*h->data_a->unit, 0)); | |||||
| 307 | } | |||||
| 308 | h->idx[h->invidx[h->key_a->len-1]]=ai; | |||||
| 309 | h->invidx[ai]=h->invidx[h->key_a->len-1]; | |||||
| 310 | } | |||||
| 311 | heapLenIncr(h, -1); | |||||
| 312 | /* push moved element downheap */ | |||||
| 313 | if (old_invidx_ai<h->key_a->len) | |||||
| 314 | downheap(h, old_invidx_ai); | |||||
| 315 | return 0; | |||||
| 316 | } | |||||
| 317 | ||||||
| 318 | /* Changes the key (and optional data) of the element ai, re-sorting | |||||
| 319 | * the heap if necessary. Returns 0 upon success. */ | |||||
| 320 | int airHeapUpdate(airHeap *h, unsigned int ai, double newKey, | |||||
| 321 | const void *newData) { | |||||
| 322 | double oldkey; | |||||
| 323 | if (h==NULL((void*)0) || h->key_a->len<=ai) | |||||
| 324 | return 1; | |||||
| 325 | oldkey = h->key[ai]; | |||||
| 326 | /* replace key and data */ | |||||
| 327 | h->key[ai] = newKey; | |||||
| 328 | if (h->data_a!=NULL((void*)0) && newData!=NULL((void*)0)) { | |||||
| 329 | memcpy((char*)h->data_a->data+ai*h->data_a->unit,__builtin___memcpy_chk ((char*)h->data_a->data+ai*h-> data_a->unit, newData, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+ai*h->data_a->unit, 0)) | |||||
| 330 | newData, h->data_a->unit)__builtin___memcpy_chk ((char*)h->data_a->data+ai*h-> data_a->unit, newData, h->data_a->unit, __builtin_object_size ((char*)h->data_a->data+ai*h->data_a->unit, 0)); | |||||
| 331 | } | |||||
| 332 | if (oldkey<newKey) downheap(h, h->invidx[ai]); | |||||
| 333 | else upheap(h, h->invidx[ai]); | |||||
| 334 | return 0; | |||||
| 335 | } |