Opened 2 years ago

Closed 15 months ago

#6550 closed defect (fixed)

Crash atlas in relation to Terrain.cpp CalcPosition

Reported by: Langbart Owned by: trompetin17
Priority: Must Have Milestone: Alpha 27
Component: Atlas editor Keywords:
Cc: Patch: Phab:D4900

Description

Testing on the latest GIT version [26910].

to reproduce

  • Start the editor
  • Click Paint terrain texture
  • Click Terrain
  • Hold Shift and do a single click at the ground texture
  • Click Map icon
  • Click Change players and change the Num players from 8 to 2
  • Click Map icon again
  • Click Generate map
  • Boom
GAME STARTED, ALL INIT COMPLETE
pyrogenesis was compiled with optimization - stepping may behave oddly; variables may not be available.
Process 40415 stopped
* thread #1, name = 'main', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x000000010033b723 pyrogenesis`CTerrain::CalcPosition(this=<unavailable>, i=<unavailable>, j=95, pos=0x00007ffeefbfafb0) const at Terrain.cpp:106:15 [opt]
   103 	{
   104 		ssize_t hi = Clamp<ssize_t>(i, 0, m_MapSize - 1);
   105 		ssize_t hj = Clamp<ssize_t>(j, 0, m_MapSize - 1);
-> 106 		u16 height = m_Heightmap[hj*m_MapSize + hi];
   107 		pos.X = float(i*TERRAIN_TILE_SIZE);
   108 		pos.Y = float(height*HEIGHT_SCALE);
   109 		pos.Z = float(j*TERRAIN_TILE_SIZE);
Target 0: (pyrogenesis) stopped.
(lldb) bt

Note: If there is no crash, try it a couple of times. Sometimes it does occur on the first attempt, sometimes it takes up to 3 runs.

See GIF below for more clarity

Higher quality video (link will be dead within a year)

lldb

(lldb) bt
* thread #1, name = 'main', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x000000010033b723 pyrogenesis`CTerrain::CalcPosition(this=<unavailable>, i=<unavailable>, j=95, pos=0x00007ffeefbfafb0) const at Terrain.cpp:106:15 [opt]
    frame #1: 0x00000001003bef31 pyrogenesis`TerrainOverlay::RenderTile(this=0x000000011241eae0, deviceCommandContext=0x0000000110ee6310, color=0x00007ffeefbfb030, drawHidden=<unavailable>, i=51, j=95) at TerrainOverlay.cpp:160:15 [opt]
    frame #2: 0x0000000100414161 pyrogenesis`BrushTerrainOverlay::ProcessTile(this=0x000000011241eae0, deviceCommandContext=0x0000000110ee6310, i=<unavailable>, j=<unavailable>) at Brushes.cpp:67:3 [opt]
    frame #3: 0x00000001003bee4c pyrogenesis`TerrainOverlay::RenderBeforeWater(this=0x000000011241eae0, deviceCommandContext=0x0000000110ee6310) at TerrainOverlay.cpp:137:4 [opt]
    frame #4: 0x00000001003be67d pyrogenesis`ITerrainOverlay::RenderOverlaysBeforeWater(deviceCommandContext=0x0000000110ee6310) at TerrainOverlay.cpp:77:34 [opt]
    frame #5: 0x00000001003b0409 pyrogenesis`CSceneRenderer::RenderRefractions(this=0x000000010b074260, deviceCommandContext=0x0000000110ee6310, context=0x00007ffeefbfb3d0, scissor=<unavailable>) at SceneRenderer.cpp:672:2 [opt]
    frame #6: 0x00000001003b0e3a pyrogenesis`CSceneRenderer::RenderSubmissions(this=0x000000010b074260, deviceCommandContext=0x0000000110ee6310, waterScissor=0x00007ffeefbfb610) at SceneRenderer.cpp:810:5 [opt]
    frame #7: 0x00000001003b2130 pyrogenesis`CSceneRenderer::RenderScene(this=0x000000010b074260, deviceCommandContext=0x0000000110ee6310, scene=0x0000000113487410) at SceneRenderer.cpp:1143:2 [opt]
    frame #8: 0x00000001003a4671 pyrogenesis`CRenderer::RenderFrameImpl(this=0x0000000110ee47e0, renderGUI=<unavailable>, renderLogger=<unavailable>) at Renderer.cpp:459:22 [opt]
    frame #9: 0x00000001003a444d pyrogenesis`CRenderer::RenderFrame(this=0x0000000110ee47e0, needsPresent=false) at Renderer.cpp:416:3 [opt]
    frame #10: 0x0000000100459c17 pyrogenesis`AtlasViewGame::Render(this=<unavailable>) at View.cpp:232:13 [opt]
    frame #11: 0x000000010042a227 pyrogenesis`AtlasMessage::fRenderLoop(msg=0x00007ffeefbfbb20) at GraphicsSetupHandlers.cpp:252:25 [opt]
    frame #12: 0x0000000100451248 pyrogenesis`MessagePasserImpl::Query(this=<unavailable>, msg=0x00007ffeefbfbb20, (null)=<unavailable>)()) at MessagePasserImpl.cpp:68:3 [opt]
    frame #13: 0x00000001082725f5 libAtlasUI.dylib`ScenarioEditor::OnTimer(wxTimerEvent&) [inlined] AtlasMessage::QueryMessage::Post(this=<unavailable>) at ScenarioEditor.cpp:1157:19 [opt]
    frame #14: 0x00000001082725df libAtlasUI.dylib`ScenarioEditor::OnTimer(this=0x000000010584f800, evt=<unavailable>) at ScenarioEditor.cpp:696 [opt]
    frame #15: 0x00000001085a498f libAtlasUI.dylib`wxEventHashTable::HandleEvent(wxEvent&, wxEvtHandler*) + 447
    frame #16: 0x00000001085a5f3a libAtlasUI.dylib`wxEvtHandler::ProcessEventLocally(wxEvent&) + 90
    frame #17: 0x00000001085a5dd0 libAtlasUI.dylib`wxEvtHandler::ProcessEvent(wxEvent&) + 96
    frame #18: 0x00000001085a64ec libAtlasUI.dylib`wxEvtHandler::SafelyProcessEvent(wxEvent&) + 12
    frame #19: 0x000000010856062a libAtlasUI.dylib`wxTimerImpl::SendEvent() + 90
    frame #20: 0x00007fff38a91718 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 20
    frame #21: 0x00007fff38a9127e CoreFoundation`__CFRunLoopDoTimer + 872
    frame #22: 0x00007fff38a90d69 CoreFoundation`__CFRunLoopDoTimers + 322
    frame #23: 0x00007fff38a759ed CoreFoundation`__CFRunLoopRun + 1885
    frame #24: 0x00007fff38a74c33 CoreFoundation`CFRunLoopRunSpecific + 466
    frame #25: 0x00007fff37690aad HIToolbox`RunCurrentEventLoopInMode + 292
    frame #26: 0x00007fff376906e4 HIToolbox`ReceiveNextEventCommon + 359
    frame #27: 0x00007fff37690569 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 64
    frame #28: 0x00007fff35cd93c9 AppKit`_DPSNextEvent + 883
    frame #29: 0x00007fff35cd7c10 AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1352
    frame #30: 0x00007fff35cc991e AppKit`-[NSApplication run] + 658
    frame #31: 0x00000001083aaa8a libAtlasUI.dylib`wxGUIEventLoop::OSXDoRun() + 186
    frame #32: 0x000000010858441d libAtlasUI.dylib`wxCFEventLoop::DoRun() + 29
    frame #33: 0x00000001084fcffe libAtlasUI.dylib`wxEventLoopBase::Run() + 158
    frame #34: 0x00000001084cf9b3 libAtlasUI.dylib`wxAppConsoleBase::MainLoop() + 99
    frame #35: 0x000000010836baaa libAtlasUI.dylib`wxApp::OnRun() + 26
    frame #36: 0x000000010827013e libAtlasUI.dylib`::Atlas_StartWindow(type=<unavailable>) at DLLInterface.cpp:154:12 [opt]
    frame #37: 0x0000000100415092 pyrogenesis`BeginAtlas(args=0x00007ffeefbff310, dll=0x0000000103c52ab8) at GameLoop.cpp:136:2 [opt]
    frame #38: 0x00000001002069fd pyrogenesis`ATLAS_RunIfOnCmdLine(CmdLineArgs const&, bool) [inlined] ATLAS_Run(args=0x00007ffeefbff310, flags=1) at Atlas.cpp:54:7 [opt]
    frame #39: 0x00000001002069de pyrogenesis`ATLAS_RunIfOnCmdLine(args=0x00007ffeefbff310, force=<unavailable>) at Atlas.cpp:77 [opt]
    frame #40: 0x00000001000049be pyrogenesis`RunGameOrAtlas(argc=<unavailable>, argv=<unavailable>) at main.cpp:573:6 [opt]
    frame #41: 0x0000000100003b76 pyrogenesis`main(argc=2, argv=0x00007ffeefbff650) at main.cpp:739:2 [opt]
    frame #42: 0x00007fff727aacc9 libdyld.dylib`start + 1

reproducible

The crash could be reproduced up to A22, after which I stopped testing.

Attachments (1)

crash.gif (1.8 MB ) - added by Langbart 2 years ago.

Download all attachments as: .zip

Change History (5)

by Langbart, 2 years ago

Attachment: crash.gif added

comment:1 by Vladislav Belov, 18 months ago

Priority: Should HaveMust Have

comment:2 by trompetin17, 15 months ago

The problem is able to reproduce without modify player, step to reproduce:

Use any terrain modify tool close to the edge and then "generate random map" and you are going to see how atlas is going to crash.

checking the code in high lvl the problem sounds related about map size, _default.xml use

<Terrain patches="16" texture="aegean_grass_dirt_01" priority="0" height="4096"/>

looks like a "Normal" map size with 256 tiles, when you generate a random map, the map size option has selected tiny.

		{
			"Name": "Tiny",
			"Tooltip": "This map size has barely any room for even the most basic 			resources.",
			"Tiles": 128
		},

I realized that all stuff about brush use the same object "Brush AtlasMessage::g_CurrentBrush".

That mean when you use any brush it set Width and height

void Brush::SetData(ssize_t w, ssize_t h, const std::vector<float>& data)

but when you create a random nap with a different size, the Brush is never "shutdown"/"reinitialize" so the next call from screen render, it ask to ITextureOVerlay to execute "ProcessTile" and Brush have the previous value from map.

SOLUTION: make sure we call deactive the current tool before we send the message to create the random map, like we use to do when we are going to open a new map

// Deactivate tools, so they don't carry forwards into the new CWorld
// and crash.
m_ToolManager.SetCurrentTool(_T(""));
// TODO: clear the undo buffer, etc

from here https://code.wildfiregames.com/source/0ad/browse/ps/trunk/source/tools/atlas/AtlasUI/ScenarioEditor/ScenarioEditor.cpp$758

comment:3 by trompetin17, 15 months ago

Owner: set to trompetin17
Patch: ​Phab:D4900
Status: newassigned

comment:4 by trompetin17, 15 months ago

Resolution: fixed
Status: assignedclosed

In 27499:

Fix: Crash atlas in relation to Terrain.cpp CalcPosition

Patch by: @trompetin17
Differential revision: https://code.wildfiregames.com/D4900
Comments by: @Langbart, @Stan, @Vladislav
Fixes #6550

Note: See TracTickets for help on using tickets.