diff --git a/builder/sizes_test.go b/builder/sizes_test.go index f6bb112fa..639c32b5c 100644 --- a/builder/sizes_test.go +++ b/builder/sizes_test.go @@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) { // This is a small number of very diverse targets that we want to test. tests := []sizeTest{ // microcontrollers - {"hifive1b", "examples/echo", 4277, 307, 0, 2260}, - {"microbit", "examples/serial", 2836, 368, 8, 2256}, - {"wioterminal", "examples/pininterrupt", 8013, 1663, 132, 7488}, + {"hifive1b", "examples/echo", 4313, 323, 0, 2260}, + {"microbit", "examples/serial", 2838, 382, 8, 2256}, + {"wioterminal", "examples/pininterrupt", 8027, 1665, 132, 7488}, // TODO: also check wasm. Right now this is difficult, because // wasm binaries are run through wasm-opt and therefore the diff --git a/main_test.go b/main_test.go index 4b354ef4c..2dfd1683f 100644 --- a/main_test.go +++ b/main_test.go @@ -993,15 +993,15 @@ func TestGoexitCrash(t *testing.T) { name string want string }{ - {"main", "all goroutines are asleep - deadlock!"}, - {"deadlock", "all goroutines are asleep - deadlock!"}, - {"exit", "all goroutines are asleep - deadlock!"}, - {"main-other", "all goroutines are asleep - deadlock!"}, - {"in-panic", "all goroutines are asleep - deadlock!"}, + {"main", "fatal error: all goroutines are asleep - deadlock!"}, + {"deadlock", "fatal error: all goroutines are asleep - deadlock!"}, + {"exit", "fatal error: all goroutines are asleep - deadlock!"}, + {"main-other", "fatal error: all goroutines are asleep - deadlock!"}, + {"in-panic", "fatal error: all goroutines are asleep - deadlock!"}, {"panic", "panic: panic after Goexit"}, - {"recovered-panic", "all goroutines are asleep - deadlock!"}, - {"recover-before-panic", "all goroutines are asleep - deadlock!"}, - {"recover-before-panic-loop", "all goroutines are asleep - deadlock!"}, + {"recovered-panic", "fatal error: all goroutines are asleep - deadlock!"}, + {"recover-before-panic", "fatal error: all goroutines are asleep - deadlock!"}, + {"recover-before-panic-loop", "fatal error: all goroutines are asleep - deadlock!"}, } { t.Run(tc.name, func(t *testing.T) { output := &bytes.Buffer{} @@ -1022,6 +1022,34 @@ func TestGoexitCrash(t *testing.T) { } } +func TestRuntimeFatal(t *testing.T) { + t.Parallel() + + options := optionsFromTarget("", sema) + config, err := builder.NewConfig(&options) + if err != nil { + t.Fatal(err) + } + + output := &bytes.Buffer{} + _, err = buildAndRun("testdata/runtimefatal.go", config, output, nil, nil, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error { + cmd.Stdout = nil + cmd.Stderr = nil + data, err := cmd.CombinedOutput() + output.Write(data) + return err + }) + if err == nil { + t.Fatal("program unexpectedly exited successfully") + } + if want := "fatal error: sync: unlock of unlocked Mutex"; !strings.Contains(output.String(), want) { + t.Fatalf("output does not contain %q:\n%s", want, output.String()) + } + if strings.Contains(output.String(), "recovered:") { + t.Fatalf("fatal runtime error was recovered:\n%s", output.String()) + } +} + func TestTest(t *testing.T) { t.Parallel() diff --git a/src/internal/task/fatal.go b/src/internal/task/fatal.go new file mode 100644 index 000000000..53be72c9c --- /dev/null +++ b/src/internal/task/fatal.go @@ -0,0 +1,6 @@ +package task + +import _ "unsafe" + +//go:linkname runtimeFatal runtime.runtimeFatal +func runtimeFatal(msg string) diff --git a/src/internal/task/mutex-cooperative.go b/src/internal/task/mutex-cooperative.go index 90274df2b..57d66d013 100644 --- a/src/internal/task/mutex-cooperative.go +++ b/src/internal/task/mutex-cooperative.go @@ -20,7 +20,7 @@ func (m *Mutex) Lock() { func (m *Mutex) Unlock() { if !m.locked { - panic("sync: unlock of unlocked Mutex") + runtimeFatal("sync: unlock of unlocked Mutex") } // Wake up a blocked task, if applicable. diff --git a/src/internal/task/mutex-preemptive.go b/src/internal/task/mutex-preemptive.go index ec83a6135..3ab0f2bac 100644 --- a/src/internal/task/mutex-preemptive.go +++ b/src/internal/task/mutex-preemptive.go @@ -49,7 +49,7 @@ func (m *Mutex) Lock() { func (m *Mutex) Unlock() { if old := m.futex.Swap(0); old == 0 { // Mutex wasn't locked before. - panic("sync: unlock of unlocked Mutex") + runtimeFatal("sync: unlock of unlocked Mutex") } else if old == 2 { // Mutex was a contended lock, so we need to wake the next waiter. m.futex.Wake() diff --git a/src/internal/task/queue.go b/src/internal/task/queue.go index 7242c4e31..1095e8bbd 100644 --- a/src/internal/task/queue.go +++ b/src/internal/task/queue.go @@ -15,7 +15,7 @@ func (q *Queue) Push(t *Task) { mask := lockAtomics() if asserts && t.Next != nil { unlockAtomics(mask) - panic("runtime: pushing a task to a queue with a non-nil Next pointer") + runtimeFatal("runtime: pushing a task to a queue with a non-nil Next pointer") } if q.tail != nil { q.tail.Next = t @@ -78,7 +78,7 @@ func (s *Stack) Push(t *Task) { mask := lockAtomics() if asserts && t.Next != nil { unlockAtomics(mask) - panic("runtime: pushing a task to a stack with a non-nil Next pointer") + runtimeFatal("runtime: pushing a task to a stack with a non-nil Next pointer") } s.top, t.Next = t, s.top unlockAtomics(mask) diff --git a/src/internal/task/task_asyncify.go b/src/internal/task/task_asyncify.go index 0f7437067..d7d9a6de4 100644 --- a/src/internal/task/task_asyncify.go +++ b/src/internal/task/task_asyncify.go @@ -11,9 +11,6 @@ import ( // otherwise Go wouldn't allow the cast to a smaller integer size. const stackCanary = uintptr(uint64(0x670c1333b83bf575) & uint64(^uintptr(0))) -//go:linkname runtimePanic runtime.runtimePanic -func runtimePanic(str string) - // state is a structure which holds a reference to the state of the task. // When the task is suspended, the stack pointers are saved here. type state struct { @@ -95,7 +92,7 @@ func Current() *Task { // This function may only be called when running on a goroutine stack, not when running on the system stack. func Pause() { if *currentTask.state.canaryPtr != stackCanary { - runtimePanic("stack overflow") + runtimeFatal("stack overflow") } currentTask.state.unwind() @@ -124,7 +121,7 @@ func (t *Task) Resume() { currentTask = prevTask t.gcData.swap() if uintptr(t.state.asyncifysp) > uintptr(t.state.csp) { - runtimePanic("stack overflow") + runtimeFatal("stack overflow") } } diff --git a/src/internal/task/task_exit.go b/src/internal/task/task_exit.go index 0c2bb8ee8..40f988058 100644 --- a/src/internal/task/task_exit.go +++ b/src/internal/task/task_exit.go @@ -28,15 +28,15 @@ func exit(goexit bool) { if t == mainTask { if goexit { if remaining == 0 { - runtimePanic("all goroutines are asleep - deadlock!") + runtimeFatal("all goroutines are asleep - deadlock!") } atomic.StoreUint32(&mainExitedByGoexit, 1) } } else if atomic.LoadUint32(&mainExitedByGoexit) != 0 && remaining == 0 { - runtimePanic("all goroutines are asleep - deadlock!") + runtimeFatal("all goroutines are asleep - deadlock!") } // TODO: explicitly free the stack after switching back to the scheduler. Pause() - runtimePanic("unreachable") + runtimeFatal("unreachable") } diff --git a/src/internal/task/task_stack.go b/src/internal/task/task_stack.go index 9db5c5890..23f3b9097 100644 --- a/src/internal/task/task_stack.go +++ b/src/internal/task/task_stack.go @@ -6,9 +6,6 @@ import ( "unsafe" ) -//go:linkname runtimePanic runtime.runtimePanic -func runtimePanic(str string) - // Stack canary, to detect a stack overflow. The number is a random number // generated by random.org. The bit fiddling dance is necessary because // otherwise Go wouldn't allow the cast to a smaller integer size. diff --git a/src/internal/task/task_stack_multicore.go b/src/internal/task/task_stack_multicore.go index 65cf3a004..dd2a266ae 100644 --- a/src/internal/task/task_stack_multicore.go +++ b/src/internal/task/task_stack_multicore.go @@ -23,10 +23,10 @@ func PauseLocked() { // valid. If it is not, a stack overflow has occurred. current := Current() if *current.state.canaryPtr != stackCanary { - runtimePanic("goroutine stack overflow") + runtimeFatal("goroutine stack overflow") } if interrupt.In() { - runtimePanic("blocked inside interrupt") + runtimeFatal("blocked inside interrupt") } if current.RunState == RunStateResuming { // Another core already marked this goroutine as ready to resume. diff --git a/src/internal/task/task_stack_unicore.go b/src/internal/task/task_stack_unicore.go index b4425de38..e1b172f9c 100644 --- a/src/internal/task/task_stack_unicore.go +++ b/src/internal/task/task_stack_unicore.go @@ -18,10 +18,10 @@ func Pause() { // Check whether the canary (the lowest address of the stack) is still // valid. If it is not, a stack overflow has occurred. if *currentTask.state.canaryPtr != stackCanary { - runtimePanic("goroutine stack overflow") + runtimeFatal("goroutine stack overflow") } if interrupt.In() { - runtimePanic("blocked inside interrupt") + runtimeFatal("blocked inside interrupt") } currentTask.state.pause() } diff --git a/src/internal/task/task_threads.go b/src/internal/task/task_threads.go index 0d14eae34..52374dec8 100644 --- a/src/internal/task/task_threads.go +++ b/src/internal/task/task_threads.go @@ -48,7 +48,7 @@ var activeTaskLock PMutex var mainExitedByGoexit bool func OnSystemStack() bool { - runtimePanic("todo: task.OnSystemStack") + runtimeFatal("todo: task.OnSystemStack") return false } @@ -63,7 +63,7 @@ func Init(sp uintptr) { func Current() *Task { t := (*Task)(tinygo_task_current()) if t == nil { - runtimePanic("unknown current task") + runtimeFatal("unknown current task") } return t } @@ -112,7 +112,7 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) { activeTaskLock.Lock() errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop, stackSize) if errCode != 0 { - runtimePanic("could not start thread") + runtimeFatal("could not start thread") } t.state.QueueNext = activeTasks activeTasks = t @@ -127,7 +127,7 @@ func taskExited(t *Task) { } if exit(t) { - runtimePanic("all goroutines are asleep - deadlock!") + runtimeFatal("all goroutines are asleep - deadlock!") } } @@ -149,7 +149,7 @@ func exit(t *Task) bool { // Sanity check. if !found { - runtimePanic("taskExited failed") + runtimeFatal("taskExited failed") } return deadlocked } @@ -173,11 +173,11 @@ func Exit() { } activeTaskLock.Unlock() if noOtherTasks { - runtimePanic("all goroutines are asleep - deadlock!") + runtimeFatal("all goroutines are asleep - deadlock!") } } if exit(t) { - runtimePanic("all goroutines are asleep - deadlock!") + runtimeFatal("all goroutines are asleep - deadlock!") } tinygo_task_exit() } @@ -325,9 +325,6 @@ func StackTop() uintptr { return Current().state.stackTop } -//go:linkname runtimePanic runtime.runtimePanic -func runtimePanic(msg string) - // Using //go:linkname instead of //export so that we don't tell the compiler // that the 't' parameter won't escape (because it will). // diff --git a/src/runtime/arch_tinygowasm_malloc.go b/src/runtime/arch_tinygowasm_malloc.go index 471361bd7..df824881e 100644 --- a/src/runtime/arch_tinygowasm_malloc.go +++ b/src/runtime/arch_tinygowasm_malloc.go @@ -34,7 +34,7 @@ func libc_free(ptr unsafe.Pointer) { if _, ok := allocs[(*byte)(ptr)]; ok { delete(allocs, (*byte)(ptr)) } else { - panic("free: invalid pointer") + runtimeFatal("free: invalid pointer") } } @@ -63,7 +63,7 @@ func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer { copy(newBuf, oldBuf) delete(allocs, (*byte)(oldPtr)) } else { - panic("realloc: invalid pointer") + runtimeFatal("realloc: invalid pointer") } } diff --git a/src/runtime/dynamic_arm64.go b/src/runtime/dynamic_arm64.go index e167f6f2e..9f126b009 100644 --- a/src/runtime/dynamic_arm64.go +++ b/src/runtime/dynamic_arm64.go @@ -49,7 +49,7 @@ func dynamicLoader(base uintptr, dyn *dyn64) { } if rela == nil { - runtimePanic("bad reloc") + runtimeFatal("bad reloc") } if debugLoader { diff --git a/src/runtime/gc_blocks.go b/src/runtime/gc_blocks.go index 0cb11c00f..2aadaeaf8 100644 --- a/src/runtime/gc_blocks.go +++ b/src/runtime/gc_blocks.go @@ -108,7 +108,7 @@ type gcBlock uintptr // might not be heap-aligned). func blockFromAddr(addr uintptr) gcBlock { if gcAsserts && (addr < heapStart || addr >= uintptr(metadataStart)) { - runtimePanic("gc: trying to get block from invalid address") + runtimeFatal("gc: trying to get block from invalid address") } return gcBlock((addr - heapStart) / bytesPerBlock) } @@ -122,7 +122,7 @@ func (b gcBlock) pointer() unsafe.Pointer { func (b gcBlock) address() uintptr { addr := heapStart + uintptr(b)*bytesPerBlock if gcAsserts && addr > uintptr(metadataStart) { - runtimePanic("gc: block pointing inside metadata") + runtimeFatal("gc: block pointing inside metadata") } return addr } @@ -154,7 +154,7 @@ func (b gcBlock) findHead() gcBlock { } if gcAsserts { if b.state() != blockStateHead && b.state() != blockStateMark { - runtimePanic("gc: found tail without head") + runtimeFatal("gc: found tail without head") } } return b @@ -182,14 +182,14 @@ func (b gcBlock) setState(newState blockState) { stateBytePtr := (*uint8)(unsafe.Add(metadataStart, b/blocksPerStateByte)) *stateBytePtr |= uint8(newState << (b % blocksPerStateByte)) if gcAsserts && b.state() != newState { - runtimePanic("gc: setState() was not successful") + runtimeFatal("gc: setState() was not successful") } } // unmark changes the state of b from blockStateMark to blockStateHead. func (b gcBlock) unmark() { if gcAsserts && b.state() != blockStateMark { - runtimePanic("gc: block not marked") + runtimeFatal("gc: block not marked") } stateBytePtr := (*uint8)(unsafe.Add(metadataStart, b/blocksPerStateByte)) *stateBytePtr ^= uint8(blockStateMark^blockStateHead) << (b % blocksPerStateByte) @@ -234,7 +234,7 @@ type freeRangeMore struct { // insertFreeRange inserts a range of len blocks starting at ptr into the free list. func insertFreeRange(ptr unsafe.Pointer, len uintptr) { if gcAsserts && len == 0 { - runtimePanic("gc: insert 0-length free range") + runtimeFatal("gc: insert 0-length free range") } // Find the insertion point by length. @@ -267,7 +267,7 @@ func insertFreeRange(ptr unsafe.Pointer, len uintptr) { // It returns nil if there are no sufficiently long ranges. func popFreeRange(len uintptr) unsafe.Pointer { if gcAsserts && len == 0 { - runtimePanic("gc: pop 0-length free range") + runtimeFatal("gc: pop 0-length free range") } // Find the removal point by length. @@ -331,7 +331,7 @@ func initHeap() { // will be expensive. func setHeapEnd(newHeapEnd uintptr) { if gcAsserts && newHeapEnd <= heapEnd { - runtimePanic("gc: setHeapEnd didn't grow the heap") + runtimeFatal("gc: setHeapEnd didn't grow the heap") } // Save some old variables we need later. @@ -354,7 +354,7 @@ func setHeapEnd(newHeapEnd uintptr) { // should be used to avoid corruption. // This assert checks whether that's true. if gcAsserts && uintptr(metadataStart) < uintptr(oldMetadataStart)+oldMetadataSize { - runtimePanic("gc: heap did not grow enough at once") + runtimeFatal("gc: heap did not grow enough at once") } // Insert the new free range. This range will be separate from any previous @@ -393,7 +393,7 @@ func calculateHeapAddresses() { } if gcAsserts && metadataSize*blocksPerStateByte < numBlocks { // sanity check - runtimePanic("gc: metadata array is too small") + runtimeFatal("gc: metadata array is too small") } } @@ -407,7 +407,7 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { } if interrupt.In() { - runtimePanicAt(returnAddress(0), "heap alloc in interrupt") + runtimeFatal("heap alloc in interrupt") } // Round the size up to a multiple of blocks, adding space for the header. @@ -622,10 +622,10 @@ func markRoots(start, end uintptr) { } if gcAsserts { if start >= end { - runtimePanic("gc: unexpected range to mark") + runtimeFatal("gc: unexpected range to mark") } if start%unsafe.Alignof(start) != 0 { - runtimePanic("gc: unaligned start pointer") + runtimeFatal("gc: unaligned start pointer") } } @@ -881,10 +881,10 @@ func SetFinalizer(obj interface{}, finalizer interface{}) { // exact func(*T) match is not checked; the closure ABI is uniform for any // single pointer argument, which is why callFinalizer can reinterpret it. if reflectlite.ValueOf(obj).Kind() != reflectlite.Pointer { - runtimePanic("runtime.SetFinalizer: first argument is not a pointer") + runtimeFatal("runtime.SetFinalizer: first argument is not a pointer") } if finalizer != nil && reflectlite.ValueOf(finalizer).Kind() != reflectlite.Func { - runtimePanic("runtime.SetFinalizer: second argument is not a function") + runtimeFatal("runtime.SetFinalizer: second argument is not a function") } // For an interface holding a pointer, the value word is the pointer itself. diff --git a/src/runtime/gc_boehm.go b/src/runtime/gc_boehm.go index a0adc93d3..e0fc16a67 100644 --- a/src/runtime/gc_boehm.go +++ b/src/runtime/gc_boehm.go @@ -55,7 +55,7 @@ func markCurrentGoroutineStack(sp uintptr) { // more pointers alive than needed on the current stack). base := libgc_base(sp) if base == 0 { // && asserts - runtimePanic("goroutine stack not in a heap allocation?") + runtimeFatal("goroutine stack not in a heap allocation?") } stackBottom := base + libgc_size(base) libgc_push_all_stack(sp, stackBottom) @@ -69,6 +69,7 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { gcLock.Lock() var ptr unsafe.Pointer + var needsZero bool if layout == gclayout.NoPtrs.AsPtr() { // This object is entirely pointer free, for example make([]int, ...). // Make sure the GC knows this so it doesn't scan the object @@ -76,7 +77,7 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { ptr = libgc_malloc_atomic(size) // Memory returned from libgc_malloc_atomic has not been zeroed so we // have to do that manually. - memzero(ptr, size) + needsZero = true } else { // TODO: bdwgc supports typed allocations, which could be useful to // implement a mostly-precise GC. @@ -88,6 +89,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer { gcLock.Unlock() if ptr == nil { runtimeFatal("gc: out of memory") + return nil + } + if needsZero { + memzero(ptr, size) } return ptr @@ -129,7 +134,7 @@ func ReadMemStats(m *MemStats) { } func setHeapEnd(newHeapEnd uintptr) { - runtimePanic("gc: did not expect setHeapEnd call") + runtimeFatal("gc: did not expect setHeapEnd call") } func SetFinalizer(obj interface{}, finalizer interface{}) { diff --git a/src/runtime/gc_leaking.go b/src/runtime/gc_leaking.go index 1467cb6bc..4ec9e6097 100644 --- a/src/runtime/gc_leaking.go +++ b/src/runtime/gc_leaking.go @@ -79,7 +79,7 @@ func free(ptr unsafe.Pointer) { } func markRoots(start, end uintptr) { - runtimePanic("unreachable: markRoots") + runtimeFatal("unreachable: markRoots") } // ReadMemStats populates m with memory statistics. diff --git a/src/runtime/gc_none.go b/src/runtime/gc_none.go index 3c092c65c..ce9649c71 100644 --- a/src/runtime/gc_none.go +++ b/src/runtime/gc_none.go @@ -33,7 +33,7 @@ func GC() { } func markRoots(start, end uintptr) { - runtimePanic("unreachable: markRoots") + runtimeFatal("unreachable: markRoots") } func SetFinalizer(obj interface{}, finalizer interface{}) { diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index 3bc939e81..6a151af80 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -80,7 +80,7 @@ func findGlobals(found func(start, end uintptr)) { // Sanity check that we're actually looking at a MachO header. if gcAsserts && libc_mh_execute_header.magic != MH_MAGIC_64 { - runtimePanic("gc: unexpected MachO header") + runtimeFatal("gc: unexpected MachO header") } // Iterate through the load commands. @@ -106,7 +106,7 @@ func findGlobals(found func(start, end uintptr)) { // Note that when ASLR is disabled (for example, when // running inside lldb), the offset is zero. That's why we // need a separate hasOffset for this assert. - runtimePanic("gc: did not detect ASLR offset") + runtimeFatal("gc: did not detect ASLR offset") } // Scan this segment for GC roots. // This could be improved by only reading the memory areas diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go index 908ce7052..c6d221850 100644 --- a/src/runtime/os_windows.go +++ b/src/runtime/os_windows.go @@ -29,7 +29,7 @@ func findGlobals(found func(start, end uintptr)) { // it using GetModuleHandle to account for ASLR etc. result := _GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, nil, &module) if gcAsserts && (!result || module.signature != 0x5A4D) { // 0x4D5A is "MZ" - runtimePanic("cannot get module handle") + runtimeFatal("cannot get module handle") } } diff --git a/src/runtime/os_windows_pe.go b/src/runtime/os_windows_pe.go index 53bc62f2b..61f2f7fa0 100644 --- a/src/runtime/os_windows_pe.go +++ b/src/runtime/os_windows_pe.go @@ -48,7 +48,7 @@ func findGlobalsForPE(found func(start, end uintptr)) { pe := (*peHeader)(unsafe.Add(unsafe.Pointer(module), module.peHeader)) if gcAsserts && pe.magic != 0x00004550 { // 0x4550 is "PE" - runtimePanic("cannot find PE header") + runtimeFatal("cannot find PE header") } section := (*peSection)(unsafe.Pointer(uintptr(unsafe.Pointer(pe)) + uintptr(pe.sizeOfOptionalHeader) + unsafe.Sizeof(peHeader{}))) diff --git a/src/runtime/panic.go b/src/runtime/panic.go index 3c5b4029a..ff4bb8af2 100644 --- a/src/runtime/panic.go +++ b/src/runtime/panic.go @@ -145,7 +145,7 @@ func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) { // Defer is not currently allowed in interrupts. // We could add support for this, but since defer might also allocate // (especially in loops) it might not be a good idea anyway. - runtimePanicAt(returnAddress(0), "defer in interrupt") + runtimeFatal("defer in interrupt") } currentTask := task.Current() frame.Previous = (*deferFrame)(currentTask.DeferFrame) @@ -272,5 +272,5 @@ func blockingPanic() { //go:linkname fips_fatal crypto/internal/fips140.fatal func fips_fatal(msg string) { - runtimePanic(msg) + runtimeFatal(msg) } diff --git a/src/runtime/rand.go b/src/runtime/rand.go index 531910ef0..620988bfa 100644 --- a/src/runtime/rand.go +++ b/src/runtime/rand.go @@ -8,4 +8,4 @@ import _ "unsafe" func vgetrandom(p []byte, flags uint32) (ret int, supported bool) { return 0, false } //go:linkname fatal crypto/internal/sysrand.fatal -func fatal(msg string) { runtimePanic(msg) } +func fatal(msg string) { runtimeFatal(msg) } diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index 26d29dbc9..6ad14fe10 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -94,7 +94,7 @@ func nanotime() int64 { // //go:linkname os_sigpipe os.sigpipe func os_sigpipe() { - runtimePanic("too many writes on closed pipe") + runtimeFatal("too many writes on closed pipe") } // LockOSThread wires the calling goroutine to its current operating system thread. diff --git a/src/runtime/runtime_nintendoswitch.go b/src/runtime/runtime_nintendoswitch.go index b2d13f86b..02b7e8c1c 100644 --- a/src/runtime/runtime_nintendoswitch.go +++ b/src/runtime/runtime_nintendoswitch.go @@ -181,7 +181,7 @@ func setupEnv() { default: if entry.Flags&1 > 0 { // Mandatory but not parsed - runtimePanic("mandatory config entry not parsed") + runtimeFatal("mandatory config entry not parsed") } } ptr += unsafe.Sizeof(configEntry{}) @@ -224,7 +224,7 @@ func setupHeap() { svcSetHeapSize(&heapStart, uint64(size)) if heapStart == 0 { - runtimePanic("failed to allocate heap") + runtimeFatal("failed to allocate heap") } totalHeap = uint64(size) @@ -340,6 +340,6 @@ func hardwareRand() (n uint64, ok bool) { func libc_errno_location() *int32 { // CGo is unavailable, so this function should be unreachable. - runtimePanic("runtime: no cgo errno") + runtimeFatal("runtime: no cgo errno") return nil } diff --git a/src/runtime/runtime_rp2.go b/src/runtime/runtime_rp2.go index f6d31f980..09ec364cd 100644 --- a/src/runtime/runtime_rp2.go +++ b/src/runtime/runtime_rp2.go @@ -270,7 +270,7 @@ func coreStackTop(core uint32) uintptr { case 1: return uintptr(unsafe.Pointer(&stack1TopSymbol)) default: - runtimePanic("unexpected core") + runtimeFatal("unexpected core") return 0 } } diff --git a/src/runtime/runtime_tinygoriscv_qemu.go b/src/runtime/runtime_tinygoriscv_qemu.go index 1ee0d22d8..7f4035c4f 100644 --- a/src/runtime/runtime_tinygoriscv_qemu.go +++ b/src/runtime/runtime_tinygoriscv_qemu.go @@ -117,7 +117,7 @@ func handleInterrupt() { sleepCheckpoint.Jump() } default: - runtimePanic("unknown interrupt") + runtimeFatal("unknown interrupt") abort() } } else { @@ -200,7 +200,7 @@ func coreStackTop(core uint32) uintptr { case 3: return uintptr(unsafe.Pointer(&stack3TopSymbol)) default: - runtimePanic("unexpected core") + runtimeFatal("unexpected core") return 0 } } @@ -367,7 +367,7 @@ func (l *spinLock) Lock() { func (l *spinLock) Unlock() { // Safety check: the spinlock should have been locked. if schedulerAsserts && l.Uint32.Load() != 1 { - runtimePanic("unlock of unlocked spinlock") + runtimeFatal("unlock of unlocked spinlock") } // Unlock the lock. Simply write 0, because we already know it is locked. @@ -417,7 +417,7 @@ func schedulerUnlockAndWait() { // We can do this check since this is not baremetal: there won't be any // external interrupts that might unblock a goroutine. if sleepingHarts == (1<