Browse Source

Ensure COWData does not reallocate on push back, fixes #22561

(cherry picked from commit 0c24a844ecff77cb956ce052e47ccf6d4c774666)
Juan Linietsky 5 years ago
parent
commit
94f451e070
1 changed files with 24 additions and 17 deletions
  1. 24 17
      core/cowdata.h

+ 24 - 17
core/cowdata.h

@@ -252,7 +252,9 @@ Error CowData<T>::resize(int p_size) {
 
 
 	ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
 	ERR_FAIL_COND_V(p_size < 0, ERR_INVALID_PARAMETER);
 
 
-	if (p_size == size())
+	int current_size = size();
+
+	if (p_size == current_size)
 		return OK;
 		return OK;
 
 
 	if (p_size == 0) {
 	if (p_size == 0) {
@@ -265,24 +267,27 @@ Error CowData<T>::resize(int p_size) {
 	// possibly changing size, copy on write
 	// possibly changing size, copy on write
 	_copy_on_write();
 	_copy_on_write();
 
 
+	size_t current_alloc_size = _get_alloc_size(current_size);
 	size_t alloc_size;
 	size_t alloc_size;
 	ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
 	ERR_FAIL_COND_V(!_get_alloc_size_checked(p_size, &alloc_size), ERR_OUT_OF_MEMORY);
 
 
-	if (p_size > size()) {
+	if (p_size > current_size) {
 
 
-		if (size() == 0) {
-			// alloc from scratch
-			uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
-			ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
-			*(ptr - 1) = 0; //size, currently none
-			*(ptr - 2) = 1; //refcount
+		if (alloc_size != current_alloc_size) {
+			if (current_size == 0) {
+				// alloc from scratch
+				uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
+				ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
+				*(ptr - 1) = 0; //size, currently none
+				*(ptr - 2) = 1; //refcount
 
 
-			_ptr = (T *)ptr;
+				_ptr = (T *)ptr;
 
 
-		} else {
-			void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
-			ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
-			_ptr = (T *)(_ptrnew);
+			} else {
+				void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+				ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+				_ptr = (T *)(_ptrnew);
+			}
 		}
 		}
 
 
 		// construct the newly created elements
 		// construct the newly created elements
@@ -297,7 +302,7 @@ Error CowData<T>::resize(int p_size) {
 
 
 		*_get_size() = p_size;
 		*_get_size() = p_size;
 
 
-	} else if (p_size < size()) {
+	} else if (p_size < current_size) {
 
 
 		if (!__has_trivial_destructor(T)) {
 		if (!__has_trivial_destructor(T)) {
 			// deinitialize no longer needed elements
 			// deinitialize no longer needed elements
@@ -307,10 +312,12 @@ Error CowData<T>::resize(int p_size) {
 			}
 			}
 		}
 		}
 
 
-		void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
-		ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+		if (alloc_size != current_alloc_size) {
+			void *_ptrnew = (T *)Memory::realloc_static(_ptr, alloc_size, true);
+			ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
 
 
-		_ptr = (T *)(_ptrnew);
+			_ptr = (T *)(_ptrnew);
+		}
 
 
 		*_get_size() = p_size;
 		*_get_size() = p_size;
 	}
 	}