integer overflow at runtime — Como Resolver em Zig
O Que Este Erro Significa
O erro integer overflow em tempo de execução é um panic que ocorre quando uma operação aritmética produz um resultado que não cabe no tipo inteiro utilizado. Em builds Debug e ReleaseSafe, Zig verifica automaticamente todas as operações aritméticas para overflow e gera um panic quando detectado. Isso previne uma classe inteira de bugs silenciosos que existem em C/C++.
A mensagem de panic é:
thread 1 panic: integer overflow
Diferença do Overflow em Comptime
O overflow em comptime é sempre um erro de compilação. O overflow em runtime só é detectado em builds com verificações de segurança habilitadas (Debug e ReleaseSafe). Em ReleaseFast e ReleaseSmall, a verificação é removida para performance.
Causas Comuns
1. Soma que Excede o Limite
pub fn main() void {
var a: u8 = 250;
a += 10; // PANIC: 250 + 10 = 260, que não cabe em u8 (max 255)
}
2. Multiplicação com Resultado Grande
pub fn main() void {
var x: u16 = 1000;
x *= 100; // PANIC: 1000 * 100 = 100000, não cabe em u16 (max 65535)
}
3. Subtração com Resultado Negativo em Unsigned
pub fn main() void {
var saldo: u32 = 100;
const debito: u32 = 150;
saldo -= debito; // PANIC: 100 - 150 = -50, não representável em u32
}
4. Conversão com @intCast que Não Cabe
pub fn main() void {
const grande: u32 = 300;
const pequeno: u8 = @intCast(grande); // PANIC: 300 não cabe em u8
_ = pequeno;
}
5. Loop com Contador que Estoura
pub fn main() void {
var contador: u8 = 0;
while (true) {
contador += 1; // PANIC quando contador chega a 255 e tenta incrementar
if (contador == 0) break; // Nunca alcançado em Debug
}
}
6. Negação de Inteiro Mínimo em Signed
pub fn main() void {
var x: i8 = -128;
x = -x; // PANIC: -(-128) = 128, que não cabe em i8 (max 127)
}
Como Corrigir
Solução 1: Usar Tipo Maior
pub fn main() void {
var x: u32 = 1000; // u32 ao invés de u16
x *= 100; // OK: 100000 cabe em u32
_ = x;
}
Solução 2: Operações com Saturação (+|, -|, *|)
Operações saturantes limitam o resultado ao valor máximo ou mínimo do tipo:
pub fn main() void {
var a: u8 = 250;
a +|= 10; // Resultado: 255 (saturado no máximo)
// a é 255, não causa panic
var b: u8 = 5;
b -|= 10; // Resultado: 0 (saturado no mínimo)
_ = a;
_ = b;
}
Solução 3: Operações com Wrapping (+%, -%, *%)
Se o comportamento de wrap-around é o desejado:
pub fn main() void {
var contador: u8 = 250;
contador +%= 10; // Resultado: 4 (wrap around: 260 % 256 = 4)
_ = contador;
}
Solução 4: Verificar Antes de Operar
const std = @import("std");
pub fn main() void {
var saldo: u32 = 100;
const debito: u32 = 150;
if (debito > saldo) {
std.debug.print("Saldo insuficiente!\n", .{});
} else {
saldo -= debito; // Seguro: verificado antes
}
_ = saldo;
}
Solução 5: Usar @addWithOverflow
const std = @import("std");
pub fn main() void {
const a: u8 = 250;
const b: u8 = 10;
const resultado = @addWithOverflow(a, b);
if (resultado[1] != 0) {
std.debug.print("Overflow detectado!\n", .{});
} else {
std.debug.print("Resultado: {}\n", .{resultado[0]});
}
}
Solução 6: Usar math.add Para Verificação Segura
const std = @import("std");
pub fn main() void {
const a: u8 = 250;
const b: u8 = 10;
const resultado = std.math.add(u8, a, b) catch {
std.debug.print("Overflow!\n", .{});
return;
};
std.debug.print("Resultado: {}\n", .{resultado});
}
Operadores Aritméticos do Zig — Referência Rápida
| Operação | Normal | Wrapping | Saturating |
|---|---|---|---|
| Soma | + | +% | +| |
| Subtração | - | -% | -| |
| Multiplicação | * | *% | *| |
| Shift left | << | <<% | <<| |
Comportamento por Build Mode
| Build Mode | Overflow detectado? | Ação |
|---|---|---|
| Debug | Sim | Panic + trace |
| ReleaseSafe | Sim | Panic + trace |
| ReleaseFast | Não | Wrap silencioso |
| ReleaseSmall | Não | Wrap silencioso |
Dicas Práticas
- Sempre teste em Debug — Overflow silencioso em Release pode esconder bugs
- Prefira tipos maiores — Se não há restrição de memória, use
u32ouu64 - Use saturação para contadores — Contadores que não devem ultrapassar um limite
- Use wrapping para checksums — Operações onde wrap-around é o comportamento desejado
Erros Relacionados
- integer overflow at comptime — Overflow em tempo de compilação
- integer truncation — Truncamento ao converter tipos
- division by zero — Divisão por zero