Skip to content
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

src: implement backtrace-on-abort for windows #16951

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
35 changes: 34 additions & 1 deletion src/backtrace_win32.cc
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
#include "node.h"
#define _WIN32_WINNT 0x0600
Copy link
Member Author

Choose a reason for hiding this comment

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

@nodejs/platform-windows What’s the right way to do this? That’s basically the only question I have left here…

Copy link
Contributor

Choose a reason for hiding this comment

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

This is actually an interesting question. We have multiple version targeting macros:

Copy link
Contributor

Choose a reason for hiding this comment

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

(shirt-return is not the right key-chord. it's not new line, it's Submit)

Copy link
Contributor

@refack refack Nov 11, 2017

Choose a reason for hiding this comment

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

(grrrr, shift-return again)

  • From uv
    #ifndef _WIN32_WINNT
    # define _WIN32_WINNT 0x0502
    #endif
  • Our:

    node/src/node.h

    Lines 42 to 47 in a36aa04

    // This should be defined in make system.
    // See issue https://github.com/joyent/node/issues/1236
    #if defined(__MINGW32__) || defined(_MSC_VER)
    #ifndef _WIN32_WINNT
    # define _WIN32_WINNT 0x0501
    #endif

tl;dr this should be injected by the build system, so you should ifndef around it. Also semantically it's used for targeting a minimum platform requirements, and 0x0600 is anyway our platform minimum.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not at my laptop rn but if it's really just ifdef'ing it feel free to push that to this branch

#include "node_internals.h"
#include <windows.h>
#include <dbghelp.h>

namespace node {

void DumpBacktrace(FILE* fp) {
void* frames[256];
int size = CaptureStackBackTrace(0, arraysize(frames), frames, nullptr);
HANDLE process = GetCurrentProcess();
(void)SymInitialize(process, nullptr, true);

// Ref: https://msdn.microsoft.com/en-en/library/windows/desktop/ms680578(v=vs.85).aspx
char info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
SYMBOL_INFO* info = reinterpret_cast<SYMBOL_INFO*>(info_buf);
char demangled[MAX_SYM_NAME];

for (int i = 1; i < size; i += 1) {
void* frame = frames[i];
fprintf(fp, "%2d: ", i);
info->MaxNameLen = MAX_SYM_NAME;
info->SizeOfStruct = sizeof(SYMBOL_INFO);
const bool have_info =
SymFromAddr(process, reinterpret_cast<DWORD64>(frame), nullptr, info);
if (!have_info || strlen(info->Name) == 0) {
fprintf(fp, "%p", frame);
} else if (UnDecorateSymbolName(info->Name,
demangled,
sizeof(demangled),
UNDNAME_COMPLETE)) {
fprintf(fp, "%s", demangled);
} else {
fprintf(fp, "%s", info->Name);
}
fprintf(fp, "\n");
}
(void)SymCleanup(process);
}

} // namespace node
9 changes: 4 additions & 5 deletions test/abort/test-abort-backtrace.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
'use strict';
const common = require('../common');
if (common.isWindows)
common.skip('Backtraces unimplemented on Windows.');

const assert = require('assert');
const cp = require('child_process');

Expand All @@ -21,8 +18,10 @@ if (process.argv[2] === 'child') {
assert.fail(`Each frame should start with a frame number:\n${stderr}`);
}

if (!frames.some((frame) => frame.includes(`[${process.execPath}]`))) {
assert.fail(`Some frames should include the binary name:\n${stderr}`);
if (!common.isWindows) {
if (!frames.some((frame) => frame.includes(`[${process.execPath}]`))) {
assert.fail(`Some frames should include the binary name:\n${stderr}`);
}
}
}
}