Skip to content

IntegerDivideByZero Core 1 Panic in WaveformGenerator::setFrequency when called before SoundGenerator::attach #421

Description

@UfkuAcik

Bug Report: IntegerDivideByZero Core 1 Panic in WaveformGenerator::setFrequency when called before SoundGenerator::attach

Note from the author: I am not an expert in ESP32 internals. This entire debugging process, root cause analysis, and the following report were conducted by my AI coding assistant, Gemini 3.1 Pro High, working within the Google Antigravity IDE.

Description

When creating a WaveformGenerator (e.g., SineWaveformGenerator) and immediately setting its frequency using setFrequency(int value) before attaching it to the SoundGenerator via soundGenerator.attach(), the ESP32 crashes instantly with a Guru Meditation Error: Core 1 panic'ed (IntegerDivideByZero). Exception was unhandled.

This happens because the base WaveformGenerator constructor initializes m_sampleRate to 0. When setFrequency is called, it executes the following formula:

m_phaseInc = (((uint32_t)m_frequency * 256) << 11) / sampleRate();

Since sampleRate() is 0, this causes a hardware divide-by-zero exception. m_sampleRate is only properly updated later when soundGenerator.attach(WaveformGenerator * value) is invoked.

The Misleading Stack Trace

This bug was particularly difficult to track down because the exception handler on the ESP32 (Xtensa architecture without a frame pointer) unwinds the stack incorrectly. The resulting backtrace almost always points to _vfiprintf_r or vsnprintf (if there was any recent UI text formatting in FabGL, such as uiLabel::setTextFmt), making it look like a string formatting bug or a memory corruption in newlib.

Steps to Reproduce

  1. Create a SineWaveformGenerator object.
  2. Call setFrequency(440) on it.
  3. Do not call soundGenerator.attach() before setting the frequency.
  4. The ESP32 will reboot in a loop with an IntegerDivideByZero panic.

Snippet that crashes:

auto sineGen = new fabgl::SineWaveformGenerator();
sineGen->setFrequency(440); // CRASH! IntegerDivideByZero
soundGenerator.attach(sineGen); 

Workaround / Fix:
Manually setting the sample rate before calling setFrequency() prevents the crash:

auto sineGen = new fabgl::SineWaveformGenerator();
sineGen->setSampleRate(16000); // or whatever your SoundGenerator sample rate is
sineGen->setFrequency(440); // Works perfectly
soundGenerator.attach(sineGen); 

Environment Details

  • FabGL Version: 1.0.9
  • Arduino Core for ESP32: 2.0.11
  • Hardware: ESP32-D0WD-V3 (revision v3.0)
  • Board Config: PartitionScheme=huge_app, PSRAM=enabled

Suggested Fix in FabGL

In src/devdrivers/soundgen.cpp (and other generator files), the setFrequency methods could be protected against a zero sample rate to prevent hard crashes. For example:

void SineWaveformGenerator::setFrequency(int value) {
  if (m_frequency != value) {
    m_frequency = value;
    if (sampleRate() > 0) {
      m_phaseInc = (((uint32_t)m_frequency * 256) << 11) / sampleRate();
    } else {
      m_phaseInc = 0; // Or defer the calculation until attach() is called
    }
  }
}

Relevant Commit

You can see the exact workaround applied in my project repository here:
Commit: fabgl fix

Thank you for this amazing library!

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