Skip to content

-fshort-wchar is broken with -O2/-Os #26579

@choehwanjin

Description

@choehwanjin

Using -fshort-wchar with em++ produces incorrect results that vary depending on the optimization level.

Version of emscripten/emsdk:

emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 5.0.4 (62e22652509fbe7a00609ce48a653d0d66f27ba5)
clang version 23.0.0git (https:/github.com/llvm/llvm-project dcaab6dd99a33edbf98ad1ade0ea0d196b797910)
Target: wasm32-unknown-emscripten
Thread model: posix

Failing command line in full:
I've tested with the following code (
u16.cpp
wchar.cpp
wcslen.cpp
).

Command line:

em++ -fshort-wchar u16.cpp -O0 && env node ./a.out.js
em++ -fshort-wchar u16.cpp -O2 && env node ./a.out.js
em++ -fshort-wchar u16.cpp -Os && env node ./a.out.js

Results:

length: 10 == 10
find: 6 == -1

length: 10 == 10
find: 6 == -1

length: 10 == 56
find: 6 == -1

u16string::size() — fails when -Os is used
u16string::find() — always fails

u16.cpp:

#include <stdio.h>
#include <string>
int main()
{
    std::u16string s = u"0123456789";
    std::u16string::size_type l = s.size();
    printf("length: %d == %zd\n", 10, l);
    std::u16string::size_type p = s.find(u"678");
    printf("find: %d == %zd\n", 6, p);
    return 0;
}

wchar_t behavior is also unstable.
The my_wcslen() function malfunctions when -O2 or -Os is used.

Command line:

make

Results:

em++ -fshort-wchar -c wcslen.cpp -O0
em++ -fshort-wchar -c wchar.cpp -O0
em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
env node ./wchar.js
wchar_t size: 2
len: 10 == 10
em++ -fshort-wchar -c wcslen.cpp -O2
em++ -fshort-wchar -c wchar.cpp -O2
em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
env node ./wchar.js
wchar_t size: 2
len: 10 == 5
em++ -fshort-wchar -c wcslen.cpp -Os
em++ -fshort-wchar -c wchar.cpp -Os
em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
env node ./wchar.js
wchar_t size: 2
len: 10 == 5

wcslen.cpp:

#include <wchar.h>
extern "C" size_t my_wcslen(const wchar_t* s)
{
    const wchar_t* e = s;
    while (*e) {
        ++e;
    }
    return e - s;
}

wchar.cpp:

#include <stdio.h>
#include <wchar.h>
extern "C" size_t my_wcslen(const wchar_t* s);
int
main()
{
    printf("wchar_t size: %zu\n", sizeof(wchar_t));
    wchar_t str[] = L"0123456789";
    size_t l1 = sizeof(str) / sizeof(str[0]) - 1;
    size_t l2 = my_wcslen(str);
    printf("len: %zu == %zu\n", l1, l2);
    return 0;
}

Makefile:

OPTFLAGS =
run: run0 run2 runs
run0: OPTFLAGS = -O0
run0:
        em++ -fshort-wchar -c wcslen.cpp $(OPTFLAGS)
        em++ -fshort-wchar -c wchar.cpp $(OPTFLAGS)
        em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
        env node ./wchar.js
run2: OPTFLAGS = -O2
run2:
        em++ -fshort-wchar -c wcslen.cpp $(OPTFLAGS)
        em++ -fshort-wchar -c wchar.cpp $(OPTFLAGS)
        em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
        env node ./wchar.js
runs: OPTFLAGS = -Os
runs:
        em++ -fshort-wchar -c wcslen.cpp $(OPTFLAGS)
        em++ -fshort-wchar -c wchar.cpp $(OPTFLAGS)
        em++ -fshort-wchar -o wchar.js wchar.o wcslen.o
        env node ./wchar.js

This wcslen bug is reproducible when my_wcslen() is compiled in a separate translation unit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions