Skip to content

Sleef_strtoq in 4.0 incorrectly sets endptr and ignores delimiters #706

@SwayamInSync

Description

@SwayamInSync

In SLEEF 4.0, Sleef_strtoq has a regression compared to version 3.8. The function no longer correctly sets endptr to indicate where parsing stopped, and it incorrectly parses past whitespace and other delimiters (like commas), which violates the expected behavior of strtod-like functions.

Expected Behavior

Sleef_strtoq should behave like the standard strtod function:

  • endptr should point to the first character that could not be parsed
  • Parsing should stop at whitespace, commas, letters, or any non-numeric character that isn't part of a valid floating-point representation

Actual Behavior in SLEEF 4.0

  1. endptr is always set to the end of the string (empty string ""), regardless of where parsing actually stopped
  2. The function ignores whitespace and comma delimiters, continuing to parse characters that should stop parsing
  3. This makes it impossible to detect parse failures or determine where valid input ends

Reproduction

Details
#include <iostream>
#include <iomanip>
#include <sleefquad.h>
#include <cmath>
#include <cstdlib>

int main()
{
    // Test strtoq with invalid strings
    char *endptr = NULL;
    char *endptr_d = NULL;
    
    // Test 1: "abc"
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q1 = Sleef_strtoq("abc", &endptr);
    double d1 = strtod("abc", &endptr_d);
    std::cout << "Input: 'abc'" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q1);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d1 << std::endl;
    std::cout << std::endl;
    
    // Test 2: "1.23abc"
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q2 = Sleef_strtoq("1.23abc", &endptr);
    double d2 = strtod("1.23abc", &endptr_d);
    std::cout << "Input: '1.23abc'" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q2);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d2 << std::endl;
    std::cout << std::endl;
    
    // Test 3: "1.23"
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q3 = Sleef_strtoq("1.23", &endptr);
    double d3 = strtod("1.23", &endptr_d);
    std::cout << "Input: '1.23'" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q3);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d3 << std::endl;
    std::cout << std::endl;
    
    // Test 4: "1.23 456" - whitespace delimiter test
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q4 = Sleef_strtoq("1.23 456", &endptr);
    double d4 = strtod("1.23 456", &endptr_d);
    std::cout << "Input: '1.23 456'" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q4);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d4 << std::endl;
    std::cout << std::endl;
    
    // Test 5: "1.23,456" - comma delimiter test
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q5 = Sleef_strtoq("1.23,456", &endptr);
    double d5 = strtod("1.23,456", &endptr_d);
    std::cout << "Input: '1.23,456'" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q5);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d5 << std::endl;
    std::cout << std::endl;
    
    // Test 6: "  1.23  " - leading/trailing whitespace
    endptr = NULL;
    endptr_d = NULL;
    Sleef_quad q6 = Sleef_strtoq("  1.23  ", &endptr);
    double d6 = strtod("  1.23  ", &endptr_d);
    std::cout << "Input: '  1.23  '" << std::endl;
    std::cout << "  [strtoq] endptr: '" << (endptr ? endptr : "NULL") << "'" << std::endl;
    Sleef_printf("  [strtoq] value: %.6Qe\n", q6);
    std::cout << "  [strtod] endptr: '" << (endptr_d ? endptr_d : "NULL") << "'" << std::endl;
    std::cout << "  [strtod] value: " << std::scientific << std::setprecision(6) << d6 << std::endl;
    
    return 0;
}

Results

SLEEF 3.8 (Correct behavior, matches strtod):

Input: 'abc'
  [strtoq] endptr: 'abc'
  [strtoq] value: 0.000000e+00
  [strtod] endptr: 'abc'
  [strtod] value: 0.000000e+00

Input: '1.23abc'
  [strtoq] endptr: 'abc'
  [strtoq] value: 1.230000e+00
  [strtod] endptr: 'abc'
  [strtod] value: 1.230000e+00

Input: '1.23'
  [strtoq] endptr: ''
  [strtoq] value: 1.230000e+00
  [strtod] endptr: ''
  [strtod] value: 1.230000e+00

Input: '1.23 456'
  [strtoq] endptr: ' 456'
  [strtoq] value: 1.230000e+00
  [strtod] endptr: ' 456'
  [strtod] value: 1.230000e+00

Input: '1.23,456'
  [strtoq] endptr: ',456'
  [strtoq] value: 1.230000e+00
  [strtod] endptr: ',456'
  [strtod] value: 1.230000e+00

Input: '  1.23  '
  [strtoq] endptr: '  '
  [strtoq] value: 1.230000e+00
  [strtod] endptr: '  '
  [strtod] value: 1.230000e+00

SLEEF 4.0 (Broken behavior):

Input: 'abc'
  [strtoq] endptr: ''
  [strtoq] value: 0.000000e+00
  [strtod] endptr: 'abc'
  [strtod] value: 0.000000e+00

Input: '1.23abc'
  [strtoq] endptr: ''
  [strtoq] value: 1.230000e+00
  [strtod] endptr: 'abc'
  [strtod] value: 1.230000e+00

Input: '1.23'
  [strtoq] endptr: ''
  [strtoq] value: 1.230000e+00
  [strtod] endptr: ''
  [strtod] value: 1.230000e+00

Input: '1.23 456'
  [strtoq] endptr: ''
  [strtoq] value: 1.234560e+00
  [strtod] endptr: ' 456'
  [strtod] value: 1.230000e+00

Input: '1.23,456'
  [strtoq] endptr: ''
  [strtoq] value: 1.234560e+00
  [strtod] endptr: ',456'
  [strtod] value: 1.230000e+00

Input: '  1.23  '
  [strtoq] endptr: ''
  [strtoq] value: 1.230000e+00
  [strtod] endptr: '  '
  [strtod] value: 1.230000e+00

Environment

  • SLEEF version: 4.0 and 3.8
  • Platform: macOS (arm64)
  • Compiler: Apple clang

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions