sandbox: Fix setjmp/longjmp
authorAlexander Graf <agraf@suse.de>
Fri, 22 Jun 2018 12:44:12 +0000 (14:44 +0200)
committerAlexander Graf <agraf@suse.de>
Sun, 23 Sep 2018 19:55:30 +0000 (21:55 +0200)
In sandbox, longjmp returns to itself in an endless loop because
os_longjmp() calls into longjmp() which is provided by U-Boot which
again calls os_longjmp().

Setjmp on the other hand must not return because otherwise the
return freees up stack elements that we need during longjmp().

The only straight forward fix that doesn't involve nasty hacks I
could find is to directly link against the system setjmp/longjmp
implementations. That means we just provide the compiler with
hints that the symbol will be available and actually fill them
out with versions from libc.

This approach should be reasonably platform agnostic

Signed-off-by: Alexander Graf <agraf@suse.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
arch/sandbox/cpu/cpu.c
arch/sandbox/cpu/os.c
arch/sandbox/include/asm/setjmp.h
include/os.h

index e523223ebf8685a730af772bdb91605618e06ba6..609894504925c3fcec842d3cc834e2ea3df257d6 100644 (file)
@@ -288,15 +288,3 @@ ulong timer_get_boot_us(void)
 
        return (count - base_count) / 1000;
 }
-
-int setjmp(jmp_buf jmp)
-{
-       return os_setjmp((ulong *)jmp, sizeof(*jmp));
-}
-
-void longjmp(jmp_buf jmp, int ret)
-{
-       os_longjmp((ulong *)jmp, ret);
-       while (1)
-               ;
-}
index ca8d924cd65a9eaa4a48f1fe439176b266ac6fda..bb075042ade21d00ed988611d85fca2f730d8072 100644 (file)
@@ -631,28 +631,6 @@ void os_localtime(struct rtc_time *rt)
        rt->tm_isdst = tm->tm_isdst;
 }
 
-int os_setjmp(ulong *jmp, int size)
-{
-       jmp_buf dummy;
-
-       /*
-        * We cannot rely on the struct name that jmp_buf uses, so use a
-        * local variable here
-        */
-       if (size < sizeof(dummy)) {
-               printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n",
-                      size, sizeof(jmp_buf));
-               return -ENOSPC;
-       }
-
-       return setjmp((struct __jmp_buf_tag *)jmp);
-}
-
-void os_longjmp(ulong *jmp, int ret)
-{
-       longjmp((struct __jmp_buf_tag *)jmp, ret);
-}
-
 void os_abort(void)
 {
        abort();
index 1fe37c91cc3e7b02203a091ebe01cb270b5ae4e3..001c7ea322d2fae53ffb53c3e030920cc8ce5fe4 100644 (file)
@@ -24,6 +24,11 @@ struct jmp_buf_data {
 
 typedef struct jmp_buf_data jmp_buf[1];
 
+/*
+ * We have to directly link with the system versions of
+ * setjmp/longjmp, because setjmp must not return as otherwise
+ * the stack may become invalid.
+ */
 int setjmp(jmp_buf jmp);
 __noreturn void longjmp(jmp_buf jmp, int ret);
 
index e850f879ec3bfb714597ed81b53cbf259bec9caa..5c797212c25de1bb7450faaf7f8e217d932bf2a9 100644 (file)
@@ -330,27 +330,6 @@ int os_spl_to_uboot(const char *fname);
  */
 void os_localtime(struct rtc_time *rt);
 
-/**
- * os_setjmp() - Call setjmp()
- *
- * Call the host system's setjmp() function.
- *
- * @jmp: Buffer to store current execution state
- * @size: Size of buffer
- * @return normal setjmp() value if OK, -ENOSPC if @size is too small
- */
-int os_setjmp(ulong *jmp, int size);
-
-/**
- * os_longjmp() - Call longjmp()
- *
- * Call the host system's longjmp() function.
- *
- * @jmp: Buffer where previous execution state was stored
- * @ret: Value to pass to longjmp()
- */
-void os_longjmp(ulong *jmp, int ret);
-
 /**
  * os_abort() - Raise SIGABRT to exit sandbox (e.g. to debugger)
  */