On Wed, Sep 16, 2020 at 10:24 AM Jeff Law <l...@redhat.com> wrote: > > > On 9/16/20 11:13 AM, H.J. Lu wrote: > > On Wed, Sep 16, 2020 at 10:10 AM Jeff Law <l...@redhat.com> wrote: > >> > >> On 9/16/20 11:05 AM, H.J. Lu wrote: > >>> On Wed, Sep 16, 2020 at 9:53 AM Jeff Law via Gcc-patches > >>> <gcc-patches@gcc.gnu.org> wrote: > >>>> Consider a TU with file scoped "static const object utf8_sb_map". A > >>>> routine within the TU will stuff &utf8_sb_map into an object, something > >>>> like: > >>>> > >>>> fu (...) > >>>> > >>>> { > >>>> > >>>> if (cond) > >>>> > >>>> dfa->sb_char = utf8_sb_map; > >>>> > >>>> else > >>>> > >>>> dfa->sb_char = malloc (...); > >>>> > >>>> } > >>>> > >>>> > >>>> There is another routine in the TU which looks like > >>>> > >>>> bar (...) > >>>> > >>>> { > >>>> > >>>> if (dfa->sb_char != utf8_sb_map) > >>>> > >>>> free (dfa->sb_char); > >>>> > >>>> } > >>>> > >>>> > >>>> Now imagine that the TU is compiled (with LTO) into a static library, > >>>> libgl.a and there's a DSO (libdso.so) which gets linked against libgl.a > >>>> and references the first routine (fu). We get a copy of fu in the DSO > >>>> along with a copy of utf8_sb_map. > >>>> > >>>> > >>>> Then imagine there's a main executable that dynamicly links against > >>>> libdso.so, then links statically against libgl.a. Assume the main > >>>> executable does not directly reference fu(), but does call a routine in > >>>> libdso.so which eventually calls fu(). Also assume the main executable > >>>> directly calls bar(). Again, remember we're compiling with LTO, so we > >>>> don't suck in the entire TU, just the routines/data we need. > >>>> > >>>> > >>>> In this scenario, both libdso.so and the main executable are going to a > >>>> copy of utf8_sb_map and they'll be at different addresses. So when the > >>>> main executable calls into libdso.so which in turn calls libdso's copy > >>>> of fu() which stuffs the address of utf8_sb_map from the DSO into > >>>> dfa->sb_char. Later the main executable calls bar() that's in the main > >>>> executable. It does the comparison to see if dfa->sb_char is equal to > >>>> utf8_sb_map -- but it's using the main executable's copy of utf8_sb_map > >>>> and naturally free() blows us because it was passed a static object, not > >>>> a malloc'd object. > >>>> > >>>> > >>>> ISTM this is a lot like the problem we have where we inline functions > >>>> with static data. To fix those we use STB_GNU_UNIQUE. But I don't see > >>>> any code in the C front-end which would utilize STB_GNU_UNIQUE. It's > >>>> support seems limited to C++. > >>>> > >>>> > >>>> How is this supposed to work for C? > >>>> > >>>> > >>>> Jeff > >>>> > >>>> > >>> Can you group utf8_sb_map, fu and bar together so that they are defined > >>> together? > >> They're all defined within the same TU in gnulib. It's the LTO > >> dead/unreachable code elimination that results in just parts of the TU > >> being copied into the DSO and a different set copied into the main > >> executable. In many ways LTO makes this look a lot like the static data > >> member problems we've had to deal with in the C++ world. > > In this case, LTO should treat them as in a single group. Removing > > one group member should remove the whole group. Keep one member > > should keep the whole group. > > Do you mean ensure they're all in a partition together? I think that > might work in the immediate term, but is probably brittle in the long > term. I'd tend to lean towards forcing these static data objects to be > STB_GNU_UNIQUE -- that seems more robust to me.
Isn't STB_GNU_UNIQUE binding global? How does it work with static const int foo; and static const double foo; in different files? -- H.J.