Making a copy of some measures crushes the app
Issue overview
Making a copy of some measures crushes the app.
Current Behavior
Making a copy of some measures crushes the app. For example, making a copy of SetBoilerThermalEfficiency crushes the app.
Expected Behavior
A folder named “set_boiler_thermal_efficiency_copy” should be popped up.
Steps to Reproduce
- Select the measure SetBoilerThermalEfficiency.
- Click the copy button.
- Click the button “Create Measure and Open for Editing”. Following is the video link of this bug. https://drive.google.com/file/d/1rmfqqPzxO0rk_7-culWJuJtyhv54sXjv/view?usp=sharing
Details
Environment
- Platform (Operating system, version): Windows 10 Pro (1909) for Workstations
- Version of OpenStudio Application: OpenStudio Application 1.1.0
Issue confirmed with Ubuntu 18.04, application 1.2.0-rc2 (local build of it). It only does so for BCL measures, it works fine for local measures.
Haha, I used a C++ debugger and stopped to inspect what the program was doing. I think there's an infinite loop happening that's not hard to spot (frame number 2)
Since the github formatting isn't helping, here's what I see

[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/measure.xml' -> 'measure.xml'
[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/measure.rb' -> 'measure.rb'
[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/tests/USA_CO_Golden-NREL.724666_TMY3.epw' -> 'USA_CO_Golden-NREL.724666_TMY3.epw'
[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/tests/test5.osm' -> 'test5.osm'
[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/tests/apply_end_use_subcategory_Test.rb' -> 'apply_end_use_subcategory_Test.rb'
[FilesystemHelpers] <-2> directory_elements '/home/julien/BCL/33833705-0ae8-4d53-ab95-723f35f89d2c/a77c3953-9370-4b44-a76c-f9f939d8eeb0/resources/End-Use Subcategory OpenStudio Measure Design Doc-rev01.pdf' -> 'End-Use Subcategory OpenStudio Measure Design Doc-rev01.pdf'
This version of LLDB has no plugin for the mipsassem language. Inspection of frame variables will be limited.
Process 5754 stopped
* thread #1, name = 'OpenStudioApp', stop reason = signal SIGSTOP
frame #0: 0x00007fffece43b46 libc.so.6`__memmove_ssse3 at memcpy-ssse3.S:2995
(lldb) bt
* thread #1, name = 'OpenStudioApp', stop reason = signal SIGSTOP
* frame #0: 0x00007fffece43b46 libc.so.6`__memmove_ssse3 at memcpy-ssse3.S:2995
frame #1: 0x00007fffed7b76b1 libstdc++.so.6`std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long) + 161
frame #2: 0x00007ffff3287f36 libopenstudiolib.so`openstudio::replace(input="require 'openstudio'\nrequire 'openstudio/ruleset/ShowRunnerOutput'\nrequire 'minitest/autorun'\n\nrequire_relative '../measure.rb'\n\nrequire 'fileutils'\n\nclass ApplyEndUseSubcategoryCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCopyCo"..., before="ApplyEndUseSubcategory", after="ApplyEndUseSubcategoryCopy") at StringHelpers.cpp:390:44
frame #3: 0x00007ffff31a1ef0 libopenstudiolib.so`openstudio::BCLMeasure::updateMeasureTests(this=0x00007fffffffaf48, oldClassName="ApplyEndUseSubcategory", newClassName="ApplyEndUseSubcategoryCopy") at BCLMeasure.cpp:878:43
frame #4: 0x0000555555d6e059 OpenStudioApp`openstudio::BCLMeasureDialog::createMeasure(this=0x0000555557e53290) at BCLMeasureDialog.cpp:222:33
frame #5: 0x0000555555aaa294 OpenStudioApp`openstudio::MeasureManager::duplicateSelectedMeasure(this=0x0000555556c066b0) at MeasureManager.cpp:1025:69
frame #6: 0x000055555599f0e1 OpenStudioApp`openstudio::OSAppBase::duplicateSelectedMeasure(this=0x00007fffffffcac0) at OSAppBase.cpp:207:44
frame #7: 0x0000555555d73c33 OpenStudioApp`openstudio::LocalLibraryController::duplicateSelectedMeasure(this=0x0000555557a7ec80) at LocalLibraryController.cpp:112:34
frame #8: 0x0000555555d80388 OpenStudioApp`QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (openstudio::LocalLibraryController::*)()>::call(f=08 3c d7 55 55 55 00 00 00 00 00 00 00 00 00 00, o=0x0000555557a7ec80, arg=0x00007fffffffbd00)(), openstudio::LocalLibraryController*, void**) at qobjectdefs_impl.h:152:20
frame #9: 0x0000555555d7ec8e OpenStudioApp`void QtPrivate::FunctionPointer<void (openstudio::LocalLibraryController::*)()>::call<QtPrivate::List<>, void>(f=08 3c d7 55 55 55 00 00 00 00 00 00 00 00 00 00, o=0x0000555557a7ec80, arg=0x00007fffffffbd00)(), openstudio::LocalLibraryController*, void**) at qobjectdefs_impl.h:185:95
frame #10: 0x0000555555d7caad OpenStudioApp`QtPrivate::QSlotObject<void (openstudio::LocalLibraryController::*)(), QtPrivate::List<>, void>::impl(which=1, this_=0x0000555557d66740, r=0x0000555557a7ec80, a=0x00007fffffffbd00, ret=0x0000000000000000) at qobjectdefs_impl.h:418:49
frame #11: 0x00007fffedd58e80 libQt5Core.so.5`void doActivate<false>(QObject*, int, void**) + 912
frame #12: 0x00007fffeedfb882 libQt5Widgets.so.5`QAbstractButton::clicked(bool) + 50
frame #13: 0x00007fffeedfba8a libQt5Widgets.so.5`QAbstractButtonPrivate::emitClicked() + 58
frame #14: 0x00007fffeedfd70f libQt5Widgets.so.5`QAbstractButtonPrivate::click() + 207
frame #15: 0x00007fffeedfd875 libQt5Widgets.so.5`QAbstractButton::mouseReleaseEvent(QMouseEvent*) + 213
frame #16: 0x00007fffeed4e5e0 libQt5Widgets.so.5`QWidget::event(QEvent*) + 496
frame #17: 0x00007fffeed1013c libQt5Widgets.so.5`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 156
frame #18: 0x00007fffeed17268 libQt5Widgets.so.5`QApplication::notify(QObject*, QEvent*) + 2056
frame #19: 0x000055555599e78b OpenStudioApp`openstudio::OSAppBase::notify(this=0x00007fffffffcac0, receiver=0x0000555557bb7a10, e=0x00007fffffffc210) at OSAppBase.cpp:78:30
frame #20: 0x00005555559742c3 OpenStudioApp`openstudio::OpenStudioApp::notify(this=0x00007fffffffcac0, receiver=0x0000555557bb7a10, event=0x00007fffffffc210) at OpenStudioApp.cpp:1044:27
frame #21: 0x00007fffedd208f8 libQt5Core.so.5`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 264
frame #22: 0x00007fffeed1625a libQt5Widgets.so.5`QApplicationPrivate::sendMouseEvent(QWidget*, QMouseEvent*, QWidget*, QWidget*, QWidget**, QPointer<QWidget>&, bool, bool) + 506
frame #23: 0x00007fffeed67e79 libQt5Widgets.so.5`QWidgetWindow::handleMouseEvent(QMouseEvent*) + 1785
frame #24: 0x00007fffeed6ab5b libQt5Widgets.so.5`QWidgetWindow::event(QEvent*) + 651
frame #25: 0x00007fffeed1013c libQt5Widgets.so.5`QApplicationPrivate::notify_helper(QObject*, QEvent*) + 156
frame #26: 0x00007fffeed16d10 libQt5Widgets.so.5`QApplication::notify(QObject*, QEvent*) + 688
frame #27: 0x000055555599e78b OpenStudioApp`openstudio::OSAppBase::notify(this=0x00007fffffffcac0, receiver=0x0000555557d6ff90, e=0x00007fffffffc670) at OSAppBase.cpp:78:30
frame #28: 0x00005555559742c3 OpenStudioApp`openstudio::OpenStudioApp::notify(this=0x00007fffffffcac0, receiver=0x0000555557d6ff90, event=0x00007fffffffc670) at OpenStudioApp.cpp:1044:27
frame #29: 0x00007fffedd208f8 libQt5Core.so.5`QCoreApplication::notifyInternal2(QObject*, QEvent*) + 264
frame #30: 0x00007fffee3e7ec8 libQt5Gui.so.5`QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent*) + 1592
frame #31: 0x00007fffee3e93a5 libQt5Gui.so.5`QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent*) + 261
frame #32: 0x00007fffee3c517b libQt5Gui.so.5`QWindowSystemInterface::sendWindowSystemEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 203
frame #33: 0x00007fffd8bcd3aa libQt5XcbQpa.so.5`xcbSourceDispatch(_GSource*, int (*)(void*), void*) + 26
frame #34: 0x00007fffe0e30537 libglib-2.0.so.0`g_main_context_dispatch + 743
frame #35: 0x00007fffe0e30770 libglib-2.0.so.0`___lldb_unnamed_symbol192$$libglib-2.0.so.0 + 512
frame #36: 0x00007fffe0e307fc libglib-2.0.so.0`g_main_context_iteration + 44
frame #37: 0x00007fffedd7c11c libQt5Core.so.5`QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) + 92
frame #38: 0x00007fffedd1f30a libQt5Core.so.5`QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) + 266
frame #39: 0x00007fffedd282b3 libQt5Core.so.5`QCoreApplication::exec() + 131
frame #40: 0x0000555555967d68 OpenStudioApp`main(argc=1, argv=0x00007fffffffcd48) at main.cpp:238:28
frame #41: 0x00007fffeccf3bf7 libc.so.6`__libc_start_main(main=(OpenStudioApp`main at main.cpp:119:34), argc=1, argv=0x00007fffffffcd48, init=<unavailable>, fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007fffffffcd38) at libc-start.c:310
frame #42: 0x0000555555966fea OpenStudioApp`_start + 42
THis happens here: https://github.com/NREL/OpenStudio/blob/734787b8bb99d3507d1a7a7adcdfe202212eabc7/src/utilities/bcl/BCLMeasure.cpp#L878
In repalce... before="CreateBaselineBuilding", after="CreateBaselineBuildingCopy"
https://github.com/NREL/OpenStudio/blob/734787b8bb99d3507d1a7a7adcdfe202212eabc7/src/utilities/core/StringHelpers.cpp#L380-L394
How the hell was that working before?
Bottom line is that:
We have a measure called Measure. By default when you click duplicateMeasure in the OS App, it will propose a new name Measure Copy. So when openstudio::replace is called, after (thing to replace with) contains the substring before (the thing to replace). And since the openstudio::replace is broken (missing loc += after.size(); after the replace), it constantly finds it...
I'm pretty sure it never worked, we just didn't really notice because usually you would actually change the measure name... I'll open an issue on the OpenStudio side.
I made a MCVE on compiler explorer: https://godbolt.org/z/4s11s6ccM
Moved issue to https://github.com/NREL/OpenStudio/issues/4331
Fixed via https://github.com/NREL/OpenStudio/pull/4332