Skip to content

Stack: a call to a weak function uses a definition the link may replace #191

Open

Description

@SizzleUnrlsd

The max stack of a caller takes a weak function's definition as the callee, but the link may replace that definition by another one. The result is then a known max stack that is wrong.

Example

weak-function.c:

__attribute__((weak)) int replaceable(int n) { return n; }
int caller(int n) { return replaceable(n); }

override.c, the definition that replaces it at link time:

int replaceable(int n) { volatile unsigned char buffer[256]; buffer[0] = (unsigned char)n; return buffer[0]; }

With the analyzer built from main 112ffcf:

$ stack_usage_analyzer weak-function.c override.c --format=json --compile-arg=--target=x86_64-unknown-linux-gnu
   replaceable  override.c       maxStack 272  maxStackUnknown false
   replaceable  weak-function.c  maxStack 16   maxStackUnknown false
   caller       weak-function.c  maxStack 32   maxStackUnknown false

$ stack_usage_analyzer weak-function.c --format=json --compile-arg=--target=x86_64-unknown-linux-gnu
   replaceable  weak-function.c  maxStack 16   maxStackUnknown false
   caller       weak-function.c  maxStack 32   maxStackUnknown false

Why it is wrong

The linked program calls the strong replaceable of override.c, which alone takes 272 bytes. caller is reported at 32 bytes, known.

Analyzed alone, weak-function.c can still be linked with a program that defines replaceable, so its definition is not the callee for sure.

Expected

The caller's max stack stays unknown in both runs, as for a call whose callee is not known:

  • caller.maxStackUnknown == true with override.c;
  • caller.maxStackUnknown == true without it.

Where it comes from

src/analysis/StackComputation.cpp takes any definition as the callee:

  • calledDefinition, without a resolver: callee && !callee->isDeclaration();
  • CallResolver::resolve: a direct callee that is not a declaration.

Neither checks hasExactDefinition(), which CallResolver's own index and the never-return pass (src/passes/ModulePasses.cpp) already require.

A weak alias does not have the problem: on main its call is not resolved at all, and #190, which follows aliases, keeps an interposable alias's callee unknown. A weak function that is not an alias is outside #190's scope.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions