How to debug code that crashes the app?

I have a problem, I have some code that crashes the app but I don’t know where it is. Often to debug I will use prints and errors to find the problem but I can’t do that if the app crashes, any tips on how to find my bug?

If the app crashes back to iOS and you can’t see normal print statements, you can use something like save project data to save some info. After the app crashed you can restart the app and read project data to see what you saved.

@ellie_ff1493 it would really help if you showed us the code. If you don’t want to, then to add on to what @dave1707 said, look at all the code that is outside of functions, and look at the setup function. Those two are most prone to causing crashes

Actually, the thing that causes a Codea program to crash the most is using too much memory before it can be cleared. Just for kicks, add the statement collectgarbage() at the beginning of the draw() function and see if the app still crashes. If it doesn’t, then it’s a memory issue. Are you drawing/creating a lot of images or using the camera to create images. Those usually cause a crash.

@dave1707 You are correct, except he is saying that the program isn’t even starting up because it crashes immediately. I don’t think the program gets a chance to make it to the draw() function

@CamelCoder Where does it say that the app crashes on startup. I read that it crashes but they don’t know where. They said they would put print statement in the code but they can’t because the app crashes. So, does it crash back to iOS. If that’s the case, then using saveprojectdata might help because you can go back and see what was saved. As you mentioned, it would help if we could see some code or at least have more information about what’s happening.

Here is the code

Bubbles = class()

function Bubbles:init(x, y)
    -- Initialising our bubble emitter
    self.x = x
    self.y = y
    self.bubbles = {}
    self.maxbubbles = 100
    self.bubblecount = 0
    m = mesh()
    m.shader = shader("Project:Stck")
    m:addRect(WIDTH/2, HEIGHT/2, WIDTH-50, HEIGHT-50)
    
    self.m = m
end

function Bubbles:emit()
    -- Make sure we don't emit more than maxbubbles
    if self.bubblecount < self.maxbubbles then
        local dir = vec2(0,1):rotate(math.random() - 0.5) * math.random(1,6)
        local size = math.random(10, 50)
        local life = math.random(30, 60)
        local bubble = {pos = vec2(self.x, self.y), 
                        dir = dir, 
                        size = size, 
                        life = life}
        
        -- Bubbles have the following properties
        --  dir: direction
        --  size: size of the bubble
        --  life: how many frames the bubble lives
        --  pos: the initial position of the bubble 
        --   (all bubbles start at the emitter position)
        
        -- Add the bubble to our table of bubbles
        table.insert(self.bubbles, bubble)
        
        -- Keep track of how many bubbles we have
        self.bubblecount = self.bubblecount + 1
    end
end

-- This function updates all the bubbles in the system
function Bubbles:update()
    -- Loop through bubbles
    for k,v in pairs(self.bubbles) do
        -- Add direction of bubble to its
        --  position, to generate new position
        v.pos = v.pos + v.dir
        
        -- Subtract one from its life
        v.life = v.life - 1
        
        -- If this bubble's life is 0
        if v.life == 0 then
            -- Remove it from the table
            self.bubbles[k] = nil
            
            -- Reduce our bubble count
            --  (we can emit more now!)
            self.bubblecount = self.bubblecount - 1
        end
    end
end

