Skip to content

Commit 07a49d4

Browse files
committed
Refactored PR #144
1 parent d59dff6 commit 07a49d4

File tree

5 files changed

+143
-109
lines changed

5 files changed

+143
-109
lines changed

Source/CommandLine.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,6 @@ inline void logAndFlush (const juce::String& m)
5757

5858
//==============================================================================
5959
//==============================================================================
60-
CommandLineValidator::CommandLineValidator()
61-
{
62-
}
63-
64-
CommandLineValidator::~CommandLineValidator()
65-
{
66-
}
67-
6860
void CommandLineValidator::validate (const juce::String& fileOrID, PluginTests::Options options)
6961
{
7062
validator = std::make_unique<ValidationPass> (fileOrID, options, ValidationType::inProcess,

Source/CommandLine.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
//==============================================================================
2121
struct CommandLineValidator
2222
{
23-
CommandLineValidator();
24-
~CommandLineValidator();
23+
CommandLineValidator() = default;
24+
~CommandLineValidator() = default;
2525

2626
void validate (const juce::String&, PluginTests::Options);
2727

Source/CrashHandler.cpp

Lines changed: 15 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,9 @@
1515
#include "juce_core/juce_core.h"
1616
#include "CrashHandler.h"
1717

18-
#if !JUCE_WINDOWS
19-
#include <dlfcn.h>
20-
#include <execinfo.h>
21-
#include <fcntl.h>
22-
#include <stdarg.h>
23-
#include <stdio.h>
24-
#include <unistd.h>
25-
#define CRASH_LOG "/tmp/pluginval_crash.txt"
18+
#if ! JUCE_WINDOWS
19+
#include "native/pluginval_native_posix.h"
20+
static const auto crashLogPath = "/tmp/pluginval_crash.txt";
2621
#endif
2722

2823
namespace
@@ -34,113 +29,35 @@ namespace
3429

3530
static juce::File getCrashTraceFile()
3631
{
37-
#if JUCE_WINDOWS
32+
#if JUCE_WINDOWS
3833
return juce::File::getSpecialLocation (juce::File::tempDirectory).getChildFile ("pluginval_crash.txt");
39-
#else
40-
return juce::File(CRASH_LOG);
41-
#endif
34+
#else
35+
return juce::File (crashLogPath);
36+
#endif
4237
}
4338

44-
#if JUCE_WINDOWS
45-
static void handleCrash(void*)
39+
#if JUCE_WINDOWS
40+
static void handleCrash (void*)
4641
{
4742
const auto log = getCrashLogContents();
4843
std::cout << "\n*** FAILED: VALIDATION CRASHED\n" << log << std::endl;
4944
getCrashTraceFile().replaceWithText (log);
5045
}
51-
#else
52-
#ifdef __printflike
53-
__printflike(2, 3)
54-
#endif
55-
static void writeToCrashLog(int fd, const char* fmt, ...)
46+
#else
47+
static void handleCrash (void*)
5648
{
57-
char buf[1024];
58-
va_list args;
59-
va_start(args, fmt);
60-
// Warning: printf is not 100% async-signal-safe, but should be ok for locale-independent arguments like
61-
// integers, strings, hex... floating point is locale-dependent and not safe to use here.
62-
vsnprintf(buf, sizeof(buf), fmt, args);
63-
va_end(args);
64-
auto len = strlen(buf);
65-
write(STDERR_FILENO, buf, len);
66-
if (fd != -1)
67-
write(fd, buf, len);
68-
}
69-
70-
static void handleCrash(void*)
71-
{
72-
// On Linux & Mac this is a signal handler, and therefore only "async-signal-safe" functions should be used.
73-
// This means nothing that uses malloc (juce::File, juce::String, std::string, std::vector etc.) or buffered I/O.
74-
75-
int fd = open(CRASH_LOG, O_RDWR | O_CREAT | O_TRUNC);
76-
77-
const char *message = "\n*** FAILED: VALIDATION CRASHED\n";
78-
write(STDERR_FILENO, message, strlen(message));
79-
80-
// Recreate the output of backtrace_symbols(), which cannot be used in a signal handler because it uses malloc
81-
static const int kMaxStacks = 128;
82-
void *stacktrace[kMaxStacks] {};
83-
int stackCount = backtrace(stacktrace, kMaxStacks);
84-
85-
static const int kMaxImages = 64;
86-
const void *imageAddresses[kMaxImages] {};
87-
const char *imageNames[kMaxImages] {};
88-
int imageCount = 0;
89-
90-
int skip = 2; // Skip handleCrash and juce::handleCrash)
91-
for (int i = skip; i < stackCount; i++)
92-
{
93-
Dl_info info {};
94-
// Warning: dladdr can deadlock under rare conditions on macOS - if dyld is adding an image to its list
95-
if (!dladdr(stacktrace[i], &info))
96-
{
97-
writeToCrashLog(fd, "%-3d %-35s %p\n", i - skip, "", stacktrace[i]);
98-
continue;
99-
}
100-
101-
const char *imageName = info.dli_fname ? strrchr(info.dli_fname, '/') : nullptr;
102-
if (imageName)
103-
{
104-
imageName++;
105-
106-
auto it = std::find(std::begin(imageAddresses), std::end(imageAddresses), info.dli_fbase);
107-
if (it == std::end(imageAddresses) && imageCount < kMaxImages)
108-
{
109-
imageAddresses[imageCount] = info.dli_fbase;
110-
imageNames[imageCount] = imageName;
111-
imageCount++;
112-
}
113-
}
114-
115-
if (info.dli_saddr)
116-
{
117-
ptrdiff_t offset = (char *)stacktrace[i] - (char *)info.dli_saddr;
118-
writeToCrashLog(fd, "%-3d %-35s %p %s + %ld\n", i - skip, imageName, stacktrace[i], info.dli_sname, offset);
119-
}
120-
else
121-
{
122-
writeToCrashLog(fd, "%-3d %-35s %p\n", i - skip, imageName, stacktrace[i]);
123-
}
124-
}
125-
126-
if (imageCount)
127-
{
128-
writeToCrashLog(fd, "\nBinary Images:");
129-
for (int i = 0; i < imageCount; i++)
130-
writeToCrashLog(fd, "\n%p %s", imageAddresses[i], imageNames[i]);
131-
writeToCrashLog(fd, "\n");
132-
}
49+
const char* header = "\n*** FAILED: VALIDATION CRASHED\n";
50+
write (STDERR_FILENO, header, strlen (header));
13351

134-
if (fd != -1)
135-
close(fd);
52+
writeStackTrace (crashLogPath, 2); // Skip handleCrash and juce::handleCrash)
13653

13754
// Terminate normally to work around a bug in juce::ChildProcess::ActiveProcess::getExitStatus()
13855
// which returns 0 (a "pass" in the host process) if the child process terminates abnormally.
13956
// - https://github.com/Tracktion/pluginval/issues/125
14057
// - https://forum.juce.com/t/killed-childprocess-activeprocess-exit-code/61645/3
14158
// Use _Exit() instead of exit() so that static destructors don't run (they may not be async-signal-safe).
14259
// FIXME: exiting here prevents Apple's Crash Reporter from creating reports.
143-
std::_Exit(SIGKILL);
60+
std::_Exit (SIGKILL);
14461
}
14562
#endif
14663
}

Source/Validator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
//==============================================================================
2323
struct PluginsUnitTestRunner : public juce::UnitTestRunner,
24-
private juce::Thread
24+
private juce::Thread
2525
{
2626
PluginsUnitTestRunner (std::function<void (const juce::String&)> logCallback, std::unique_ptr<juce::FileOutputStream> logDestination, juce::int64 timeoutInMs)
2727
: Thread ("TimoutThread"),
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*==============================================================================
2+
3+
Copyright 2018 by Tracktion Corporation.
4+
For more information visit www.tracktion.com
5+
6+
You may also use this code under the terms of the GPL v3 (see
7+
www.gnu.org/licenses).
8+
9+
pluginval IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
10+
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
11+
DISCLAIMED.
12+
13+
==============================================================================*/
14+
15+
#pragma once
16+
17+
#if __has_include(<unistd.h>)
18+
19+
#include <dlfcn.h>
20+
#include <execinfo.h>
21+
#include <fcntl.h>
22+
#include <stdarg.h>
23+
#include <stdio.h>
24+
#include <unistd.h>
25+
26+
#ifdef __printflike
27+
__printflike(2, 3)
28+
#endif
29+
30+
/** Writes a string to a file descriptor in a async-signal-safe way. I.e. no allocations etc. */
31+
inline void writeAsyncSignalSafe (int fd, const char* fmt, ...)
32+
{
33+
char buf[1024];
34+
35+
va_list args;
36+
va_start (args, fmt);
37+
// Warning: printf is not 100% async-signal-safe, but should be ok for locale-independent arguments like
38+
// integers, strings, hex... floating point is locale-dependent and not safe to use here.
39+
vsnprintf (buf, sizeof (buf), fmt, args);
40+
va_end (args);
41+
42+
auto len = strlen (buf);
43+
write (STDERR_FILENO, buf, len);
44+
45+
if (fd != -1)
46+
write (fd, buf, len);
47+
}
48+
49+
/** Writes the current stack trace and images to a given filepath and stderr.
50+
*/
51+
inline void writeStackTrace (const char* filePath, const int numLinesToSkip = 0)
52+
{
53+
// On Linux & Mac this is a signal handler, and therefore only "async-signal-safe" functions should be used.
54+
// This means nothing that uses malloc (juce::File, juce::String, std::string, std::vector etc.) or buffered I/O.
55+
int fd = open (filePath, O_RDWR | O_CREAT | O_TRUNC);
56+
57+
// Write stack traces and images
58+
{
59+
// Recreate the output of backtrace_symbols(), which cannot be used in a
60+
// signal handler because it uses malloc
61+
constexpr int maxNumStacks = 128;
62+
void *stacktrace[maxNumStacks]{};
63+
int stackCount = backtrace(stacktrace, maxNumStacks);
64+
65+
constexpr int maxNumImages = 64;
66+
const void *imageAddresses[maxNumImages]{};
67+
const char *imageNames[maxNumImages]{};
68+
int imageCount = 0;
69+
70+
for (int i = numLinesToSkip; i < stackCount; ++i)
71+
{
72+
Dl_info info{};
73+
74+
// Warning: dladdr can deadlock under rare conditions on macOS - if dyld
75+
// is adding an image to its list
76+
if (! dladdr (stacktrace[i], &info))
77+
{
78+
writeAsyncSignalSafe (fd, "%-3d %-35s %p\n", i - numLinesToSkip, "", stacktrace[i]);
79+
continue;
80+
}
81+
82+
const char* imageName = info.dli_fname ? strrchr (info.dli_fname, '/') : nullptr;
83+
84+
if (imageName)
85+
{
86+
++imageName;
87+
88+
auto it = std::find (std::begin (imageAddresses), std::end (imageAddresses), info.dli_fbase);
89+
90+
if (it == std::end (imageAddresses) && imageCount < maxNumImages)
91+
{
92+
imageAddresses[imageCount] = info.dli_fbase;
93+
imageNames[imageCount] = imageName;
94+
++imageCount;
95+
}
96+
}
97+
98+
if (info.dli_saddr)
99+
{
100+
ptrdiff_t offset = static_cast<char*> (stacktrace[i]) - static_cast<char*> (info.dli_saddr);
101+
writeAsyncSignalSafe (fd, "%-3d %-35s %p %s + %ld\n", i - numLinesToSkip, imageName, stacktrace[i], info.dli_sname,
102+
offset);
103+
}
104+
else
105+
{
106+
writeAsyncSignalSafe (fd, "%-3d %-35s %p\n", i - numLinesToSkip, imageName, stacktrace[i]);
107+
}
108+
}
109+
110+
if (imageCount > 0)
111+
{
112+
writeAsyncSignalSafe (fd, "\nBinary Images:");
113+
114+
for (int i = 0; i < imageCount; i++)
115+
writeAsyncSignalSafe (fd, "\n%p %s", imageAddresses[i], imageNames[i]);
116+
117+
writeAsyncSignalSafe (fd, "\n");
118+
}
119+
}
120+
121+
if (fd != -1)
122+
close (fd);
123+
}
124+
125+
#endif //__has_include(<unistd.h>)

0 commit comments

Comments
 (0)