PixarAnimationStudios / OpenUSD

Universal Scene Description
http://www.openusd.org
Other
5.99k stars 1.18k forks source link

USDA Writes Sensitive to User's Locale #3214

Open erslavin opened 1 month ago

erslavin commented 1 month ago

Description of Issue

The USDA writer appears to be sensitive to the current locale setting when writing integer content. Indeed digging down it looks to be using TfStringify, with no specialization for integers, which results in the underlying ostream being initialized with whatever the current global locale is set to. I isolated this by adding the following sequence into the test for TfStringUtils:

// verify that TfStringify is agnostic to locale for
// numerical values
std::locale originalLocale;
std::locale::global(std::locale(""));
TF_AXIOM(TfStringify(1000.56) == "1000.56");
TF_AXIOM(TfStringify(1000) == "1000");
std::locale::global(originalLocale);
TF_AXIOM(TfStringify(1000) == "1000");
TF_AXIOM(TfStringify(1000.56) == "1000.56");

Indeed, this fails on the line you would expect:

`TF_AXIOM(TfStringify(1000) == "1000");

Either this behavior should be guarded against in TfStringify by potentially specializing for integer values, or if not globally desirable for TfStringify the USDA writer needs to be aware that this is a possibility and initialize the writes with the standard C++ locale prior to using the streams (and restore it after write is complete).

Steps to Reproduce

  1. Add the above block to the TfStringUtils tests
  2. Run the TfStringUtils test to note the failure

A similar issue was noted here (likely with the same underlying cause), but closed: https://github.com/PixarAnimationStudios/OpenUSD/issues/1350

System Information (OS, Hardware)

Windows

Package Versions

Current dev branch

Build Flags

jesschimein commented 1 month ago

Filed as internal issue #USD-9954

meshula commented 1 month ago

From a discussion, a plausible solution is to specialize using std::to_chars since it is optimized for performance, and does not use locale.

eg

std::string result(32, '\0'); // big enough
auto [ptr, ec] = std::to_chars(&result[0], &result[0] + result.size(), value);