-- This function draws all the bubbles in the system
function Bubbles:draw()
    -- Store current style
    pushStyle()
    
    -- Set up our bubble style
    ellipseMode(CENTER)
    stroke(255)
    strokeWidth(4)
    fill(153, 197, 210, 100)
    
    -- Loop through bubbles and draw them
    arr = {}
    for i = 0, 99 do
        v = self.bubbles[i]
        if v==nil then 
            table.insert(arr, vec2(0,0))
            
        else
            table.insert(arr, vec2(v.pos.x/WIDTH, v.pos.y/HEIGHT))
        end
        
        
    end
    
    -- print(#arr)
    self.m.shader.points = arr
    
    self.m.shader.len = #self.bubbles
    self.m:draw()
    for k,v in pairs(self.bubbles) do
        -- ellipse(v.pos.x, v.pos.y, v.size)
    end
    
    -- Restore original style
    popStyle()
end

-- Use this function to perform your initial setup
function setup()

    displayMode(OVERLAY)

    -- Create a global bubble emitter
    emitter = Bubbles(0, 0)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    fill(255)
    text("Drag your finger to make bubbles", WIDTH/1.5, HEIGHT - 40)
    
    -- Update and draw bubbles
    emitter:update()
    emitter:draw()
end

-- This function gets called whenever a touch event occurs
function touched(touch)
    -- Whenever the screen encounters a touch event we:
    --  update the emitter position
    --  emit a single bubble
    emitter.x = touch.x
    emitter.y = touch.y
    emitter:emit()
    
    -- Touch events happen when your finger moves, begins
    --  touching or ends touching
end

And the fragment shader

precision highp float;
uniform vec2 points[100];
uniform int len;
varying lowp vec4 vColor;

//The interpolated texture coordinate for this fragment
varying highp vec2 vTexCoord;

void main(){
    float num = 0.;
    for (int i=0; i<len; i++){
        num += 0.02 / distance(vTexCoord, points[i])+0.00001;
    }
    if (num > .8) {
        gl_FragColor = vec4(1,1,1,1);
    }
    else{
        gl_FragColor = vec4(0,0,0,1);
        }
}

I have also narrowed it down.
If I stop the code by pressing back it will crash but if I stop the code it’s less likely to crash.
If I resize the console it will crash

@ellie_ff1493 Your code ran without crashing, but it didn’t do anything. I made some changes so it would work. At least I think this is what it’s supposed to do. I took all the comments out just to shorten the repost. I’m not sure how you were doing the shader, but I changed it to the way I use shaders.

displayMode(FULLSCREEN)

function setup()
    emitter = Bubbles(0, 0)
end

function draw()
    background(40, 40, 50)
    fill(255)
    text("Drag your finger to make bubbles", WIDTH/2, HEIGHT - 40)
    emitter:update()
    emitter:draw()
end

function touched(touch)
    emitter.x = touch.x
    emitter.y = touch.y
    emitter:emit()
end

Bubbles = class()

function Bubbles:init(x, y)
    self.x = x
    self.y = y
    self.bubbles = {}
    self.maxbubbles = 100
    self.bubblecount = 0
    m = mesh()
    m.shader = shader(sh.v,sh.f)
    m:addRect(WIDTH/2, HEIGHT/2, WIDTH-50, HEIGHT-50)
    self.m = m
end

function Bubbles:emit()
    if self.bubblecount < self.maxbubbles then
        local dir = vec2(0,1):rotate(math.random() - 0.5) * math.random(1,6)
        local size = math.random(10, 50)
        local life = math.random(30, 60)
        local bubble = {pos = vec2(self.x, self.y), 
                        dir = dir, 
                        size = size, 
                        life = life}
        table.insert(self.bubbles, bubble)
        self.bubblecount = #self.bubbles
    end
end

function Bubbles:update()
    for k,v in pairs(self.bubbles) do
        v.pos = v.pos + v.dir
        v.life = v.life - 1
        if v.life == 0 then
            self.bubbles[k] = nil
            self.bubblecount = self.bubblecount - 1
        end
    end
end

-- This function draws all the bubbles in the system
function Bubbles:draw()
    ellipseMode(CENTER)
    stroke(255)
    strokeWidth(4)
    fill(153, 197, 210, 100)
    arr = {}
    for i = 0, 99 do
        v = self.bubbles[i]
        if v==nil then 
            table.insert(arr, vec2(0,0))
        else
            table.insert(arr, vec2(v.pos.x/WIDTH, v.pos.y/HEIGHT))
        end
    end
    self.m.shader.points = arr
    self.m.shader.len = #self.bubbles
    self.m:draw()
    for k,v in pairs(self.bubbles) do
        ellipse(v.pos.x, v.pos.y, v.size)
    end
end

sh = 
{   v=[[
    uniform mat4 modelViewProjection;
    attribute vec4 position;    
    void main()
    {   gl_Position = modelViewProjection * position;
    }
    ]], 

    f=[[   
    precision highp float;
    uniform vec2 points[100];
    uniform int len;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;        
    void main()
    {   float num = 0.;
        for (int i=0; i<len; i++)
            num += 0.02 / distance(vTexCoord, points[i])+0.00001;
        if (num > .8) 
            gl_FragColor = vec4(1,1,1,1);    
        else
            gl_FragColor = vec4(0,0,0,1);    
    }
    ]]
}

It didn’t do anything because the shader wasn’t running
Here is the correct code in your format
It is a bit more stable but still crashes

displayMode(FULLSCREEN)

function setup()
    emitter = Bubbles(0, 0)
end

function draw()
    background(40, 40, 50)
    fill(255)
    text("Drag your finger to make bubbles", WIDTH/2, HEIGHT - 40)
    emitter:update()
    emitter:draw()
end

function touched(touch)
    emitter.x = touch.x
    emitter.y = touch.y
    emitter:emit()
end

Bubbles = class()

function Bubbles:init(x, y)
    self.x = x
    self.y = y
    self.bubbles = {}
    self.maxbubbles = 100
    self.bubblecount = 0
    m = mesh()
    m.shader = shader(sh.v,sh.f)
    m:addRect(WIDTH/2, HEIGHT/2, WIDTH-50, HEIGHT-50)
    self.m = m
end

function Bubbles:emit()
    if self.bubblecount < self.maxbubbles then
        local dir = vec2(0,1):rotate(math.random() - 0.5) * math.random(1,6)
        local size = math.random(10, 50)
        local life = 600
        local bubble = {pos = vec2(self.x, self.y), 
                        dir = dir, 
                        size = size, 
                        life = life}
        table.insert(self.bubbles, bubble)
        self.bubblecount = #self.bubbles
    end
end

function Bubbles:update()
    for k,v in pairs(self.bubbles) do
        v.pos = v.pos + v.dir
        v.life = v.life - 1
        if v.life == 0 then
            self.bubbles[k] = nil
            self.bubblecount = self.bubblecount - 1
        end
    end
end

-- This function draws all the bubbles in the system
function Bubbles:draw()
    ellipseMode(CENTER)
    stroke(255)
    strokeWidth(4)
    fill(153, 197, 210, 100)
    arr = {}
    for i = 0, 99 do
        v = self.bubbles[i]
        if v==nil then 
            table.insert(arr, vec2(0,0))
        else
            table.insert(arr, vec2(v.pos.x/WIDTH, v.pos.y/HEIGHT))
        end
    end
    self.m.shader.points = arr
    self.m.shader.len = #self.bubbles
    self.m:draw()

end

sh = 
{   v=[[
    
uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec4 color;
attribute vec2 texCoord;
varying lowp vec4 vColor;
varying highp vec2 vTexCoord;
void main()
{
    vColor = color;
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * position;
}


    ]], 

    f=[[   
    precision highp float;
    uniform vec2 points[100];
    uniform int len;
    varying lowp vec4 vColor;
    varying highp vec2 vTexCoord;        
    void main()
    {   float num = 0.;
        for (int i=0; i<len; i++)
            num += 0.02 / distance(vTexCoord, points[i])+0.00001;
        if (num > .8) 
            gl_FragColor = vec4(1,1,1,1);    
        else
            gl_FragColor = vec4(0,0,0,1);    
    }
    ]]
}

@ellie_ff1493 When I get it to run, it has a bubble/blob that acts like what’s in a lava lamp. It looks really nice, but still crashes after awhile. I don’t know enough about shaders, so I can’t say why it crashes. When you work with shaders, be prepared to debug blind because you won’t get any information other than a crash if things don’t work right. You never said what this program is really supposed to do.

I fixed it, turns out 100 is to large of an array size, I changed it to 10 and it’s really stable now

I looked in to it some more and it’s not the large array it just makes the bug worse, the problem is using a uniform variable in a for loop because it try’s to unroll the loop but can’t because it’s an unknown when it compiles. This also makes a bug where different parts of the screen get rendered in different places like in the pic