History

Merge pull request #312 from doctashay/fix-realloc-leak

Wolfgang Thaller committed 3 months ago

Commit f99ecb52 parents 335fa54 17407693 files · +138 −13Browse files

Unified · Split

3 files
  1. AutomatedTests/CMakeLists.txt +2 −0
  2. AutomatedTests/Realloc.c +120 −0
  3. libretro/malloc.c +16 −13
AutomatedTests/CMakeLists.txt+2−0
@@ -59,6 +59,8 @@ test(Empty.c) · 58 unmodified lines
5959
6060 test(File.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
6161
62+test(Realloc.c PROPERTIES PASS_REGULAR_EXPRESSION "OK")
63+
6264 #test(Timeout.c PROPERTIES PASS_REGULAR_EXPRESSION "One" DISABLED TRUE)
6365
6466 test(Log.c PROPERTIES PASS_REGULAR_EXPRESSION "One\nTwo\nThree")
AutomatedTests/Realloc.c+120−0
@@ -0,0 +1,120 @@
1+#include "Test.h"
2+
3+#include <MacMemory.h>
4+#include <stdlib.h>
5+#include <string.h>
6+
7+enum
8+{
9+ initialSize = 64 * 1024,
10+ grownSize = 128 * 1024,
11+ blockerSize = 8 * 1024,
12+ blockerCount = 96,
13+ releasedBlockers = (grownSize / blockerSize) + 4,
14+ freeMemoryTolerance = 1024
15+};
16+
17+int main(void)
18+{
19+ Size freeBefore = FreeMem();
20+ unsigned char *allocation = malloc(initialSize);
21+ void *blockers[blockerCount];
22+ unsigned char *grown;
23+ Size freeAfter;
24+ int failure = 0;
25+ int numBlockers = 0;
26+ int ok = allocation != NULL;
27+ int i;
28+
29+ memset(blockers, 0, sizeof(blockers));
30+
31+ if(!ok)
32+ failure = 1;
33+
34+ if(ok)
35+ {
36+ for(i = 0; i < initialSize; ++i)
37+ allocation[i] = (unsigned char)(i * 37 + 11);
38+
39+ while(numBlockers < blockerCount &&
40+ (blockers[numBlockers] = malloc(blockerSize)) != NULL)
41+ {
42+ memset(blockers[numBlockers], 0x5a, blockerSize);
43+ ++numBlockers;
44+ }
45+
46+ if(numBlockers <= releasedBlockers)
47+ {
48+ ok = 0;
49+ failure = 6;
50+ }
51+
52+ for(i = numBlockers - releasedBlockers; i < numBlockers; ++i)
53+ {
54+ if(i >= 0)
55+ {
56+ free(blockers[i]);
57+ blockers[i] = NULL;
58+ }
59+ }
60+
61+ grown = realloc(allocation, grownSize);
62+ if(!grown)
63+ {
64+ ok = 0;
65+ failure = 2;
66+ }
67+ else if(grown == allocation)
68+ {
69+ ok = 0;
70+ failure = 3;
71+ }
72+
73+ if(grown)
74+ {
75+ for(i = 0; ok && i < initialSize; ++i)
76+ {
77+ if(grown[i] != (unsigned char)(i * 37 + 11))
78+ {
79+ ok = 0;
80+ failure = 4;
81+ }
82+ }
83+ free(grown);
84+ }
85+ else
86+ {
87+ free(allocation);
88+ }
89+
90+ }
91+ else
92+ {
93+ free(allocation);
94+ }
95+
96+ for(i = 0; i < numBlockers; ++i)
97+ free(blockers[i]);
98+
99+ freeAfter = FreeMem();
100+ if(ok && freeAfter + freeMemoryTolerance < freeBefore)
101+ {
102+ ok = 0;
103+ failure = 5;
104+ }
105+
106+ if(ok)
107+ {
108+ TEST_LOG_OK();
109+ }
110+ else
111+ {
112+ char result[3];
113+ result[0] = 'N';
114+ result[1] = (char)('0' + failure);
115+ result[2] = '\0';
116+ TEST_LOG_SIZED(result, 2);
117+ }
118+
119+ return ok ? 0 : 1;
120+}
libretro/malloc.c+16−13
@@ -69,27 +69,30 @@ void *_realloc_r(struct _reent *reent_ptr, void *ptr, size_t sz) · 68 unmodified lines
6969 }
7070 else
7171 {
72+ if(sz == 0)
73+ {
74+ DisposePtr(ptr);
75+ return NULL;
76+ }
77+
78+ /* Save this now in case the block has to be moved. */
79+ size_t oldSz = GetPtrSize(ptr);
80+
7281 MemError();
7382 SetPtrSize(ptr, sz);
7483 if(MemError())
7584 {
76− size_t oldSz = GetPtrSize(ptr);
77− if(sz > oldSz)
78− {
79− void *newPtr = NewPtr(sz);
80− if(!newPtr)
81− {
82− reent_ptr->_errno = ENOMEM;
83− return NULL;
84− }
85− memcpy(newPtr, ptr, oldSz);
86− return newPtr;
87− }
88− else
85+ void *newPtr = NewPtr(sz);
86+ if(!newPtr)
8987 {
9088 reent_ptr->_errno = ENOMEM;
9189 return NULL;
9290 }
91+
92+ memcpy(newPtr, ptr, sz < oldSz ? sz : oldSz);
93+ /* The new block owns the data, so the old one can be released. */
94+ DisposePtr(ptr);
95+ return newPtr;
9396 }
9497 else
9598 return ptr;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t