Skip to content

Commit

Permalink
Use stringstream with locale override.
Browse files Browse the repository at this point in the history
Add test for compiling float literals in locales with comma decimal separators.

Handle inexplicable test setlocale failure on Android,Linux. (Require success on other platforms)

Skip setting the locale on Android, which is always C locale in C++, but for some
reason std::locale::classic isn't implemented as a no-op.

Bug: angleproject:2607
Test: angle_unittests
Change-Id: I7c97cb56c01335db46f532fb8af3f9a4f2a30564
  • Loading branch information
kdashg committed Jun 2, 2018
1 parent 2426b09 commit 595ccab
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
15 changes: 11 additions & 4 deletions src/compiler/preprocessor/numeric_lex.h
Expand Up @@ -48,10 +48,17 @@ bool numeric_lex_int(const std::string &str, IntType *value)
template <typename FloatType>
bool numeric_lex_float(const std::string &str, FloatType *value)
{
// Some platforms have issues with the usage of std::locale and std::stringstream and cause
// crashes. Usage of strtod appears to be safe.
*value = static_cast<FloatType>(strtod(str.c_str(), nullptr));
return errno != ERANGE && std::isfinite(*value);
std::istringstream stream(str);

// Android NDK forbids access to locales by always throwing instead of only accepting the C locale.
#if !defined(ANGLE_PLATFORM_ANDROID)
// Force "C" locale so that decimal character is always '.', and not dependent on the current
// locale.
stream.imbue(std::locale::classic());
#endif

stream >> (*value);
return !stream.fail() && std::isfinite(*value);
}

} // namespace pp.
Expand Down
47 changes: 45 additions & 2 deletions src/tests/compiler_tests/ShCompile_test.cpp
Expand Up @@ -7,9 +7,11 @@
// Test the sh::Compile interface with different parameters.
//

#include <clocale>
#include "GLSLANG/ShaderLang.h"
#include "angle_gl.h"
#include "common/platform.h"
#include "gtest/gtest.h"
#include "GLSLANG/ShaderLang.h"

class ShCompileTest : public testing::Test
{
Expand All @@ -36,13 +38,16 @@ class ShCompileTest : public testing::Test

void testCompile(const char **shaderStrings, int stringCount, bool expectation)
{
bool success = sh::Compile(mCompiler, shaderStrings, stringCount, 0);
ShCompileOptions options = SH_OBJECT_CODE;
bool success = sh::Compile(mCompiler, shaderStrings, stringCount, options);
const std::string &compileLog = sh::GetInfoLog(mCompiler);
EXPECT_EQ(expectation, success) << compileLog;
}

private:
ShBuiltInResources mResources;

public:
ShHandle mCompiler;
};

Expand Down Expand Up @@ -81,3 +86,41 @@ TEST_F(ShCompileTest, TokensSplitInShaderStrings)

testCompile(shaderStrings, 3, true);
}

// Parsing floats in shaders can run afoul of locale settings.
// In de_DE, `strtof("1.9")` will yield `1.0f`. (It's expecting "1,9")
TEST_F(ShCompileTest, DecimalSepLocale)
{
const auto defaultLocale = setlocale(LC_NUMERIC, nullptr);

const auto fnSetLocale = [](const char *const name) {
return bool(setlocale(LC_NUMERIC, name));
};

const bool setLocaleToDe =
fnSetLocale("de_DE") || fnSetLocale("de-DE"); // Windows doesn't like de_DE.

// These configs don't support de_DE: android_angle_vk[32,64]_rel_ng, linux_angle_rel_ng
// Just allow those platforms to quietly fail, but require other platforms to succeed.
#if defined(ANGLE_PLATFORM_ANDROID) || defined(ANGLE_PLATFORM_LINUX)
if (!setLocaleToDe)
{
return;
}
#endif
ASSERT_TRUE(setLocaleToDe);

const char kSource[] = R"(
void main()
{
gl_FragColor = vec4(1.9);
})";
const char *parts[] = {kSource};
testCompile(parts, 1, true);

const auto &translated = sh::GetObjectCode(mCompiler);
// printf("%s\n", translated.data());
EXPECT_NE(translated.find("1.9"), std::string::npos);

fnSetLocale(defaultLocale);
}

0 comments on commit 595ccab

Please sign in to comment.