emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.35k stars 3.25k forks source link

`charconv` function `to_chars` silently casts `long double` to `double` #22121

Closed WarrenWeckesser closed 1 week ago

WarrenWeckesser commented 1 week ago

This is main.cpp:

#include <cstdio>
#include <charconv>
#include <system_error>
#include <limits>

template<typename T>
static inline void
print_value(const T x)
{
    char buf[100];
    const std::to_chars_result res = std::to_chars(buf, buf + sizeof(buf), x);
    if (res.ec == std::errc{}) {
        printf("%.*s", static_cast<int>(res.ptr - buf), buf);
    }
    else {
        printf("<to_chars() failed!>");
    }
}

int main()
{
    printf("std::numeric_limits<long double>::digits = %d\n",
           std::numeric_limits<long double>::digits);

    long double x = 0.333333333333333333333333333333333333L;
    printf("x = ");
    print_value(x);
    printf("\n");

    printf("x = %-40.33Lf\n", x);
}

Here are the commands I use to build and run it:

% em++ main.cpp -sPRINTF_LONG_DOUBLE
% node a.out.js
std::numeric_limits<long double>::digits = 113
x = 0.3333333333333333
x = 0.333333333333333333333333333333333

I expect the first output of x to be the same as the second (other than possibly the last digit or two).

It looks like the culprit is the use of static_cast<double>(__value) here: https://github.com/emscripten-core/emscripten/blob/77448a918c9004e43470c251d0d8d33ce7b5fce3/system/lib/libcxx/src/charconv.cpp#L44-L47

Personally I would rather have an error than a silent cast to double.

I labeled this issue a bug report, but you might not consider it a bug. In that case, this is an enhancement request!

Version of emscripten/emsdk:

% emcc -v
emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.61 (67fa4c16496b157a7fc3377afd69ee0445e8a6e3)
clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /Users/warren/repos/git/forks/emsdk/upstream/bin

Full link command and output with -v appended:

Here's the build command again, with -v included:

% em++ -v main.cpp -sPRINTF_LONG_DOUBLE
 "/Users/warren/repos/git/forks/emsdk/upstream/bin/clang++" -target wasm32-unknown-emscripten -fignore-exceptions -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr --sysroot=/Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot -DEMSCRIPTEN -Xclang -iwithsysroot/include/fakesdl -Xclang -iwithsysroot/include/compat -v main.cpp -c -o /var/folders/6f/wyccw81j5kj1c7v6p47zr9fr0000gn/T/emscripten_temp__vzc3gnf/main_0.o
clang version 19.0.0git (https:/github.com/llvm/llvm-project 7cfffe74eeb68fbb3fb9706ac7071f8caeeb6520)
Target: wasm32-unknown-emscripten
Thread model: posix
InstalledDir: /Users/warren/repos/git/forks/emsdk/upstream/bin
 (in-process)
 "/Users/warren/repos/git/forks/emsdk/upstream/bin/clang-19" -cc1 -triple wasm32-unknown-emscripten -emit-obj -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.cpp -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -fdebug-compilation-dir=/Users/warren/code-snippets/c++/test-emscripten-stuff -v -fcoverage-compilation-dir=/Users/warren/code-snippets/c++/test-emscripten-stuff -resource-dir /Users/warren/repos/git/forks/emsdk/upstream/lib/clang/19 -D EMSCRIPTEN -isysroot /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot -internal-isystem /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten/c++/v1 -internal-isystem /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/c++/v1 -internal-isystem /Users/warren/repos/git/forks/emsdk/upstream/lib/clang/19/include -internal-isystem /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten -internal-isystem /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include -fdeprecated-macro -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcxx-exceptions -fignore-exceptions -fexceptions -fcolor-diagnostics -iwithsysroot/include/fakesdl -iwithsysroot/include/compat -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr -o /var/folders/6f/wyccw81j5kj1c7v6p47zr9fr0000gn/T/emscripten_temp__vzc3gnf/main_0.o -x c++ main.cpp
clang -cc1 version 19.0.0git based upon LLVM 19.0.0git default target x86_64-apple-darwin22.6.0
ignoring nonexistent directory "/Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten/c++/v1"
ignoring nonexistent directory "/Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/wasm32-emscripten"
#include "..." search starts here:
#include <...> search starts here:
 /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/fakesdl
 /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/compat
 /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include/c++/v1
 /Users/warren/repos/git/forks/emsdk/upstream/lib/clang/19/include
 /Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/include
End of search list.
 /Users/warren/repos/git/forks/emsdk/upstream/bin/clang --version
 /Users/warren/repos/git/forks/emsdk/upstream/bin/wasm-ld -o a.out.wasm -L/Users/warren/repos/git/forks/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten /var/folders/6f/wyccw81j5kj1c7v6p47zr9fr0000gn/T/emscripten_temp__vzc3gnf/main_0.o -lGL-getprocaddr -lal -lhtml5 -lprintf_long_double-debug -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /var/folders/6f/wyccw81j5kj1c7v6p47zr9fr0000gn/T/tmpa9mob5fklibemscripten_js_symbols.so --strip-debug --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=_emscripten_stack_alloc --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export=_emscripten_stack_restore --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --no-growable-memory --initial-heap=16777216 --no-entry --stack-first --table-base=1
 /Users/warren/repos/git/forks/emsdk/upstream/bin/llvm-objcopy a.out.wasm a.out.wasm --remove-section=.debug* --remove-section=producers
 /Users/warren/repos/git/forks/emsdk/upstream/bin/wasm-emscripten-finalize --dyncalls-i64 --pass-arg=legalize-js-interface-exported-helpers a.out.wasm -o a.out.wasm --detect-features
 /Users/warren/repos/git/forks/emsdk/node/18.20.3_64bit/bin/node /Users/warren/repos/git/forks/emsdk/upstream/emscripten/src/compiler.mjs /var/folders/6f/wyccw81j5kj1c7v6p47zr9fr0000gn/T/tmpdn_74rpb.json
sbc100 commented 1 week ago

the code in question here is part of libc++ which itself is part of LLVM. If you really think this is a bug perhaps its best to file that bug upstream?

WarrenWeckesser commented 1 week ago

Ah, right. In fact, there is already this: https://github.com/llvm/llvm-project/issues/56261

Sorry for the noise!