You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Hot Restart does not complete if exceptions are hit during the restart #3448
First, check the All Exceptions and Uncaught Exceptions setting at debug panel.
Then debug the following example code. When debugger stoped at exception in function a, press continue button, the debugger will stoped at catch block in function b. Finally, click restart button, debugger will run into endless waiting.
@bkonyi@jonahwilliams I can repro this, but I'm not sure whether it's a Flutter or VM issue. Here's an annotated log of what happens:
Thu Jul 01 2021 [12:21:44 GMT+0100 (British Summer Time)] Log file started
// Send a Hot Restart
[12:21:50] [FlutterRun] [Info] [Dart ] ==> [{"id":"6","method":"app.restart","params":{"appId":"3b4b3b51-22aa-427d-b47c-108e801a623c","fullRestart":true,"pause":true,"reason":"manual"}}]
[12:21:50] [FlutterRun] [Info] [Dart ] <== [{"event":"app.progress","params":{"appId":"3b4b3b51-22aa-427d-b47c-108e801a623c","id":"2","progressId":"hot.restart","message":"Performing hot restart...","finished":false}}]
[12:21:50] [FlutterRun] [Info] [Dart ] <== [{"event":"app.progress","params":{"appId":"3b4b3b51-22aa-427d-b47c-108e801a623c","id":"3","progressId":null,"message":"Syncing files to device iPhone 12 Pro Max...","finished":false}}]
[12:21:50] [FlutterRun] [Info] [Dart ] <== [{"event":"app.progress","params":{"appId":"3b4b3b51-22aa-427d-b47c-108e801a623c","id":"3","progressId":null,"finished":true}}]
// Something resumes the isolate that was paused at the excepton (Flutter tool?)
[12:21:50] [VmService] [Info] [Dart ] <== {"jsonrpc":"2.0","method":"streamNotify","params":{"streamId":"Debug","event":{"type":"Event","kind":"Resume","isolate":{"type":"@Isolate","id":"isolates/1903522107348907","name":"main","number":"1903522107348907","isSystemIsolate":false},"timestamp":1625138510269,"topFrame":{"type":"Frame","kind":"Regular","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@551033593/scripts/package%3Aflutter_application_1%2Ffoo.dart/17a61cd7c22","uri":"package:flutter_application_1/foo.dart","_kind":"kernel"},"tokenPos":127},"function":{"type":"@Function","fixedId":true,"id":"libraries/@551033593/functions/b","name":"b","owner":{"type":"@Library","fixedId":true,"id":"libraries/@551033593","name":"","uri":"package:flutter_application_1/foo.dart"},"_kind":"RegularFunction","static":true,"const":false,"_intrinsic":false,"_native":false,"location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@551033593/scripts/package%3Aflutter_application_1%2Ffoo.dart/17a61cd7c22","uri":"package:flutter_application_1/foo.dart","_kind":"kernel"},"tokenPos":79,"endTokenPos":153}},"code":{"type":"@Code","fixedId":true,"id":"code/3220792bd-1309b0e40","name":"[Unoptimized] b","kind":"Dart","_optimized":false,"_intrinsic":false,"_native":false},"vars":[{"type":"BoundVariable","name":"e","value":{"type":"@Instance","class":{"type":"@Class","fixedId":true,"id":"classes/237","name":"_Exception","_vmName":"_Exception@0150898","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@0150898/scripts/dart%3Acore%2Fexceptions.dart/0","uri":"dart:core/exceptions.dart","_kind":"kernel"},"tokenPos":1005,"endTokenPos":1243},"library":{"type":"@Library","fixedId":true,"id":"libraries/@0150898","name":"dart.core","uri":"dart:core"}},"identityHashCode":2125179152,"kind":"PlainInstance","id":"objects/99"},"declarationTokenPos":118,"scopeStartTokenPos":119,"scopeEndTokenPos":151}],"index":0}}}}
// Another exception is hit in the code that ran after the resume
[12:21:50] [VmService] [Info] [Dart ] <== {"jsonrpc":"2.0","method":"streamNotify","params":{"streamId":"Debug","event":{"type":"Event","kind":"PauseException","isolate":{"type":"@Isolate","id":"isolates/1903522107348907","name":"main","number":"1903522107348907","isSystemIsolate":false},"timestamp":1625138510269,"topFrame":{"type":"Frame","kind":"Regular","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@551033593/scripts/package%3Aflutter_application_1%2Ffoo.dart/17a61cd7c22","uri":"package:flutter_application_1/foo.dart","_kind":"kernel"},"tokenPos":204},"function":{"type":"@Function","fixedId":true,"id":"libraries/@551033593/functions/c","name":"c","owner":{"type":"@Library","fixedId":true,"id":"libraries/@551033593","name":"","uri":"package:flutter_application_1/foo.dart"},"_kind":"RegularFunction","static":true,"const":false,"_intrinsic":false,"_native":false,"location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@551033593/scripts/package%3Aflutter_application_1%2Ffoo.dart/17a61cd7c22","uri":"package:flutter_application_1/foo.dart","_kind":"kernel"},"tokenPos":156,"endTokenPos":230}},"code":{"type":"@Code","fixedId":true,"id":"code/322079285-1309b0d30","name":"[Unoptimized] c","kind":"Dart","_optimized":false,"_intrinsic":false,"_native":false},"vars":[{"type":"BoundVariable","name":"e","value":{"type":"@Instance","class":{"type":"@Class","fixedId":true,"id":"classes/237","name":"_Exception","_vmName":"_Exception@0150898","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@0150898/scripts/dart%3Acore%2Fexceptions.dart/0","uri":"dart:core/exceptions.dart","_kind":"kernel"},"tokenPos":1005,"endTokenPos":1243},"library":{"type":"@Library","fixedId":true,"id":"libraries/@0150898","name":"dart.core","uri":"dart:core"}},"identityHashCode":739325732,"kind":"PlainInstance","id":"objects/100"},"declarationTokenPos":195,"scopeStartTokenPos":196,"scopeEndTokenPos":228}],"index":0},"exception":{"type":"@Instance","class":{"type":"@Class","fixedId":true,"id":"classes/237","name":"_Exception","_vmName":"_Exception@0150898","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@0150898/scripts/dart%3Acore%2Fexceptions.dart/0","uri":"dart:core/exceptions.dart","_kind":"kernel"},"tokenPos":1005,"endTokenPos":1243},"library":{"type":"@Library","fixedId":true,"id":"libraries/@0150898","name":"dart.core","uri":"dart:core"}},"identityHashCode":1822449961,"kind":"PlainInstance","id":"objects/101"}}}}
// VS Code tries to fetch information/stack for the exception/pause (some of these never respond)
[12:21:50] [VmService] [Info] [Dart ] ==> {"id":"587","jsonrpc":"2.0","method":"invoke","params":{"argumentIds":[],"disableBreakpoints":true,"isolateId":"isolates/1903522107348907","selector":"toString","targetId":"objects/101"}}
[12:21:50] [VmService] [Info] [Dart ] <== {"jsonrpc":"2.0","result":{"type":"@Instance","_vmType":"String","class":{"type":"@Class","fixedId":true,"id":"classes/81","name":"_OneByteString","_vmName":"_OneByteString@0150898","location":{"type":"SourceLocation","script":{"type":"@Script","fixedId":true,"id":"libraries/@0150898/scripts/dart%3Acore-patch%2Fstring_patch.dart/0","uri":"dart:core-patch/string_patch.dart","_kind":"kernel"},"tokenPos":32310,"endTokenPos":44599},"library":{"type":"@Library","fixedId":true,"id":"libraries/@0150898","name":"dart.core","uri":"dart:core"}},"identityHashCode":0,"kind":"String","id":"objects/102","length":12,"valueAsString":"Exception: c"},"id":"587"}
[12:21:50] [VmService] [Info] [Dart ] ==> {"id":"588","jsonrpc":"2.0","method":"getObject","params":{"isolateId":"isolates/1903522107348907","objectId":"objects/101"}}
[12:21:50] [VmService] [Info] [Dart ] ==> {"id":"589","jsonrpc":"2.0","method":"getStack","params":{"isolateId":"isolates/1903522107348907","limit":20}}
// I clicked Resume to try and continue from the exception pause, but that also never responds
[12:21:58] [VmService] [Info] [Dart ] ==> {"id":"590","jsonrpc":"2.0","method":"resume","params":{"isolateId":"isolates/1903522107348907"}}
Thu Jul 01 2021 [12:22:21 GMT+0100 (British Summer Time)] Log file ended
changed the title [-]restart will alway pending when there are many break points [/-][+]restart will always pending when there are many breakpoints [/+]on Jul 2, 2021
In fact, this issue often happens when I debug hybird app using flutter attach. At that time, I usually have to uncheck All Exceptions and Uncaught Exceptions setting at debug panel. Then press the continue button in debug toolbar and restart.
The flutter engine cannot hot restart if it is paused at a breakpoint , so the tool will attempt to remove breakpoints before performing the hot restart. looks like this doesn't work well if its due to an exception - but unfortunately I'm not sure there is any way around it.
Hot restart has some requirements to run on the same thread as the dart ui thread, that requires it to be un-paused. The only way to fix this would be to find a way to relax this requirement.
I would file a new issue on the flutter issue tracker.
so the tool will attempt to remove breakpoints before performing the hot restart. looks like this doesn't work well if its due to an exception - but unfortunately I'm not sure there is any way around it.
Does it put these back, or rely on the IDE doing it? Perhaps it could also just set the pause-on-exception behaviour to Non (and then also put that back, or rely on the IDE putting it back)?
changed the title [-]restart will always pending when there are many breakpoints [/-][+]Hot Restart does not complete if exceptions are hit during the restart[/+]on Jul 3, 2021
I don't think its putting these back - since the restart destroys breakpoints anyway. We could definitely try disabling the pause on exception behavior - will the IDE reset that after a restart?
It doesn't seem like it today - but I don't think it would be an unreasonable request for them to do so if it would fix this (another option could be to force the IDEs to remove it before sending the hot reload then put them back - avoiding any changes in Flutter - although I think for consistency it'd be better done in the tool along with the breakpoints).
@jacob314@stevemessick wdyt? Does it seem reasonable to also update IntelliJ/DevTools to re-send pause-on-exception behaviour when they re-send breakpoints after a restart? If we shipped that, we could then update Flutter tools to reset it during the restart, which would solve this issue.
In VS Code we pass pause:true when restarting so we can re-send the breakpoints (so doing it there seems like a reasonable place). If the tool was doing it and pause:true was not passed, there could be races - but that would be the case for the breakpoints the editor is sending too so I suspect the tools would probably all be using pause:true.
There's also the possibility that DDS may take on some of what the editors currently do (like resetting breakpoints after a restart) - there are some weird cases if you have multiple tools attached. If so, maybe this would fit nicely there too. I don't know if there are concrete plans in this area yet though (@bkonyi may).
@jacob314@stevemessick do you have any thoughts on the above? If Flutter started resetting the break-on-exception behaviour during a restart, is it reasonable for IntelliJ/DevTools (and VS Code) to re-set them along with breakpoints before unpausing after the restart?
(or @bkonyi - are there plans for DDS to handle some of this behaviour, and would it make sense handled there?)
I've added a fix to VS Code that disables pause-on-exceptions during a Hot Restart. It turns out we don't need to re-set it, because the restart results in a new isolate, which means we re-transmit all breakpoints and exception-pause behaviour anyway.
The fix is currently only in the Dart-Code DAP, but also needs replicating in the SDK DAP. If we can confirm AS/IntelliJ also always send the pause-exception behaviour during a restart, we could move this to the tool instead.
It turned out this doesn't need any cooperation from the IDEs to fix in Flutter. The flag is per-isolate and and the restart creates new isolates, so it's safe to just remove the flag on the existing isolates before the resume (same pace as breakpoints are removed) and the IDE already needs to set this flag on new isolates that are created.
I've opened a PR to move the fix to Flutter in flutter/flutter#93411 since we needed it Flutter-side for the Flutter SDK DAP anyway.
Activity
DanTup commentedon Jul 1, 2021
@bkonyi @jonahwilliams I can repro this, but I'm not sure whether it's a Flutter or VM issue. Here's an annotated log of what happens:
Is this best raised in Flutter or SDK repo?
[-]restart will alway pending when there are many break points [/-][+]restart will always pending when there are many breakpoints [/+]tjx666 commentedon Jul 3, 2021
In fact, this issue often happens when I debug hybird app using
flutter attach. At that time, I usually have to uncheckAll ExceptionsandUncaught Exceptionssetting at debug panel. Then press thecontinuebutton in debug toolbar and restart.jonahwilliams commentedon Jul 3, 2021
The flutter engine cannot hot restart if it is paused at a breakpoint , so the tool will attempt to remove breakpoints before performing the hot restart. looks like this doesn't work well if its due to an exception - but unfortunately I'm not sure there is any way around it.
Hot restart has some requirements to run on the same thread as the dart ui thread, that requires it to be un-paused. The only way to fix this would be to find a way to relax this requirement.
I would file a new issue on the flutter issue tracker.
DanTup commentedon Jul 3, 2021
Does it put these back, or rely on the IDE doing it? Perhaps it could also just set the pause-on-exception behaviour to Non (and then also put that back, or rely on the IDE putting it back)?
[-]restart will always pending when there are many breakpoints [/-][+]Hot Restart does not complete if exceptions are hit during the restart[/+]jonahwilliams commentedon Jul 3, 2021
I don't think its putting these back - since the restart destroys breakpoints anyway. We could definitely try disabling the pause on exception behavior - will the IDE reset that after a restart?
DanTup commentedon Jul 3, 2021
It doesn't seem like it today - but I don't think it would be an unreasonable request for them to do so if it would fix this (another option could be to force the IDEs to remove it before sending the hot reload then put them back - avoiding any changes in Flutter - although I think for consistency it'd be better done in the tool along with the breakpoints).
@jacob314 @stevemessick wdyt? Does it seem reasonable to also update IntelliJ/DevTools to re-send pause-on-exception behaviour when they re-send breakpoints after a restart? If we shipped that, we could then update Flutter tools to reset it during the restart, which would solve this issue.
jonahwilliams commentedon Jul 3, 2021
We could also re-enable from the tool as well. I'm not sure if there would be timing issues though
DanTup commentedon Jul 6, 2021
In VS Code we pass
pause:truewhen restarting so we can re-send the breakpoints (so doing it there seems like a reasonable place). If the tool was doing it andpause:truewas not passed, there could be races - but that would be the case for the breakpoints the editor is sending too so I suspect the tools would probably all be usingpause:true.There's also the possibility that DDS may take on some of what the editors currently do (like resetting breakpoints after a restart) - there are some weird cases if you have multiple tools attached. If so, maybe this would fit nicely there too. I don't know if there are concrete plans in this area yet though (@bkonyi may).
DanTup commentedon Aug 24, 2021
@jacob314 @stevemessick do you have any thoughts on the above? If Flutter started resetting the break-on-exception behaviour during a restart, is it reasonable for IntelliJ/DevTools (and VS Code) to re-set them along with breakpoints before unpausing after the restart?
(or @bkonyi - are there plans for DDS to handle some of this behaviour, and would it make sense handled there?)
DanTup commentedon Oct 25, 2021
I've added a fix to VS Code that disables pause-on-exceptions during a Hot Restart. It turns out we don't need to re-set it, because the restart results in a new isolate, which means we re-transmit all breakpoints and exception-pause behaviour anyway.
The fix is currently only in the Dart-Code DAP, but also needs replicating in the SDK DAP. If we can confirm AS/IntelliJ also always send the pause-exception behaviour during a restart, we could move this to the tool instead.
DanTup commentedon Oct 26, 2021
I've opened #3631 to track the Flutter DAP fix, as it's a bit stalled on the main DAP work landing.
DanTup commentedon Nov 10, 2021
It turned out this doesn't need any cooperation from the IDEs to fix in Flutter. The flag is per-isolate and and the restart creates new isolates, so it's safe to just remove the flag on the existing isolates before the resume (same pace as breakpoints are removed) and the IDE already needs to set this flag on new isolates that are created.
I've opened a PR to move the fix to Flutter in flutter/flutter#93411 since we needed it Flutter-side for the Flutter SDK DAP anyway.