https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95755
Martin Sebor <msebor at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Ever confirmed|0 |1 Last reconfirmed| |2020-06-19 Blocks| |88781 Component|c |middle-end Status|UNCONFIRMED |NEW --- Comment #1 from Martin Sebor <msebor at gcc dot gnu.org> --- The sizes used to trigger the warning are based on what it can determine from the representation of source code it sees. In this case it's the IL below (seen in the output of -fdump-tree-strlen): mz_format (struct mz_cb * rcb) { struct mz_unity ncred; struct mz_unity * ocred; char[513] * _1; <bb 2> [local count: 1073741824]: ocred_4 = rcb_3(D)->mz_creds; ncred = *ocred_4; _1 = &rcb_3(D)->mz_url; snprintf (_1, 513, "%s/name/%s/abc1234", &MEM <char[129]> [(void *)&ncred + 8B], &MEM <char[161]> [(void *)&ncred + 288B]); ncred ={v} {CLOBBER}; return; } >From the argument to the first %s directive (&MEM <char[129]> [(void *)&ncred + 8B]), rather than using its type which is unfortunately unreliable in other contexts, the warning conservatively uses the size of the whole object, which it calculates to be 4552 bytes. It uses the same conservative heuristic as optimizations use here, which could be argued is both good and bad. It's good in that it reflects what would happen if only the last ncred array member was a nul-terminated string (GCC assumes that strlen results are bounded by the size of the complete object the argument points to). The words "may be truncated" in the warning are used specifically to reflect that truncation is possible but not inevitable. It's bad because it triggers what for correct code seems like false positives. In this case, to avoid triggering, the warning could consider the MEM_REF type instead (which is char[129]). Unfortunately, because the type is seen as unreliable and relying on it has led to bugs in the past, there's a lot of sensitivity to using it for anything. Alternatively, the warning could use the offset to find the member and the size of the member (like -Wrestrict already does). That in this case is rcred->variant.variant01.am_field0, the first member of the union, not the second member, az_field11, referenced in the source. Because they happen to have the same size the strategy would work here but not in other cases when the first member were bigger. Another alternative (for unions) is to find the smallest member at the offset. That would lead to false negatives if the member actually referenced in the source were the bigger one. Yet another option is to give up if the member can't be unambiguously identified. That would lead to even more false negatives (basically, any representation involving a MEM_REF would have to be excluded from the analysis). Yet another possibility that we have been discussing recently is capturing the member referenced in the source earlier on, before it has been lost to MEM_REF, and using it. That's probably the only viable alternative but it requires a change to the internal representation GCC uses, so it's not going to be a simple solution. I realize as a user you probably don't care about any of this. I summarize it mainly for other GCC developers. Until we have decided on and implemented a strategy for this there are a few ways to avoid the warning: 1) use precision to limit the amount of output of each %s directive 2) assert before the call that the lengths of the strings passed to the %s directives aren't too long (e.g., if (strlen (cred->variant.variant02.az_field11) > 32) __builtin_unreachable ();) 3) test the result of the call and handle the truncation somehow (e.g., similarly to the precondition above except with an abort or trap replacing __builtin_unreachable if the snprintf call isn't followed by another statement) Referenced Bugs: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88781 [Bug 88781] [meta-bug] bogus/missing -Wstringop-truncation warnings