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
2823namespace
@@ -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, " \n Binary 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}
0 commit comments