Skip to content

Enhancement: Detect Complex Struct Getters with Omitted Members #2779

@dguido

Description

@dguido

Summary

Add a detector that identifies public state variables containing complex structs where automatic getters omit certain members, potentially causing confusion and incorrect assumptions about data accessibility.

Motivation

Solidity automatically generates getter functions for public state variables. However, these getters have limitations when dealing with complex data structures:

  1. Arrays and mappings within structs are omitted from the generated getter
  2. Nested structs with arrays/mappings are partially omitted
  3. Developers may assume all struct members are accessible via the getter

This behavior is not immediately obvious and can lead to:

  • Incorrect assumptions about data availability
  • Inefficient workarounds when data appears inaccessible
  • Security issues if access control depends on getter visibility
  • Integration problems with external contracts or front-ends

Problem Description

When a struct contains arrays or mappings, Solidity's automatic getter will skip these members:

struct UserData {
    string name;           // ✓ Included in getter
    uint256 balance;       // ✓ Included in getter
    uint256[] tokenIds;    // ✗ Omitted from getter
    mapping(address => uint256) allowances; // ✗ Omitted from getter
}

contract Example {
    UserData public userData; // Getter won't return tokenIds or allowances
}

Example Vulnerable Patterns

contract ProblematicPatterns {
    // Pattern 1: Direct struct with arrays/mappings
    struct Config {
        address owner;
        uint256[] limits;        // Won't be in getter
        mapping(address => bool) whitelist; // Won't be in getter
    }
    Config public config; // Getter omits limits and whitelist
    
    // Pattern 2: Nested structs
    struct Inner {
        uint256[] values;        // Won't be accessible
    }
    struct Outer {
        Inner data;              // Partially accessible
        string name;
    }
    Outer public settings;       // Getter omits Inner.values
    
    // Pattern 3: Array of structs with complex members
    struct Token {
        string symbol;
        address[] holders;       // Omitted when accessing array elements
    }
    Token[] public tokens;       // Individual token getters omit holders
}

Recommended Solutions

The detector should suggest alternatives:

contract ImprovedPatterns {
    struct Config {
        address owner;
        uint256[] limits;
        mapping(address => bool) whitelist;
    }
    
    // Solution 1: Make variable private/internal and create custom getter
    Config private config;
    
    function getConfig() external view returns (
        address owner,
        uint256[] memory limits
    ) {
        return (config.owner, config.limits);
    }
    
    // Solution 2: Separate simple and complex data
    struct SimpleConfig {
        address owner;
        uint256 limitCount;
    }
    SimpleConfig public simpleConfig;
    uint256[] public limits;
}

Expected Output

Complex struct getter detected in ContractName
  State variable: config (line 45)
  Type: Config
  Omitted members:
    - limits: uint256[] (line 12)
    - whitelist: mapping(address => bool) (line 13)
  
  Impact: Automatic getter does not return these members
  Recommendation: Create a custom getter function or separate complex members

Benefits

  1. Prevent integration issues - External contracts/UIs won't be surprised by missing data
  2. Improve code clarity - Developers understand data accessibility
  3. Reduce gas costs - Avoid unnecessary workarounds for accessing "hidden" data
  4. Educational value - Teaches Solidity's getter limitations
  5. Better API design - Encourages thoughtful public interface design

Priority

Medium-High - While not directly a security vulnerability, this issue frequently causes integration problems, increases development time, and can indirectly lead to security issues when developers implement workarounds. It's particularly important for contracts intended to be integrated with other systems.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions