Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 00e7aa0

Browse files
authored
Additional parameter validation for StartNoGCRegion (#14088)
* Additional parameter validation for StartNoGCRegion * Fix the clang build by moving some defs before the first goto * Guard against size_t overflow when scaling allocation budgets * Move some parameter validation for managed code, throw better exceptions on parameter validation errors * Remove stray comma * Address code review feedback - unify code branches that branch to the failure case. Also keep data types as uint64_t as long as possible to avoid size_t overflow * Fix the clang build * Code review feedback: 1. Remove useless asserts 2. Remove a dead code path 3. Add a LocalGC TODO to comment
1 parent 02c0ef2 commit 00e7aa0

File tree

2 files changed

+73
-23
lines changed

2 files changed

+73
-23
lines changed

src/gc/gc.cpp

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15880,45 +15880,71 @@ start_no_gc_region_status gc_heap::prepare_for_no_gc_region (uint64_t total_size
1588015880
save_data_for_no_gc();
1588115881
settings.pause_mode = pause_no_gc;
1588215882
current_no_gc_region_info.start_status = start_no_gc_success;
15883-
15884-
size_t allocation_no_gc_loh = 0;
15885-
size_t allocation_no_gc_soh = 0;
15886-
size_t size_per_heap = 0;
1588715883

15888-
total_size = (size_t)((float)total_size * 1.05);
15884+
uint64_t allocation_no_gc_loh = 0;
15885+
uint64_t allocation_no_gc_soh = 0;
15886+
assert(total_size != 0);
1588915887
if (loh_size_known)
1589015888
{
15891-
loh_size = (size_t)((float)loh_size * 1.05);
15892-
allocation_no_gc_loh = (size_t)loh_size;
15893-
allocation_no_gc_soh = (size_t)(total_size - loh_size);
15889+
assert(loh_size != 0);
15890+
assert(loh_size <= total_size);
15891+
allocation_no_gc_loh = loh_size;
15892+
allocation_no_gc_soh = total_size - loh_size;
1589415893
}
1589515894
else
1589615895
{
15897-
allocation_no_gc_soh = (size_t)total_size;
15898-
allocation_no_gc_loh = (size_t)total_size;
15896+
allocation_no_gc_soh = total_size;
15897+
allocation_no_gc_loh = total_size;
1589915898
}
1590015899

1590115900
int soh_align_const = get_alignment_constant (TRUE);
15902-
size_t max_soh_allocated = (soh_segment_size - segment_info_size - eph_gen_starts_size);
15901+
size_t max_soh_allocated = soh_segment_size - segment_info_size - eph_gen_starts_size;
15902+
size_t size_per_heap = 0;
15903+
const double scale_factor = 1.05;
1590315904

1590415905
int num_heaps = 1;
1590515906
#ifdef MULTIPLE_HEAPS
1590615907
num_heaps = n_heaps;
15907-
#endif //MULTIPLE_HEAPS
15908-
size_t total_allowed_soh_allocation = max_soh_allocated * num_heaps;
15908+
#endif // MULTIPLE_HEAPS
1590915909

15910-
if (allocation_no_gc_soh > total_allowed_soh_allocation)
15910+
uint64_t total_allowed_soh_allocation = max_soh_allocated * num_heaps;
15911+
// [LOCALGC TODO]
15912+
// In theory, the upper limit here is the physical memory of the machine, not
15913+
// SIZE_T_MAX. This is not true today because total_physical_mem can be
15914+
// larger than SIZE_T_MAX if running in wow64 on a machine with more than
15915+
// 4GB of RAM. Once Local GC code divergence is resolved and code is flowing
15916+
// more freely between branches, it would be good to clean this up to use
15917+
// total_physical_mem instead of SIZE_T_MAX.
15918+
assert(total_allowed_soh_allocation <= SIZE_T_MAX);
15919+
uint64_t total_allowed_loh_allocation = SIZE_T_MAX;
15920+
uint64_t total_allowed_soh_alloc_scaled = allocation_no_gc_soh > 0 ? static_cast<uint64_t>(total_allowed_soh_allocation / scale_factor) : 0;
15921+
uint64_t total_allowed_loh_alloc_scaled = allocation_no_gc_loh > 0 ? static_cast<uint64_t>(total_allowed_loh_allocation / scale_factor) : 0;
15922+
15923+
if (allocation_no_gc_soh > total_allowed_soh_alloc_scaled ||
15924+
allocation_no_gc_loh > total_allowed_loh_alloc_scaled)
1591115925
{
1591215926
status = start_no_gc_too_large;
1591315927
goto done;
1591415928
}
1591515929

15930+
if (allocation_no_gc_soh > 0)
15931+
{
15932+
allocation_no_gc_soh = static_cast<uint64_t>(allocation_no_gc_soh * scale_factor);
15933+
allocation_no_gc_soh = min (allocation_no_gc_soh, total_allowed_soh_alloc_scaled);
15934+
}
15935+
15936+
if (allocation_no_gc_loh > 0)
15937+
{
15938+
allocation_no_gc_loh = static_cast<uint64_t>(allocation_no_gc_loh * scale_factor);
15939+
allocation_no_gc_loh = min (allocation_no_gc_loh, total_allowed_loh_alloc_scaled);
15940+
}
15941+
1591615942
if (disallow_full_blocking)
1591715943
current_no_gc_region_info.minimal_gc_p = TRUE;
1591815944

1591915945
if (allocation_no_gc_soh != 0)
1592015946
{
15921-
current_no_gc_region_info.soh_allocation_size = allocation_no_gc_soh;
15947+
current_no_gc_region_info.soh_allocation_size = static_cast<size_t>(allocation_no_gc_soh);
1592215948
size_per_heap = current_no_gc_region_info.soh_allocation_size;
1592315949
#ifdef MULTIPLE_HEAPS
1592415950
size_per_heap /= n_heaps;
@@ -15934,7 +15960,7 @@ start_no_gc_region_status gc_heap::prepare_for_no_gc_region (uint64_t total_size
1593415960

1593515961
if (allocation_no_gc_loh != 0)
1593615962
{
15937-
current_no_gc_region_info.loh_allocation_size = allocation_no_gc_loh;
15963+
current_no_gc_region_info.loh_allocation_size = static_cast<size_t>(allocation_no_gc_loh);
1593815964
size_per_heap = current_no_gc_region_info.loh_allocation_size;
1593915965
#ifdef MULTIPLE_HEAPS
1594015966
size_per_heap /= n_heaps;

src/mscorlib/src/System/GC.cs

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
using System.Globalization;
2525
using System.Runtime.InteropServices;
2626
using System.Runtime.Versioning;
27+
using System.Diagnostics;
2728

2829
namespace System
2930
{
@@ -434,14 +435,37 @@ private enum EndNoGCRegionStatus
434435

435436
private static bool StartNoGCRegionWorker(long totalSize, bool hasLohSize, long lohSize, bool disallowFullBlockingGC)
436437
{
438+
if (totalSize <= 0)
439+
{
440+
throw new ArgumentOutOfRangeException(nameof(totalSize), "totalSize can't be zero or negative");
441+
}
442+
443+
if (hasLohSize)
444+
{
445+
if (lohSize <= 0)
446+
{
447+
throw new ArgumentOutOfRangeException(nameof(lohSize), "lohSize can't be zero or negative");
448+
}
449+
450+
if (lohSize > totalSize)
451+
{
452+
throw new ArgumentOutOfRangeException(nameof(lohSize), "lohSize can't be greater than totalSize");
453+
}
454+
}
455+
437456
StartNoGCRegionStatus status = (StartNoGCRegionStatus)_StartNoGCRegion(totalSize, hasLohSize, lohSize, disallowFullBlockingGC);
438-
if (status == StartNoGCRegionStatus.AmountTooLarge)
439-
throw new ArgumentOutOfRangeException(nameof(totalSize),
440-
"totalSize is too large. For more information about setting the maximum size, see \"Latency Modes\" in http://go.microsoft.com/fwlink/?LinkId=522706");
441-
else if (status == StartNoGCRegionStatus.AlreadyInProgress)
442-
throw new InvalidOperationException("The NoGCRegion mode was already in progress");
443-
else if (status == StartNoGCRegionStatus.NotEnoughMemory)
444-
return false;
457+
switch (status)
458+
{
459+
case StartNoGCRegionStatus.NotEnoughMemory:
460+
return false;
461+
case StartNoGCRegionStatus.AlreadyInProgress:
462+
throw new InvalidOperationException("The NoGCRegion mode was already in progress");
463+
case StartNoGCRegionStatus.AmountTooLarge:
464+
throw new ArgumentOutOfRangeException(nameof(totalSize),
465+
"totalSize is too large. For more information about setting the maximum size, see \"Latency Modes\" in http://go.microsoft.com/fwlink/?LinkId=522706");
466+
}
467+
468+
Debug.Assert(status == StartNoGCRegionStatus.Succeeded);
445469
return true;
446470
}
447471

0 commit comments

Comments
 (0)