-
Notifications
You must be signed in to change notification settings - Fork 3.4k
Fix bug where ASan shadow region was overlapping static data #15806
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||
---|---|---|---|---|
|
@@ -187,6 +187,11 @@ def base64_encode(b): | |||
return b64.decode('ascii') | ||||
|
||||
|
||||
def align_to_wasm_page_boundary(address): | ||||
page_size = webassembly.WASM_PAGE_SIZE | ||||
return ((address + (page_size - 1)) // page_size) * page_size | ||||
|
||||
|
||||
@unique | ||||
class OFormat(Enum): | ||||
# Output a relocatable object file. We use this | ||||
|
@@ -2179,6 +2184,17 @@ def check_memory_setting(setting): | |||
'emscripten_builtin_free', | ||||
] | ||||
|
||||
if ('leak' in sanitize or 'address' in sanitize) and not settings.ALLOW_MEMORY_GROWTH: | ||||
# Increase the minimum memory requirements to account for extra memory | ||||
# that the sanitizers might need (in addition to the shadow memory | ||||
# requirements handled below). | ||||
# These values are designed be an over-estimate of the actual requirements and | ||||
# are based on experimentation with different tests/programs under asan and | ||||
# lsan. | ||||
settings.INITIAL_MEMORY += 50 * 1024 * 1024 | ||||
if settings.USE_PTHREADS: | ||||
settings.INITIAL_MEMORY += 50 * 1024 * 1024 | ||||
|
||||
if settings.USE_OFFSET_CONVERTER and settings.WASM2JS: | ||||
exit_with_error('wasm2js is not compatible with USE_OFFSET_CONVERTER (see #14630)') | ||||
|
||||
|
@@ -2235,27 +2251,38 @@ def check_memory_setting(setting): | |||
if settings.GLOBAL_BASE != -1: | ||||
exit_with_error("ASan does not support custom GLOBAL_BASE") | ||||
|
||||
max_mem = settings.INITIAL_MEMORY | ||||
# Increase the TOTAL_MEMORY and shift GLOBAL_BASE to account for | ||||
# the ASan shadow region which starts at address zero. | ||||
# The shadow region is 1/8th the size of the total memory and is | ||||
# itself part of the total memory. | ||||
# We use the following variables in this calculation: | ||||
# - user_mem : memory usable/visible by the user program. | ||||
# - shadow_size : memory used by asan for shadow memory. | ||||
# - total_mem : the sum of the above. this is the size of the wasm memory (and must be aligned to WASM_PAGE_SIZE) | ||||
user_mem = settings.INITIAL_MEMORY | ||||
if settings.ALLOW_MEMORY_GROWTH: | ||||
max_mem = settings.MAXIMUM_MEMORY | ||||
user_mem = settings.MAXIMUM_MEMORY | ||||
sbc100 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||
|
||||
shadow_size = max_mem // 8 | ||||
settings.GLOBAL_BASE = shadow_size | ||||
# Given the know value of user memory size we can work backwards | ||||
# to find the total memory and the shadow size based on the fact | ||||
# that the user memory is 7/8ths of the total memory. | ||||
# (i.e. user_mem == total_mem * 7 / 8 | ||||
total_mem = user_mem * 8 / 7 | ||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am slightly worried about rounding errors here, since I assume ASan rounds up, that is, isn't the size of shadow memory potentially slightly more than user memory / 7? I would compute this is shadow_mem = ..however asan rounds..
total_mem = user_mem + shadow_mem Or does ASan actually compute it as a fraction of total memory, not user memory? In that case your code lgtm There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ASan literally does a shift to from a pointer to its shadow byte:
The problem with trying to start by calculating the size of the shadow region is that you can't do that without also knowing the size of the shadow region.. since the bigger the shadow region the more shadow region you need because it shift the reset of the memory upwards as it grows. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The assertion that I've added to the code I think means that if these calculation are wrong we would know right away.. at least if we ever under-estimate the size of the shadow region which is the dangerous direction. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wait if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For what its worth the calculation of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, right. sgtm |
||||
|
||||
sanitizer_mem = (shadow_size + webassembly.WASM_PAGE_SIZE) & ~webassembly.WASM_PAGE_SIZE | ||||
# sanitizers do at least 9 page allocs of a single page during startup. | ||||
sanitizer_mem += webassembly.WASM_PAGE_SIZE * 9 | ||||
# we also allocate at least 11 "regions". Each region is kRegionSize (2 << 20) but | ||||
# MmapAlignedOrDieOnFatalError adds another 2 << 20 for alignment. | ||||
sanitizer_mem += (1 << 21) * 11 | ||||
# When running in the threaded mode asan needs to allocate an array of kMaxNumberOfThreads | ||||
# (1 << 22) pointers. See compiler-rt/lib/asan/asan_thread.cpp. | ||||
if settings.USE_PTHREADS: | ||||
sanitizer_mem += (1 << 22) * 4 | ||||
# But we might need to re-align to wasm page size | ||||
total_mem = int(align_to_wasm_page_boundary(total_mem)) | ||||
|
||||
# The shadow size is 1/8th the resulting rounded up size | ||||
shadow_size = total_mem // 8 | ||||
|
||||
# Increase the size of the initial memory according to how much memory | ||||
# we think the sanitizers will use. | ||||
settings.INITIAL_MEMORY += sanitizer_mem | ||||
# We start our global data after the shadow memory. | ||||
# We don't need to worry about alignment here. wasm-ld will take care of that. | ||||
settings.GLOBAL_BASE = shadow_size | ||||
|
||||
if not settings.ALLOW_MEMORY_GROWTH: | ||||
settings.INITIAL_MEMORY = total_mem | ||||
else: | ||||
settings.INITIAL_MEMORY += align_to_wasm_page_boundary(shadow_size) | ||||
|
||||
if settings.SAFE_HEAP: | ||||
# SAFE_HEAP instruments ASan's shadow memory accesses. | ||||
|
Uh oh!
There was an error while loading. Please reload this page.