Skip to content

Fix Apron handling of escaped locals - #2100

Merged
sim642 merged 3 commits into
masterfrom
issue_2091
Sep 14, 2026
Merged

sim642 merged 3 commits into
masterfrom
issue_2091

Conversation

@michael-schwarz

Copy link
Copy Markdown
Member

Fix Apron’s handling of locals whose addresses escape through global pointers.

In single-threaded execution, escaped locals were read using their local relational variable but written using a separate global relational variable. Calls could also omit escaped locals from callee states and restore stale pre-call relations afterward. This allowed Apron to retain relations invalidated by indirect writes.

This change:

  • consistently updates escaped locals using their local relational variables before entering multithreaded mode;
  • retains escaped locals in callee relational states;
  • avoids restoring stale pre-call relations for escaped locals;
  • adds regressions for both entirely single-threaded execution and entering multithreaded mode inside the callee.

Tested with:

  • opam exec -- scripts/update_suite.rb group apron3 -q
  • opam exec -- dune build @runaprontest --display quiet

Closes #2091.

@michael-schwarz
michael-schwarz requested a review from sim642 August 14, 2026 09:15
@michael-schwarz
michael-schwarz marked this pull request as ready for review August 14, 2026 09:29
@michael-schwarz michael-schwarz added bug unsound relational Relational analyses (Apron, affeq, lin2var) labels Aug 14, 2026
@jprotopopov-ut

Copy link
Copy Markdown
Contributor

Locally, the change appears fine, although to me it looks like a whack-a-mole fix. For what it's worth, I tried to prompt AI to poke holes in the code for counterexamples, and (before the session got derailed by cybersecurity guardrails) it got me the following adjacent case:

// PARAM: --set ana.activated[+] apron --enable ana.sv-comp.functions
#include <goblint.h>
#include <string.h>

static int *target;

static void modify(void) {
  *target = __VERIFIER_nondet_int();
}

int main(void) {
  int left = __VERIFIER_nondet_int();
  int right = left;
  int *source = &right;
  memcpy(&target, &source, sizeof(target));

  modify();
  __goblint_check(left == right); // UNKNOWN!
}

which crashes Goblint with

Fatal error: exception Apron.Manager.Error
 {  exn = Exc_invalid_argument; funid = Funid_assign_texpr_array;
  msg = unknown variable right#671 in the environment; }

Given that the failure is different from the original one, I am approving this pull request.

@michael-schwarz

Copy link
Copy Markdown
Member Author

Although to me it looks like a whack-a-mole fix.

I took a look at your example, thank you! I think the issue there is fundamentally different. The problem is that the escape analysis does not consider the escape via memcpy. This also leads to an unsoundness in the base issue.

// PARAM: --enable ana.sv-comp.functions
#include <goblint.h>
#include <pthread.h>
#include <string.h>

static int *target;

static void *modify(void *arg) {
  *target = 7;
  return NULL;
}

int main(void) {
  int right = 42;
  int *source = &right;
  memcpy(&target, &source, sizeof(target));

  pthread_t thread;
  pthread_create(&thread, NULL, modify, NULL);
  pthread_join(thread, NULL);

  __goblint_check(right == 42); // Incorrectly succeeds
}

Given that there it is an issue with threadEscape affecting different analyses, I'll move it to a separate issue.

Comment thread src/analyses/apron/relationAnalysis.apron.ml Outdated
@michael-schwarz
michael-schwarz requested a review from sim642 August 18, 2026 03:23
@michael-schwarz

Copy link
Copy Markdown
Member Author

@sim642: Can you have another look so we can merge? Or is this subsumed by one of your larger redsigns, in which cas we shoudl close this?

@sim642 sim642 added this to the v2.9.0 milestone Sep 14, 2026
@sim642
sim642 merged commit 5320a6b into master Sep 14, 2026
19 checks passed
@sim642
sim642 deleted the issue_2091 branch September 14, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug relational Relational analyses (Apron, affeq, lin2var) unsound

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Apron unsoundly retains relations for locals modified through an escaped pointer

3 participants