Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions changelog/trap_memory_error.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Page protection error handling can now be registered via `--DRT-memoryError=1`

In environments where attaching a debugger or retrieving a core dump isn't possible or hard,
on Linux x86_64 one has always been able to attach druntime's memory handler:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in the etc.linux.memoryerror module is defined for both 32 bit and 64 bit.


---
shared static this()
{
import etc.linux.memoryerror : registerMemoryErrorHandler;
registerMemoryErrorHandler;
}

void main() {
int* ptr = null;
(*ptr)++;
}
---

And thus retrieved the full segfault as D `Error` on the command-line:

$(CONSOLE dmd -g -run test.d
etc.linux.memoryerror.NullPointerError@src/etc/linux/memoryerror.d(325)
$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)
??:? void etc.linux.memoryerror.sigsegvUserspaceProcess(void*) [0x8353df09]
??:? void etc.linux.memoryerror.sigsegvDataHandler() [0x8353de4a]
test.d:9 _Dmain [0x8353c2b5]
)

With this release, instead of recompiling the binary and adding the `registerMemoryError`,
one can use the runtime flag `--DRT-memoryError=1` to activate druntime's memory error handling.

$(CONSOLE dmd -g test.d && ./test --DRT-memoryError=1
etc.linux.memoryerror.NullPointerError@src/etc/linux/memoryerror.d(325)
$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)$(NDASH)
??:? void etc.linux.memoryerror.sigsegvUserspaceProcess(void*) [0x8353df09]
??:? void etc.linux.memoryerror.sigsegvDataHandler() [0x8353de4a]
test.d:2 _Dmain [0x8353c2b5]
)
20 changes: 20 additions & 0 deletions src/rt/dmain2.d
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,14 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF

auto useExceptionTrap = parseExceptionOptions();

// Handle page protection errors using D errors (exceptions) when supported
version (linux)
{
import etc.linux.memoryerror : registerMemoryErrorHandler;
if (parseMemoryErrorOptions())
registerMemoryErrorHandler();
}

version (Windows)
{
if (IsDebuggerPresent())
Expand Down Expand Up @@ -557,6 +565,18 @@ private auto parseExceptionOptions()
return trap;
}

private auto parseMemoryErrorOptions()
{
import rt.config : rt_configOption;
import core.internal.parseoptions : rt_parseOption;
enum optName = "memoryError";
auto option = rt_configOption(optName);
bool trap;
if (option.length)
rt_parseOption(optName, option, trap, "");
return trap;
}

extern (C) void _d_print_throwable(Throwable t)
{
// On Windows, a console may not be present to print the output to.
Expand Down
5 changes: 4 additions & 1 deletion test/exceptions/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ TESTS=stderr_msg unittest_assert invalid_memory_operation unknown_gc static_dtor
future_message refcounted rt_trap_exceptions_drt catch_in_finally

ifeq ($(OS)-$(BUILD),linux-debug)
TESTS+=line_trace long_backtrace_trunc rt_trap_exceptions
TESTS+=line_trace long_backtrace_trunc rt_trap_exceptions rt_trap_memory_error
LINE_TRACE_DFLAGS:=-L--export-dynamic
endif
ifeq ($(OS),linux)
Expand Down Expand Up @@ -67,6 +67,9 @@ $(ROOT)/catch_in_finally.done: STDERR_EXP="success."
$(ROOT)/rt_trap_exceptions.done: STDERR_EXP="object.Exception@src/rt_trap_exceptions.d(12): this will abort"
$(ROOT)/rt_trap_exceptions.done: STDERR_EXP2="src/rt_trap_exceptions.d:8 main"
$(ROOT)/assert_fail.done: STDERR_EXP="success."
$(ROOT)/rt_trap_memory_error.done: RUN_ARGS="--DRT-memoryError=1"
$(ROOT)/rt_trap_memory_error.done: STDERR_EXP="etc.linux.memoryerror.NullPointerError@src/etc/linux/memoryerror.d"

$(ROOT)/%.done: $(ROOT)/%
@echo Testing $*
$(QUIET)$(TIMELIMIT)$(ROOT)/$* $(RUN_ARGS) 2>$(ROOT)/$*.stderr || true
Expand Down
4 changes: 4 additions & 0 deletions test/exceptions/src/rt_trap_memory_error.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
void main() {
int* ptr = null;
(*ptr)++;
}