Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

Commit 145402e

Browse files
authored
Wasm: RhpNewArrayAlign8 use non-padded size when going to the slow path (#8324)
* RhpNewArrayAlign8 use non-padded size when going to the slow path and RhpGcAlloc * remove padding from slow path for RhpNewFastMisalign and RhpNewFastAlign8 * add overflow checks for 32bit host * #if out align 8 methods for HOST_64BIT. Change overflow check for padding to not use 64 bit arithmetic
1 parent 64389da commit 145402e

File tree

2 files changed

+139
-42
lines changed

2 files changed

+139
-42
lines changed

src/Native/Runtime/portable.cpp

Lines changed: 61 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,12 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFast, (EEType* pEEType))
6464

6565
size_t size = pEEType->get_BaseSize();
6666

67-
UInt8* result = acontext->alloc_ptr;
68-
UInt8* advance = result + size;
69-
if (advance <= acontext->alloc_limit)
67+
UInt8* alloc_ptr = acontext->alloc_ptr;
68+
ASSERT(alloc_ptr <= acontext->alloc_limit);
69+
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= size)
7070
{
71-
acontext->alloc_ptr = advance;
72-
pObject = (Object *)result;
71+
acontext->alloc_ptr = alloc_ptr + size;
72+
pObject = (Object *)alloc_ptr;
7373
pObject->set_EEType(pEEType);
7474
return pObject;
7575
}
@@ -147,12 +147,12 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArray, (EEType * pArrayEEType, int numElement
147147
size = ALIGN_UP(size, sizeof(UIntNative));
148148
}
149149

150-
UInt8* result = acontext->alloc_ptr;
151-
UInt8* advance = result + size;
152-
if (advance <= acontext->alloc_limit)
150+
UInt8* alloc_ptr = acontext->alloc_ptr;
151+
ASSERT(alloc_ptr <= acontext->alloc_limit);
152+
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= size)
153153
{
154-
acontext->alloc_ptr = advance;
155-
pObject = (Array *)result;
154+
acontext->alloc_ptr = alloc_ptr + size;
155+
pObject = (Array *)alloc_ptr;
156156
pObject->set_EEType(pArrayEEType);
157157
pObject->InitArrayLength((UInt32)numElements);
158158
return pObject;
@@ -192,6 +192,7 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFinalizableAlign8, (EEType* pEEType))
192192
return pObject;
193193
}
194194

