Lua:getAddressSafe
function getAddressSafe(AddressString, local OPTIONAL, shallow OPTIONAL) : integer
Safely resolves a symbol name to a memory address without raising exceptions. Returns nil on failure instead of throwing an error.
Note: This is the recommended function for symbol resolution when the symbol might not exist.
Contents
Function Parameters[edit]
| Parameter | Type | Description | 
|---|---|---|
| AddressString | string or number (CEAddressString) | The symbol to resolve (module name, address expression, label, pointer expression). If a number is provided, it's returned unchanged | 
| local | boolean | Optional. If true, uses Cheat Engine's self symbol handler instead of the target process. Default: false | 
| shallow | boolean | Optional. If true, performs a shallow (faster) symbol lookup without deep parsing. Default: false | 
Returns[edit]
An integer representing the resolved address on success, or nil if resolution fails.
Description[edit]
This function works identically to getAddress but returns nil on failure instead of raising an exception. It resolves:
- Module names (e.g., "game.exe", "kernel32.dll")
- Module + offset expressions (e.g., "game.exe+1234")
- Symbol names from debug symbols or exports
- Registered symbols from registerSymbol()
- Auto-assembler labels
- Pointer expressions
Return Behavior[edit]
- Success: Returns the resolved address as an integer
- Failure: Returns nil (nothing pushed to Lua stack)
- Numeric input: Returns the number unchanged
- Exceptions: Catches all exceptions and returns nil
Usage Examples[edit]
Basic safe resolution:
local address = getAddressSafe("game.exe+12345")
if address then
  print(string.format("Address: %X", address))
else
  print("Failed to resolve symbol")
end
Check if module exists:
local baseAddr = getAddressSafe("optionalModule.dll")
if baseAddr then
  print("Module loaded at: " .. baseAddr)
else
  print("Optional module not loaded")
end
Conditional feature detection:
local featureAddr = getAddressSafe("game.exe+NewFeatureOffset")
if featureAddr then
  -- New version with feature
  print("New version detected")
  enableNewFeature(featureAddr)
else
  -- Old version without feature
  print("Old version, feature not available")
  useOldMethod()
end
Safe symbol registration:
function tryRegisterSymbol(name, expr)
  local addr = getAddressSafe(expr)
  if addr then
    registerSymbol(name, addr)
    print(string.format("Registered %s = %X", name, addr))
    return true
  else
    print("Warning: Failed to register " .. name)
    return false
  end
end
tryRegisterSymbol("PlayerHealth", "game.exe+ABCD")
Version-dependent code:
local v1Addr = getAddressSafe("game.exe+1000")
local v2Addr = getAddressSafe("game.exe+2000")
if v2Addr and readBytes(v2Addr) == 0x48 then
  print("Using version 2 offsets")
  healthAddr = v2Addr
elseif v1Addr then
  print("Using version 1 offsets")
  healthAddr = v1Addr
else
  print("Unknown version!")
  return false
end
Numeric pass-through:
local addr = getAddressSafe(0x12345678) -- Returns 0x12345678 unchanged print(addr) -- 305419896
With shallow lookup (faster):
-- Shallow lookup is faster but may miss complex expressions
local addr = getAddressSafe("game.exe", false, true)
if addr then
  print("Quick module lookup: " .. addr)
end
Shallow vs Deep Lookup[edit]
The shallow parameter controls the symbol resolution depth:
Deep lookup (shallow = false, default):
- Performs full expression parsing
- Handles complex pointer arithmetic
- Resolves nested brackets and offsets
- Slower but more comprehensive
Shallow lookup (shallow = true):
- Quick module/symbol name lookup
- Skips complex expression evaluation
- Faster for simple module names
- May fail on complex expressions
Example:
-- Deep lookup (handles complex expressions)
local addr1 = getAddressSafe("[[game.exe+100]+8]+4", false, false)
-- Shallow lookup (fast, simple names only)
local addr2 = getAddressSafe("game.exe", false, true)
Comparison: getAddress vs getAddressSafe[edit]
| Feature | getAddress | getAddressSafe | 
|---|---|---|
| On failure | Raises exception | Returns nil | 
| Error handling | Requires pcall or try/catch | Simple if/then check | 
| Use case | Symbol must exist | Symbol might not exist | 
| Performance | Same | Slightly faster (no exception overhead on failure) | 
| Code complexity | More complex (needs pcall) | Simpler (direct nil check) | 
Advanced Examples[edit]
Multi-version support:
local offsets = {
  v1 = "game.exe+10000",
  v2 = "game.exe+20000",
  v3 = "game.exe+30000"
}
local healthAddr = nil
for version, offset in pairs(offsets) do
  local addr = getAddressSafe(offset)
  if addr and readBytes(addr) == 0x89 then  -- Signature check
    healthAddr = addr
    print("Detected " .. version)
    break
  end
end
if not healthAddr then
  print("ERROR: No compatible version found!")
  return false
end
Graceful degradation:
function findPlayerHealth()
  -- Try primary location
  local addr = getAddressSafe("PlayerHealthPrimary")
  if addr then return addr end
  
  -- Try secondary location
  addr = getAddressSafe("game.exe+ABCD")
  if addr then return addr end
  
  -- Try pattern scan as fallback
  addr = AOBScanUnique("89 44 24 ?? 8B 45", "+X")
  if addr then
    registerSymbol("PlayerHealthPrimary", addr)
    return addr
  end
  
  return nil  -- All methods failed
end
local health = findPlayerHealth()
if health then
  print("Health found at: " .. health)
else
  print("Could not locate health!")
end
Validate before use:
function safeWriteInteger(symbol, value)
  local addr = getAddressSafe(symbol)
  if not addr then
    print("Error: Cannot resolve " .. symbol)
    return false
  end
  
  writeInteger(addr, value)
  return true
end
if safeWriteInteger("PlayerGold", 9999) then
  print("Gold updated successfully")
end
Exception Safety[edit]
getAddressSafe catches ALL exceptions during symbol resolution:
-- These all return nil instead of crashing:
local addr1 = getAddressSafe("!@#$%^&*()")  -- Invalid syntax
local addr2 = getAddressSafe(nil)           -- Nil input
local addr3 = getAddressSafe("")            -- Empty string
local addr4 = getAddressSafe("[[[[[")       -- Malformed brackets
Performance Considerations[edit]
- Shallow lookups are faster for simple module names
- Deep lookups required for complex expressions
- Symbol resolution waits for symbol loading (can block)
- Cache resolved addresses in variables for repeated use:
-- Bad: Resolves every iteration
for i = 1, 1000 do
  local addr = getAddressSafe("game.exe+1234")
  writeInteger(addr, i)
end
-- Good: Resolve once, reuse
local addr = getAddressSafe("game.exe+1234")
if addr then
  for i = 1, 1000 do
    writeInteger(addr, i)
  end
end
Common Patterns[edit]
Assert pattern (fail fast):
local addr = getAddressSafe("game.exe+1234")
assert(addr, "Failed to resolve game.exe+1234")
-- Continue with addr
Default value pattern:
local addr = getAddressSafe("game.exe+1234") or 0x400000
-- Use default if resolution fails
Chain pattern (try multiple):
local addr = getAddressSafe("NewSymbol") or 
             getAddressSafe("OldSymbol") or
             getAddressSafe("game.exe+1234")

