Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix locale dependent number parsing #1229

Merged
merged 8 commits into from
Feb 22, 2025

Conversation

bcoconni
Copy link
Member

@bcoconni bcoconni commented Feb 9, 2025

Following the issue #1227, this PR is making the function atof_locale_c much more pedantic and rejects any number that do not match a strict syntax such as [+-]0.12E[+-]34 or 12.34. A regular expression is used for that purpose (they have been introduced in C++11).

1. New exception InvalidNumer

A new exception class JSBSim::InvalidNumber has been created which inherits from JSBSim::BaseException. Since the former is defined in input_output/string_utilities.h and the latter in FGJSBBase.h, it was no longer possible that FGJSBBase.h includes string_utilities.h because that was creating a mutual dependence that compilers complain about. Actually FGJSBBase.h does not need to include string_utilities.h so the corresponding #include has simply been removed from FGJSBBase.h. As a consequence, a number of source files have been modified to explicitly include string_utilities.h.

2. atof_locale_c pedantry

The function is_number will now be much more pedantic and will basically be a function that checks that atof_locale_c succeeds.

All the occurrences of the following code:

double a_value;
std::string a_string;

if (is_number(a_string)) {
  a_value = atof_locale_c(trim(a_string));
} else {
  // Error management
}

have been replaced by

double a_value;
std::string a_string;

try {
  a_value = atof_locale_c(trim(a_string));
} catch (InvalidNumber& e) {
  // Error management
}

The problem was that both is_number and strtod_l have a relaxed interpretation of what a valid number syntax is. For example strtod_l("1.3.2", nullptr, numeric_c.Locale); returns 1.3 and the strings x and . return 0.0. In addition the strings 1.3.2 and . are considered valid numbers by is_number although it rejects x. The regular expression will allow rejecting these strings as invalid.

Once this PR will be merged, all the validation and conversion work will be made by atof_locale_c which is now extremely pedantic. Also since the PR #799, atof_locale_c uses the locale "C" for numerical value whatever is the setting of LC_NUMERIC.

3. Removal of calls to atof

Most of the calls to atof have been replaced by atof_locale_c. The remaining calls to atof are all located in simger/props/props.cxx:

return atof(get_string());

result = set_float(atof(value));

result = set_float(atof(value));

These calls are respectively made in the methods SGPropertyNode::getFloatValue, SGPropertyNode::setStringValue and SGPropertyNode::setUnspecifiedValue which are not used in the code.

4. Remaining calls to strto functions

Some calls to the standard library functions starting with strto (such as strtol, strtod, ...) remain.

return strtol(get_string(), 0, 0);

result = set_long(strtol(value, 0, 0));

result = set_double(strtod(value, 0));

result = set_long(strtol(value, 0, 0));

result = set_double(strtod(value, 0));

These calls are respectively made in the methods SGPropertyNode::getLongValue, SGPropertyNode::setStringValue and SGPropertyNode::setUnspecifiedValue which are not used in the code.

The following call to strtod is made in SGPropertyNode::getLongValue:

case props::STRING:
case props::UNSPECIFIED:
return strtod(get_string(), 0);

However for that case to be selected, the property should have been previously set by SGPropertyNode::setStringValue or SGPropertyNode::setUnspecifiedValue which we are not using.

The following call to strtoul is made in simgear/xml/xmlparse.c

unsigned long debugLevel = strtoul(value, &afterValue, 10);

The function getDebugLevel is internally used by xmlparse.c to get the value of the environment variables EXPAT_ENTROPY_DEBUG, EXPAT_ACCOUNTING_DEBUG and EXPAT_ENTITY_DEBUG. These are used internally by Expat for debug purposes. It is unlikely that they are related to the issue #1227.

Conclusion

  • This PR is making the conversion from string to double much more pedantic.
  • Most of the calls to atof have been removed and replaced by atof_locale_c. For the record, the behavior of atof depends on the environment variable LC_NUMERIC.
  • Some calls to the atof and strto functions remain but they are located in functions which we do not use.
    • Most of these calls are located in simgear/props/props.cxx and I am reluctant to use atof_locale_c in this piece of code. If we want to be super safe, I'd rather remove the aforementioned functions from SGPropertyNode since we are not using them anyway.

Copy link

codecov bot commented Feb 9, 2025

Codecov Report

Attention: Patch coverage is 24.52830% with 40 lines in your changes missing coverage. Please review.

Project coverage is 24.76%. Comparing base (d1bedfb) to head (8ac494d).
Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
src/math/FGFunction.cpp 0.00% 12 Missing ⚠️
src/input_output/FGInputSocket.cpp 0.00% 6 Missing ⚠️
src/input_output/FGUDPInputSocket.cpp 0.00% 6 Missing ⚠️
src/input_output/FGXMLElement.cpp 0.00% 4 Missing ⚠️
src/models/flight_control/FGSwitch.cpp 0.00% 4 Missing ⚠️
src/models/propulsion/FGTurbine.cpp 0.00% 4 Missing ⚠️
src/models/propulsion/FGRotor.cpp 0.00% 3 Missing ⚠️
src/input_output/string_utilities.cpp 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1229      +/-   ##
==========================================
+ Coverage   24.75%   24.76%   +0.01%     
==========================================
  Files         170      170              
  Lines       19457    19464       +7     
==========================================
+ Hits         4816     4820       +4     
- Misses      14641    14644       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@bcoconni bcoconni added the bug label Feb 21, 2025
@bcoconni bcoconni merged commit e6208a3 into JSBSim-Team:master Feb 22, 2025
30 checks passed
@bcoconni bcoconni deleted the bcoconni/issue1227 branch February 22, 2025 12:18
bcoconni added a commit to bcoconni/jsbsim that referenced this pull request Feb 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant