Skip to content

Uppercase E exponent literal evades underscore validation check #16740

@researchzero-sec

Description

@researchzero-sec

Description

Solidity rejects an underscore placed directly against the exponent marker of a decimal number literal, but only when the exponent marker is lowercase e. The post-lex validator in libsolidity/analysis/SyntaxChecker.cpp:342-346 searches the literal text for the fixed lowercase substrings "e_" and "_e":

// libsolidity/analysis/SyntaxChecker.cpp:342-346  (inside visit(Literal), decimal branch)
if (value.find("_e") != ASTString::npos)
    m_errorReporter.syntaxError(6415_error, _literal.location(),
        "Invalid use of underscores in number literal. No underscore at the end of the mantissa allowed.");
if (value.find("e_") != ASTString::npos)
    m_errorReporter.syntaxError(6165_error, _literal.location(),
        "Invalid use of underscores in number literal. No underscore in front of exponent allowed.");

The scanner equally accepts uppercase E as an exponent marker (liblangutil/Scanner.cpp:996, m_char == 'e' || m_char == 'E'), and the AST keeps the literal's original case, so "1E_5" contains "E_" and never matches "e_"find returns npos and no error is emitted. As a result, every uppercase-E malformed literal slips through: 1E_5 and 1_E5 are silently accepted as 100000 (underscore dropped), while the byte-identical lowercase 1e_5/1_e5 are hard compile errors 6165/6415.

Expected: the underscore-placement check should be case-insensitive so that 1E_5/1_E5 are rejected with the same errors (6165/6415) as their lowercase equivalents, instead of silently accepting a malformed literal with no diagnostic.

Environment

  • Compiler version: 47b9dedda

Steps to Reproduce

The following compiles without any diagnostic; the underscores are silently dropped:

uint constant A = 1E_5;   // accepted, == 100000  (lowercase 1e_5 => Error 6165)
uint constant B = 1_E5;   // accepted, == 100000  (lowercase 1_e5 => Error 6415)
uint constant C = 3E_0;   // accepted, == 3

For comparison, the byte-identical lowercase forms 1e_5 and 1_e5 are hard errors (6165 and 6415 respectively), demonstrating the case-sensitivity asymmetry.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions