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
endptr is always set to the end of the string (empty string ""), regardless of where parsing actually stopped
- The function ignores whitespace and comma delimiters, continuing to parse characters that should stop parsing
- 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
In SLEEF 4.0,
Sleef_strtoqhas a regression compared to version 3.8. The function no longer correctly setsendptrto indicate where parsing stopped, and it incorrectly parses past whitespace and other delimiters (like commas), which violates the expected behavior ofstrtod-like functions.Expected Behavior
Sleef_strtoqshould behave like the standardstrtodfunction:endptrshould point to the first character that could not be parsedActual Behavior in SLEEF 4.0
endptris always set to the end of the string (empty string""), regardless of where parsing actually stoppedReproduction
Details
Results
SLEEF 3.8 (Correct behavior, matches
strtod):SLEEF 4.0 (Broken behavior):
Environment