@@ -26,6 +26,9 @@ interface WandboxOptions {
2626 compilerName : string ;
2727 compilerOptions : string [ ] ;
2828 commandline : string ;
29+ compilerOptionsRaw : string [ ] ;
30+ additionalFiles : Record < string , string > ;
31+ additionalSources : string [ ] ;
2932}
3033
3134const WandboxContext = createContext < IWandboxContext > ( null ! ) ;
@@ -111,6 +114,36 @@ interface CompileResult {
111114 url : string ;
112115}
113116
117+ const CPP_STACKTRACE_HANDLER = `
118+ #define BOOST_STACKTRACE_USE_ADDR2LINE
119+ #include <boost/stacktrace.hpp>
120+ #include <iostream>
121+ #include <signal.h>
122+ void signal_handler(int signum) {
123+ signal(signum, SIG_DFL);
124+ switch(signum) {
125+ case SIGABRT:
126+ std::cerr << "Aborted" << std::endl;
127+ break;
128+ case SIGSEGV:
129+ std::cerr << "Segmentation fault" << std::endl;
130+ break;
131+ default:
132+ std::cerr << "Signal " << signum << " received" << std::endl;
133+ break;
134+ }
135+ std::cerr << "Stack trace:" << std::endl;
136+ std::cerr << boost::stacktrace::stacktrace();
137+ raise(signum);
138+ }
139+ struct _init_signal_handler {
140+ _init_signal_handler() {
141+ signal(SIGABRT, signal_handler);
142+ signal(SIGSEGV, signal_handler);
143+ }
144+ } _init_signal_handler_instance;
145+ ` ;
146+
114147const compilerInfoFetcher : Fetcher < CompilerInfo [ ] > = ( ) =>
115148 fetch ( new URL ( "/api/list.json" , WANDBOX ) ) . then (
116149 ( res ) => res . json ( ) as Promise < CompilerInfo [ ] >
@@ -158,16 +191,17 @@ export function WandboxProvider({ children }: { children: ReactNode }) {
158191 for ( const switchSelect of selectedCompiler . switches . filter (
159192 ( s ) => s . type === "select"
160193 ) ) {
161- // boostはnothing 、stdは最新を選ぶ ほかはデフォルト
194+ // boost最新 、stdは最新を選ぶ ほかはデフォルト
162195 if ( switchSelect . name . includes ( "boost" ) ) {
163- const boostNothingOption = switchSelect . options . find ( ( o ) =>
164- o . name . includes ( "nothing" )
165- ) ;
166- if ( boostNothingOption ) {
167- compilerOptions . push ( boostNothingOption . name ) ;
168- commandlineArgs . push ( boostNothingOption [ "display-flags" ] ) ;
196+ const boostLatestOption = switchSelect . options
197+ . filter ( ( o ) => ! o . name . includes ( "nothing" ) )
198+ . sort ( )
199+ . reverse ( ) [ 0 ] ;
200+ if ( boostLatestOption ) {
201+ compilerOptions . push ( boostLatestOption . name ) ;
202+ // commandlineArgs.push(boostLatestOption["display-flags"]);
169203 } else {
170- console . warn ( "boost nothing option not found" ) ;
204+ console . warn ( "boost option not found" ) ;
171205 }
172206 } else if ( switchSelect . name . includes ( "std" ) ) {
173207 const stdLatestOption = switchSelect . options
@@ -189,10 +223,18 @@ export function WandboxProvider({ children }: { children: ReactNode }) {
189223 }
190224 }
191225
226+ // その他オプション
227+ // commandlineArgs.push("-g");
228+
192229 return {
193230 compilerName,
194231 compilerOptions,
195232 commandline : commandlineArgs . join ( " " ) ,
233+ compilerOptionsRaw : [ "-g" ] ,
234+ additionalFiles : {
235+ "_stacktrace.cpp" : CPP_STACKTRACE_HANDLER ,
236+ } ,
237+ additionalSources : [ "_stacktrace.cpp" ] ,
196238 } satisfies WandboxOptions ;
197239 } , [ compilerList ] ) ;
198240
@@ -240,10 +282,22 @@ export function WandboxProvider({ children }: { children: ReactNode }) {
240282 file : name ,
241283 code : files [ name ] || "" ,
242284 } ) )
285+ )
286+ . concat (
287+ Object . entries ( options . additionalFiles ) . map ( ( [ file , code ] ) => ( {
288+ file,
289+ code,
290+ } ) )
243291 ) ,
244292 options : options . compilerOptions . join ( "," ) ,
245293 stdin : "" ,
246- "compiler-option-raw" : namesSource . join ( "\n" ) ,
294+ "compiler-option-raw" : [
295+ options . compilerOptionsRaw ,
296+ namesSource ,
297+ options . additionalSources ,
298+ ]
299+ . flat ( )
300+ . join ( "\n" ) ,
247301 "runtime-option-raw" : "" ,
248302 save : false ,
249303 is_private : true ,
@@ -277,12 +331,31 @@ export function WandboxProvider({ children }: { children: ReactNode }) {
277331 ) ;
278332 }
279333 if ( result . program_error ) {
334+ const errorBeforeTrace =
335+ result . program_error . split ( "Stack trace:\n" ) [ 0 ] ;
280336 outputs = outputs . concat (
281- result . program_error
337+ errorBeforeTrace
282338 . trim ( )
283339 . split ( "\n" )
284340 . map ( ( line ) => ( { type : "error" as const , message : line } ) )
285341 ) ;
342+ if ( result . program_error . includes ( "Stack trace:" ) ) {
343+ // CPP_STACKTRACE_HANDLER のコードで出力されるスタックトレースを、js側でパースしていい感じに表示する
344+ const stackTrace = result . program_error . split ( "Stack trace:\n" ) [ 1 ] ;
345+ outputs = outputs . concat ( {
346+ type : "trace" as const ,
347+ message : "Stack trace (filtered):" ,
348+ } ) ;
349+ for ( const line of stackTrace . trim ( ) . split ( "\n" ) ) {
350+ // ユーザーのソースコードだけを対象にする
351+ if ( line . includes ( "/home/wandbox" ) ) {
352+ outputs = outputs . concat ( {
353+ type : "trace" as const ,
354+ message : line . replace ( "/home/wandbox/" , "" ) ,
355+ } ) ;
356+ }
357+ }
358+ }
286359 }
287360 if ( result . status !== "0" ) {
288361 outputs . push ( {
0 commit comments