Skip to content

setTimeout callbacks with stale closures #12

@rmcc3

Description

@rmcc3

Description

Several setTimeout callbacks capture the layers state at call time, but execute later when layers may have changed.

Affected File

components/canvas-editor.tsx

Current Behavior

// In captureCanvasAsLayer (~line 2280):
setTimeout(async () => {
  // ...
  const updatedLayers = [...layers, newLayer]  // 'layers' is stale!
  setLayers(updatedLayers)
}, 50)

// In handleGLBThumbnailGenerated (~line 2919):
setTimeout(() => setForceRedraw(prev => prev + 1), 50)
setTimeout(() => setForceRedraw(prev => prev + 1), 150)

Security Impact

  • New layers may be lost if user adds/deletes layers during timeout
  • Undo history may become corrupted
  • Canvas state may become inconsistent with layer state

Suggested Fix

Use functional updates consistently:

setTimeout(async () => {
  canvas.toBlob(async (blob) => {
    // ...
    // Use functional update to get latest state
    setLayers(currentLayers => [...currentLayers, newLayer])
  })
}, 50)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions