简体   繁体   中英

Why does not gcc and clang warn for unused result of library functions?

Consider this code:

int __attribute__((warn_unused_result)) foo(void)
{
    return 42;
}

int main(void)
{
    foo();
}

When compiled, it emits a warning:

$ gcc main.c
main.c: In function ‘main’:
main.c:8:5: warning: ignoring return value of ‘foo’, declared with attribute warn_unused_result [-Wunused-result]
    8 |     foo();
      |     ^~~~~

This is as expected. What I wonder is if there is any rationale why some many standard library functions is not declared with this attribute. I'm talking about functions like scanf where checking the return value is crucial in most cases, and also functions like malloc which is completely pointless if you do not use the return value. However, realloc seems to have this.

Is there any reason for not declaring scanf, malloc etc functions with __attribute__((warn_unused_result)) ? I think this could have prevented many bugs.

It may be enlightening to think about why these specific functions get warn_unused_result —this may help us figure out why other functions don't get the attribute. On my Glibc system, there are only two such functions:

extern void *realloc (void *__ptr, size_t __size)
     __THROW __attribute_warn_unused_result__ __attribute_alloc_size__ ((2));
extern void *reallocarray (void *__ptr, size_t __nmemb, size_t __size)
     __THROW __attribute_warn_unused_result__
     __attribute_alloc_size__ ((2, 3));

On my macOS system, there are three:

void    *malloc(size_t __size) __result_use_check __alloc_size(1);
void    *calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2);
void    *realloc(void *__ptr, size_t __size) __result_use_check __alloc_size(2);

So, why does this super-useful attribute only get used on realloc() and another near-identical function in Glibc?

The answer is because this attribute is designed to prevent a very specific bug. Let's say we have a 100-element array and want to resize it to add a 101st element (at index 100) (and let's ignore error handling):

// Create 100-element array.
int *arr = malloc(sizeof(int) * 100);
arr[99] = 1234;
// Resize and add a 101st element.
realloc(arr, sizeof(int) * 101); // bug
arr[100] = 1234;

Spot the bug? This is a serious memory error but it is also a memory error that may or may not get noticed very quickly. The original malloc will often round up to a larger size in the first place, and if realloc succeeds, you may end up with the same address anyway. The actual bug will only get noticed once you start writing into another object, or once another object gets allocated at the old address for arr .

This is something that might take you a while to debug.

So, the warning is designed to catch this serious bug that is difficult to debug. Compare with the following:

malloc(100 * sizeof(int));

This bug isn't very serious at all—it's just a memory leak. It's not even incorrect code!

As a fun exercise, try putting the above code into Godbolt and looking at the assembly output—GCC will actually remove the call to malloc entirely.

As for printf , scanf , and others—

int r = printf(...);
if (r == -1) {
    abort();
}

If GCC gave warnings for not checking the return of printf , people would get frustrated because they would see too many warnings in their code—and they would respond by turning the warnings off.

So sometimes it is better to only trigger warnings for the most serious cases, and let some other cases slide.


As a minor technical note, this is somewhat more an issue for the standard library maintainers, like the Glibc team, rather than GCC or Clang. Even though the standard library and compiler are tightly integrated, they are separate projects—and you can even swap out different standard libraries. For example, you might use musl, glibc, or Apple's libSystem.

  1. It is not portable.
  2. Standard does not require it.
  3. You can always write the wrapper if you want be warned.
static inline void * __attribute__((warn_unused_result, always_inline)) mymalloc(size_t size)
{
    return malloc(size);
}

int main(void)
{
    mymalloc(300);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM