On 9/16/20 11:32 AM, H.J. Lu wrote: > On Wed, Sep 16, 2020 at 10:24 AM Jeff Law wrote: >> >> On 9/16/20 11:13 AM, H.J. Lu wrote: >>> On Wed, Sep 16, 2020 at 10:10 AM Jeff Law 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 >>>>> 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? It's global in the sense that it uniqifies across TU boundaries, which is its purpose.  Consider a function scoped static object in a template or C++ inlined function.  We can end up with multiple copies in different TUs and we have to collapse them to a single representative object.  We'd need to do the same thing here.  Without thinking a whole lot about it, but ISTM that if LTO pulls in a function that references a static object, then that static object would need to be STB_GNU_UNIQUE. For something like you've shown above, I'd *hope* we give an ODR error :-) Jeff