Не можете ли вы определить максимальный размер стека для вашей программы, начало стека, а затем вычислить адрес конца стека? Перед каждой операцией в vm вы можете проверить переполнение стека (увеличение по максимальному адресу) и затем вызвать исключение.
Другой способ - написать идентификатор после конца стека (например, DEADBEEF или около того) и проверять его значение после каждой операции стека.
Я до сих пор не понимаю, почему вы не можете добавить проверки (именно так обычно определяется манипуляция со стеком). Но вы все равно можете добавить аппаратную точку останова (при записи) в конце вашей стековой области. Когда он ломается, вы знаете, что у вас есть стекопоток. Я бы не советовал, хотя это может испортить вашу среду отладки.
Но в основном - если у вас есть виртуальная машина, у вас также есть место, которое читает код (например, байт-код) и компилирует / интерпретирует его. Это место, где вы можете проверить метку (сравнимо с проверками для обнаружения переполнения буфера стека).