https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122705
--- Comment #9 from Alejandro Colomar <[email protected]> --- (In reply to Alejandro Colomar from comment #6) > (In reply to Andrew Pinski from comment #5) > > (In reply to Alejandro Colomar from comment #0) > > > I propose [[gnu::returns_input_ptr(1)]] for strcpy(3), > > > and [[gnu::returns_derived_ptr(1)]] for strstr(3), > > > where in both attributes, the '1' is a parameter index, indicating > > > which parameter is the provenance of the returned pointer. > > > > And GCC already has code to special case some builtins: > > ``` > > /* Return the argument that the call STMT to a built-in function returns > > (including with an offset) or null if it doesn't. */ > > > > tree > > pass_waccess::gimple_call_return_arg (gcall *call) > > { > > /* Check for attribute fn spec to see if the function returns one > > of its arguments. */ > > attr_fnspec fnspec = gimple_call_fnspec (call); > > unsigned int argno; > > if (!fnspec.returns_arg (&argno)) > > { > > if (gimple_call_num_args (call) < 1) > > return NULL_TREE; > > > > if (!gimple_call_builtin_p (call, BUILT_IN_NORMAL)) > > return NULL_TREE; > > > > tree fndecl = gimple_call_fndecl (call); > > switch (DECL_FUNCTION_CODE (fndecl)) > > { > > case BUILT_IN_MEMPCPY: > > case BUILT_IN_MEMPCPY_CHK: > > case BUILT_IN_MEMCHR: > > case BUILT_IN_STRCHR: > > case BUILT_IN_STRRCHR: > > case BUILT_IN_STRSTR: > > case BUILT_IN_STPCPY: > > case BUILT_IN_STPCPY_CHK: > > case BUILT_IN_STPNCPY: > > case BUILT_IN_STPNCPY_CHK: > > argno = 0; > > break; > > > > default: > > return NULL_TREE; > > } > > } > > > > if (gimple_call_num_args (call) <= argno) > > return NULL_TREE; > > > > return gimple_call_arg (call, argno); > > } > > > > ``` > > > > Exposing this might be useful but it might also get abused incorrectly ... > > I have a function which I'd like to be marked with it: > > > ``` > [[gnu::returns_derived_pointer(1)]] > char * > stpecpy(char p[], const char end[]; > char p[p ? end - p : 0], const char end[0], const char *restrict src) D'oh. Paste-and-edit issues. The p in the prototype should be 'dst'. > { > bool trunc; > char *p; > size_t dsize, dlen, slen; > > if (dst == NULL) > return NULL; > > dsize = end - dst; > slen = strnlen(src, dsize); > trunc = (slen == dsize); > dlen = slen - trunc; > > p = stpcpy(mempcpy(dst, src, dlen), ""); > if (trunc) { > errno = E2BIG; > return NULL; > } > > return p; > } > ``` > > This function is to be used like this: > > ``` > #define endof(a) (&a[countof(a)]) > > char buf[1024]; > char *p, *e; > > p = buf; > e = endof(buf); > > p = stpecpy(p, e, "foo"); > p = stpecpy(p, e, "bar"); > p = stpecpy(p, e, "baz"); > if (p == NULL) > goto fail; > ``` > > Currently, the compiler is blind to this function. It can't know the > relationship between p and e. > > If the compiler knew that p is always derived from the original p, it would > also know that 'e' is always >=p, regardless of the value of p. This would > improve static analysis. > > I think this would be necessary for a future where buffer overflows are > impossible in C.