195+
#ifndef HOST_64BIT
195196
COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
196197
{
197198
ASSERT(pEEType->RequiresAlign8());
@@ -207,20 +208,29 @@ COOP_PINVOKE_HELPER(Object *, RhpNewFastAlign8, (EEType* pEEType))
207208
UInt8* result = acontext->alloc_ptr;
208209

209210
int requiresPadding = ((uint32_t)result) & 7;
210-
if (requiresPadding) size += 12;
211-
UInt8* advance = result + size;
212-
if (advance <= acontext->alloc_limit)
211+
size_t paddedSize = size;
212+
if (requiresPadding)
213213
{
214-
acontext->alloc_ptr = advance;
214+
if(paddedSize > SIZE_MAX - 12)
215+
{
216+
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
217+
}
218+
paddedSize += 12;
219+
}
220+
221+
UInt8* alloc_ptr = acontext->alloc_ptr;
222+
ASSERT(alloc_ptr <= acontext->alloc_limit);
223+
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
224+
{
225+
acontext->alloc_ptr = alloc_ptr + paddedSize;
215226
if (requiresPadding)
216227
{
217-
Object* dummy = (Object*)result;
228+
Object* dummy = (Object*)alloc_ptr;
218229
dummy->set_EEType(g_pFreeObjectEEType);
219-
result += 12;
230+
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
220231
}
221-
pObject = (Object*)result;
232+
pObject = (Object *)alloc_ptr;
222233
pObject->set_EEType(pEEType);
223-
224234
return pObject;
225235
}
226236

@@ -247,20 +257,28 @@ COOP_PINVOKE_HELPER(Object*, RhpNewFastMisalign, (EEType* pEEType))
247257
UInt8* result = acontext->alloc_ptr;
248258

249259
int requiresPadding = (((uint32_t)result) & 7) != 4;
250-
if (requiresPadding) size += 12;
251-
UInt8* advance = result + size;
252-
if (advance <= acontext->alloc_limit)
260+
size_t paddedSize = size;
261+
if (requiresPadding)
253262
{
254-
acontext->alloc_ptr = advance;
263+
if(paddedSize > SIZE_MAX - 12)
264+
{
265+
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
266+
}
267+
paddedSize += 12;
268+
}
269+
UInt8* alloc_ptr = acontext->alloc_ptr;
270+
ASSERT(alloc_ptr <= acontext->alloc_limit);
271+
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
272+
{
273+
acontext->alloc_ptr = alloc_ptr + paddedSize;
255274
if (requiresPadding)
256275
{
257-
Object* dummy = (Object*)result;
276+
Object* dummy = (Object*)alloc_ptr;
258277
dummy->set_EEType(g_pFreeObjectEEType);
259-
result += 12;
278+
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
260279
}
261-
pObject = (Object*)result;
280+
pObject = (Object *)alloc_ptr;
262281
pObject->set_EEType(pEEType);
263-
264282
return pObject;
265283
}
266284

@@ -293,7 +311,6 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE
293311
size_t size;
294312

295313
UInt32 baseSize = pArrayEEType->get_BaseSize();
296-
#ifndef HOST_64BIT
297314
// if the element count is <= 0x10000, no overflow is possible because the component size is
298315
// <= 0xffff, and thus the product is <= 0xffff0000, and the base size is only ~12 bytes
299316
if (numElements > 0x10000)
@@ -309,26 +326,33 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE
309326
}
310327
}
311328
else
312-
#endif // !HOST_64BIT
313329
{
314330
size = (size_t)baseSize + ((size_t)numElements * (size_t)pArrayEEType->get_ComponentSize());
315331
size = ALIGN_UP(size, sizeof(UIntNative));
316332
}
317333
UInt8* result = acontext->alloc_ptr;
318334
int requiresAlignObject = ((uint32_t)result) & 7;
319-
if (requiresAlignObject) size += 12;
320-
321-
UInt8* advance = result + size;
322-
if (advance <= acontext->alloc_limit)
335+
size_t paddedSize = size;
336+
if (requiresAlignObject)
323337
{
324-
acontext->alloc_ptr = advance;
338+
if(paddedSize > SIZE_MAX - 12)
339+
{
340+
ASSERT_UNCONDITIONALLY("NYI"); // TODO: Throw overflow
341+
}
342+
paddedSize += 12;
343+
}
344+
UInt8* alloc_ptr = acontext->alloc_ptr;
345+
ASSERT(alloc_ptr <= acontext->alloc_limit);
346+
if ((size_t)(acontext->alloc_limit - alloc_ptr) >= paddedSize)
347+
{
348+
acontext->alloc_ptr = alloc_ptr + paddedSize;
325349
if (requiresAlignObject)
326350
{
327-
Object* dummy = (Object*)result;
351+
Object* dummy = (Object*)alloc_ptr;
328352
dummy->set_EEType(g_pFreeObjectEEType);
329-
result += 12;
353+
alloc_ptr += 12; // if result + paddedSize was ok, then cant overflow
330354
}
331-
pObject = (Array*)result;
355+
pObject = (Array*)alloc_ptr;
332356
pObject->set_EEType(pArrayEEType);
333357
pObject->InitArrayLength((UInt32)numElements);
334358
return pObject;
@@ -347,6 +371,7 @@ COOP_PINVOKE_HELPER(Array *, RhpNewArrayAlign8, (EEType * pArrayEEType, int numE
347371

348372
return pObject;
349373
}
374+
#endif // !HOST_64BIT
350375
#endif // defined(HOST_ARM) || defined(HOST_WASM)
351376

352377
COOP_PINVOKE_HELPER(void, RhpInitialDynamicInterfaceDispatch, ())

tests/src/Simple/HelloWasm/Program.cs

Lines changed: 78 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Collections;
1010
using System.Reflection;
1111
using System.Diagnostics;
12+
using System.Collections.Specialized;
1213

1314
#if TARGET_WINDOWS
1415
using CpObj;
@@ -386,7 +387,7 @@ private static void TestGC()
386387

387388
var genOfNewObject = GC.GetGeneration(new object());
388389
PrintLine("Generation of new object " + genOfNewObject.ToString());
389-
if(genOfNewObject != 0)
390+
if (genOfNewObject != 0)
390391
{
391392
FailTest("Gen of new object was " + genOfNewObject);
392393
return;
@@ -399,13 +400,18 @@ private static void TestGC()
399400
FailTest("object alive when has no references");
400401
return;
401402
}
402-
// create enough arrays to go over 5GB which should force older arrays to get collected
403-
// use array of size 1MB, then iterate 5*1024 times
404-
for(var i = 0; i < 5 * 1024; i++)
403+
for (var i = 0; i < 3; i++)
405404
{
406-
var a = new int[256 * 1024]; // ints are 4 bytes so this is 1MB
405+
PrintString("GC Collection Count " + i.ToString() + " ");
406+
PrintLine(GC.CollectionCount(i).ToString());
407+
}
408+
if(!TestCreateDifferentObjects())
409+
{
410+
FailTest("Failed test for creating/collecting different objects");
407411
}
408-
for(var i = 0; i < 3; i++)
412+
GC.Collect();
413+
GC.Collect();
414+
for (var i = 0; i < 3; i++)
409415
{
410416
PrintString("GC Collection Count " + i.ToString() + " ");
411417
PrintLine(GC.CollectionCount(i).ToString());
@@ -425,6 +431,72 @@ private static void TestGC()
425431
EndTest(TestGeneration2Rooting());
426432
}
427433

434+
struct MiniRandom
435+
{
436+
private uint _val;
437+
438+
public MiniRandom(uint seed)
439+
{
440+
_val = seed;
441+
}
442+
443+
public uint Next()
444+
{
445+
_val ^= (_val << 13);
446+
_val ^= (_val >> 7);
447+
_val ^= (_val << 17);
448+
return _val;
449+
}
450+
}
451+
452+
class F4 { internal int i; }
453+
class F8 { internal long l; }
454+
class F2Plus8 { internal short s; internal long l; }
455+
class CDisp : IDisposable { public void Dispose() { } }
456+
struct StructF48 { internal int i1; internal long l2; }
457+
private static bool TestCreateDifferentObjects()
458+
{
459+
var mr = new MiniRandom(257);
460+
var keptObjects = new object[100];
461+
for (var i = 0; i < 1000000; i++)
462+
{
463+
var r = mr.Next();
464+
object o;
465+
switch (r % 8)
466+
{
467+
case 0:
468+
o = new F4 { i = 1, };
469+
break;
470+
case 1:
471+
o = new F8 { l = 4 };
472+
break;
473+
case 2:
474+
o = new F2Plus8 { l = 5, s = 6 };
475+
break;
476+
case 3:
477+
o = i.ToString();
478+
break;
479+
case 4:
480+
o = new long[10000];
481+
break;
482+
case 5:
483+
o = new int[10000];
484+
break;
485+
case 6:
486+
o = new StructF48 { i1 = 7, l2 = 8 };
487+
break;
488+
case 7:
489+
o = new CDisp();
490+
break;
491+
default:
492+
o = null;
493+
break;
494+
}
495+
keptObjects[r % 100] = o;
496+
}
497+
return true;
498+
}
499+
428500
private static Parent aParent;
429501
private static ParentOfStructWithObjRefs aParentOfStructWithObjRefs;
430502
private static WeakReference childRef;

0 commit comments

Comments
 (0)