Message ID | 20210322110249.4387-3-xypron.glpk@gmx.de |
---|---|
State | Superseded, archived |
Delegated to: | Andes |
Headers | show |
Series | riscv: simplify longjmp | expand |
On 3/22/21 7:02 AM, Heinrich Schuchardt wrote: > Provide a unit test for the longjmp() library function > > Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> > --- > v2: > no change > --- > test/lib/Makefile | 1 + > test/lib/longjmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 45 insertions(+) > create mode 100644 test/lib/longjmp.c > > diff --git a/test/lib/Makefile b/test/lib/Makefile > index 97c11e35a8..a30f615aa9 100644 > --- a/test/lib/Makefile > +++ b/test/lib/Makefile > @@ -7,6 +7,7 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o > obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o > obj-y += hexdump.o > obj-y += lmb.o > +obj-y += longjmp.o > obj-$(CONFIG_CONSOLE_RECORD) += test_print.o > obj-$(CONFIG_SSCANF) += sscanf.o > obj-y += string.o > diff --git a/test/lib/longjmp.c b/test/lib/longjmp.c > new file mode 100644 > index 0000000000..7571540ffc > --- /dev/null > +++ b/test/lib/longjmp.c > @@ -0,0 +1,44 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Test setjmp(), longjmp() > + * > + * Copyright (c) 2021, Heinrich Schuchardt <xypron.glpk@gmx.de> > + */ > + > +#include <common.h> > +#include <test/lib.h> > +#include <test/test.h> > +#include <test/ut.h> > +#include <asm/setjmp.h> > + > +/** > + * test_longjmp_ret() - get longjmp() return value > + * > + * @i: value passed to longjmp() > + * Return: value returned by longjmp() > + */ > +int test_longjmp_ret(int i) > +{ > + jmp_buf env; > + int ret; > + > + ret = setjmp(env); > + if (ret) > + return ret; > + longjmp(env, i); > + /* We should not arrive here */ > + return 0x1000; > +} > + > +static int lib_test_longjmp(struct unit_test_state *uts) > +{ > + int i; > + > + for (i = -3; i < 0; ++i) > + ut_asserteq(i, test_longjmp_ret(i)); > + ut_asserteq(1, test_longjmp_ret(0)); > + for (i = 1; i < 4; ++i) > + ut_asserteq(i, test_longjmp_ret(i)); > + return 0; > +} > +LIB_TEST(lib_test_longjmp, 0); > -- > 2.30.2 > Reviewed-by: Sean Anderson <seanga2@gmail.com> Tested-by: Sean Anderson <seanga2@gmail.com> Though I would like to test that variables are set correctly e.g. by doing int test_longjmp_ret(int i) { jmp_buf env; int ret; ret = setjmp(env); if (ret) return ret; ret = 0x1000; longjmp(env, i); /* We should not arrive here */ return ret; } --Sean
On 3/22/21 9:23 AM, Sean Anderson wrote: > > On 3/22/21 7:02 AM, Heinrich Schuchardt wrote: >> Provide a unit test for the longjmp() library function >> >> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> >> --- >> v2: >> no change >> --- >> test/lib/Makefile | 1 + >> test/lib/longjmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 45 insertions(+) >> create mode 100644 test/lib/longjmp.c >> >> diff --git a/test/lib/Makefile b/test/lib/Makefile >> index 97c11e35a8..a30f615aa9 100644 >> --- a/test/lib/Makefile >> +++ b/test/lib/Makefile >> @@ -7,6 +7,7 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o >> obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o >> obj-y += hexdump.o >> obj-y += lmb.o >> +obj-y += longjmp.o >> obj-$(CONFIG_CONSOLE_RECORD) += test_print.o >> obj-$(CONFIG_SSCANF) += sscanf.o >> obj-y += string.o >> diff --git a/test/lib/longjmp.c b/test/lib/longjmp.c >> new file mode 100644 >> index 0000000000..7571540ffc >> --- /dev/null >> +++ b/test/lib/longjmp.c >> @@ -0,0 +1,44 @@ >> +// SPDX-License-Identifier: GPL-2.0+ >> +/* >> + * Test setjmp(), longjmp() >> + * >> + * Copyright (c) 2021, Heinrich Schuchardt <xypron.glpk@gmx.de> >> + */ >> + >> +#include <common.h> >> +#include <test/lib.h> >> +#include <test/test.h> >> +#include <test/ut.h> >> +#include <asm/setjmp.h> >> + >> +/** >> + * test_longjmp_ret() - get longjmp() return value >> + * >> + * @i: value passed to longjmp() >> + * Return: value returned by longjmp() >> + */ >> +int test_longjmp_ret(int i) >> +{ >> + jmp_buf env; >> + int ret; >> + >> + ret = setjmp(env); >> + if (ret) >> + return ret; >> + longjmp(env, i); >> + /* We should not arrive here */ >> + return 0x1000; >> +} >> + >> +static int lib_test_longjmp(struct unit_test_state *uts) >> +{ >> + int i; >> + >> + for (i = -3; i < 0; ++i) >> + ut_asserteq(i, test_longjmp_ret(i)); >> + ut_asserteq(1, test_longjmp_ret(0)); >> + for (i = 1; i < 4; ++i) >> + ut_asserteq(i, test_longjmp_ret(i)); >> + return 0; >> +} >> +LIB_TEST(lib_test_longjmp, 0); >> -- >> 2.30.2 >> > > Reviewed-by: Sean Anderson <seanga2@gmail.com> > Tested-by: Sean Anderson <seanga2@gmail.com> > > Though I would like to test that variables are set correctly e.g. by doing > > int test_longjmp_ret(int i) > { > jmp_buf env; > int ret; > > ret = setjmp(env); > if (ret) > return ret; > ret = 0x1000; > longjmp(env, i); > /* We should not arrive here */ > return ret; > } > > --Sean err, rather by doing int test_longjmp_ret(int i) { jmp_buf env; int ret; int foo = i; ret = setjmp(env); if (ret) return foo; foo = 0x1000; longjmp(env, i); /* We should not arrive here */ return foo; } or something else which demonstrates that variables get reset to their earlier values. --Sean
On 22.03.21 14:30, Sean Anderson wrote: > > On 3/22/21 9:23 AM, Sean Anderson wrote: >> >> On 3/22/21 7:02 AM, Heinrich Schuchardt wrote: >>> Provide a unit test for the longjmp() library function >>> >>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> >>> --- >>> v2: >>> no change >>> --- >>> test/lib/Makefile | 1 + >>> test/lib/longjmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ >>> 2 files changed, 45 insertions(+) >>> create mode 100644 test/lib/longjmp.c >>> >>> diff --git a/test/lib/Makefile b/test/lib/Makefile >>> index 97c11e35a8..a30f615aa9 100644 >>> --- a/test/lib/Makefile >>> +++ b/test/lib/Makefile >>> @@ -7,6 +7,7 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o >>> obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o >>> obj-y += hexdump.o >>> obj-y += lmb.o >>> +obj-y += longjmp.o >>> obj-$(CONFIG_CONSOLE_RECORD) += test_print.o >>> obj-$(CONFIG_SSCANF) += sscanf.o >>> obj-y += string.o >>> diff --git a/test/lib/longjmp.c b/test/lib/longjmp.c >>> new file mode 100644 >>> index 0000000000..7571540ffc >>> --- /dev/null >>> +++ b/test/lib/longjmp.c >>> @@ -0,0 +1,44 @@ >>> +// SPDX-License-Identifier: GPL-2.0+ >>> +/* >>> + * Test setjmp(), longjmp() >>> + * >>> + * Copyright (c) 2021, Heinrich Schuchardt <xypron.glpk@gmx.de> >>> + */ >>> + >>> +#include <common.h> >>> +#include <test/lib.h> >>> +#include <test/test.h> >>> +#include <test/ut.h> >>> +#include <asm/setjmp.h> >>> + >>> +/** >>> + * test_longjmp_ret() - get longjmp() return value >>> + * >>> + * @i: value passed to longjmp() >>> + * Return: value returned by longjmp() >>> + */ >>> +int test_longjmp_ret(int i) >>> +{ >>> + jmp_buf env; >>> + int ret; >>> + >>> + ret = setjmp(env); >>> + if (ret) >>> + return ret; >>> + longjmp(env, i); >>> + /* We should not arrive here */ >>> + return 0x1000; >>> +} >>> + >>> +static int lib_test_longjmp(struct unit_test_state *uts) >>> +{ >>> + int i; >>> + >>> + for (i = -3; i < 0; ++i) >>> + ut_asserteq(i, test_longjmp_ret(i)); >>> + ut_asserteq(1, test_longjmp_ret(0)); >>> + for (i = 1; i < 4; ++i) >>> + ut_asserteq(i, test_longjmp_ret(i)); >>> + return 0; >>> +} >>> +LIB_TEST(lib_test_longjmp, 0); >>> -- >>> 2.30.2 >>> >> >> Reviewed-by: Sean Anderson <seanga2@gmail.com> >> Tested-by: Sean Anderson <seanga2@gmail.com> >> >> Though I would like to test that variables are set correctly e.g. by >> doing >> >> int test_longjmp_ret(int i) >> { >> jmp_buf env; >> int ret; >> >> ret = setjmp(env); >> if (ret) >> return ret; >> ret = 0x1000; >> longjmp(env, i); >> /* We should not arrive here */ >> return ret; >> } >> >> --Sean > > err, rather by doing > > int test_longjmp_ret(int i) > { > jmp_buf env; > int ret; > int foo = i; > > ret = setjmp(env); > if (ret) > return foo; > foo = 0x1000; > longjmp(env, i); > /* We should not arrive here */ > return foo; > } > > or something else which demonstrates that variables get reset to their > earlier values. > > --Sean Hello Sean, thank you for reviewing. Would the following make sense to you to check that the stack pointer is correctly restored? struct test_jmp_buf { jmp_buf env; int val; }; /** * test_longjmp() - test longjmp function * * @i is passed to longjmp. * @i << 8 is set in the environment structure. * * @env: environment * @i: value passed to longjmp() */ static void noinline test_longjmp(struct test_jmp_buf *env, int i) { env->val = i << 8; longjmp(env->env, i); } /** * test_setjmp() - test setjmp function * * setjmp() will return the value @i passed to longjmp() if @i is non-zero. * For @i == 0 we expect return value 1. * * @i << 8 will be set by test_longjmp in the environment structure. * This value can be used to check that the stack frame is restored. * * We return the XORed values to allow simply check both at once. * * @i: value passed to longjmp() * Return: values return byby longjmp() */ static int test_setjmp(int i) { struct test_jmp_buf env; int ret; env.val = -1; ret = setjmp(env.env); if (ret) return ret ^ env.val; test_longjmp(&env, i); /* We should not arrive here */ return 0x1000; } Best regards Heinrich
On 3/22/21 12:42 PM, Heinrich Schuchardt wrote: > On 22.03.21 14:30, Sean Anderson wrote: >> >> On 3/22/21 9:23 AM, Sean Anderson wrote: >>> >>> On 3/22/21 7:02 AM, Heinrich Schuchardt wrote: >>>> Provide a unit test for the longjmp() library function >>>> >>>> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> >>>> --- >>>> v2: >>>> no change >>>> --- >>>> test/lib/Makefile | 1 + >>>> test/lib/longjmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ >>>> 2 files changed, 45 insertions(+) >>>> create mode 100644 test/lib/longjmp.c >>>> >>>> diff --git a/test/lib/Makefile b/test/lib/Makefile >>>> index 97c11e35a8..a30f615aa9 100644 >>>> --- a/test/lib/Makefile >>>> +++ b/test/lib/Makefile >>>> @@ -7,6 +7,7 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o >>>> obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o >>>> obj-y += hexdump.o >>>> obj-y += lmb.o >>>> +obj-y += longjmp.o >>>> obj-$(CONFIG_CONSOLE_RECORD) += test_print.o >>>> obj-$(CONFIG_SSCANF) += sscanf.o >>>> obj-y += string.o >>>> diff --git a/test/lib/longjmp.c b/test/lib/longjmp.c >>>> new file mode 100644 >>>> index 0000000000..7571540ffc >>>> --- /dev/null >>>> +++ b/test/lib/longjmp.c >>>> @@ -0,0 +1,44 @@ >>>> +// SPDX-License-Identifier: GPL-2.0+ >>>> +/* >>>> + * Test setjmp(), longjmp() >>>> + * >>>> + * Copyright (c) 2021, Heinrich Schuchardt <xypron.glpk@gmx.de> >>>> + */ >>>> + >>>> +#include <common.h> >>>> +#include <test/lib.h> >>>> +#include <test/test.h> >>>> +#include <test/ut.h> >>>> +#include <asm/setjmp.h> >>>> + >>>> +/** >>>> + * test_longjmp_ret() - get longjmp() return value >>>> + * >>>> + * @i: value passed to longjmp() >>>> + * Return: value returned by longjmp() >>>> + */ >>>> +int test_longjmp_ret(int i) >>>> +{ >>>> + jmp_buf env; >>>> + int ret; >>>> + >>>> + ret = setjmp(env); >>>> + if (ret) >>>> + return ret; >>>> + longjmp(env, i); >>>> + /* We should not arrive here */ >>>> + return 0x1000; >>>> +} >>>> + >>>> +static int lib_test_longjmp(struct unit_test_state *uts) >>>> +{ >>>> + int i; >>>> + >>>> + for (i = -3; i < 0; ++i) >>>> + ut_asserteq(i, test_longjmp_ret(i)); >>>> + ut_asserteq(1, test_longjmp_ret(0)); >>>> + for (i = 1; i < 4; ++i) >>>> + ut_asserteq(i, test_longjmp_ret(i)); >>>> + return 0; >>>> +} >>>> +LIB_TEST(lib_test_longjmp, 0); >>>> -- >>>> 2.30.2 >>>> >>> >>> Reviewed-by: Sean Anderson <seanga2@gmail.com> >>> Tested-by: Sean Anderson <seanga2@gmail.com> >>> >>> Though I would like to test that variables are set correctly e.g. by >>> doing >>> >>> int test_longjmp_ret(int i) >>> { >>> jmp_buf env; >>> int ret; >>> >>> ret = setjmp(env); >>> if (ret) >>> return ret; >>> ret = 0x1000; >>> longjmp(env, i); >>> /* We should not arrive here */ >>> return ret; >>> } >>> >>> --Sean >> >> err, rather by doing >> >> int test_longjmp_ret(int i) >> { >> jmp_buf env; >> int ret; >> int foo = i; >> >> ret = setjmp(env); >> if (ret) >> return foo; >> foo = 0x1000; >> longjmp(env, i); >> /* We should not arrive here */ >> return foo; >> } >> >> or something else which demonstrates that variables get reset to their >> earlier values. >> >> --Sean > > Hello Sean, > > thank you for reviewing. > > Would the following make sense to you to check that the stack pointer is > correctly restored? > > > struct test_jmp_buf { > jmp_buf env; > int val; > }; > > /** > * test_longjmp() - test longjmp function > * > * @i is passed to longjmp. > * @i << 8 is set in the environment structure. > * > * @env: environment > * @i: value passed to longjmp() > */ > static void noinline test_longjmp(struct test_jmp_buf *env, int i) > { > env->val = i << 8; > longjmp(env->env, i); > } > > /** > * test_setjmp() - test setjmp function > * > * setjmp() will return the value @i passed to longjmp() if @i is non-zero. > * For @i == 0 we expect return value 1. > * > * @i << 8 will be set by test_longjmp in the environment structure. > * This value can be used to check that the stack frame is restored. > * > * We return the XORed values to allow simply check both at once. > * > * @i: value passed to longjmp() > * Return: values return byby longjmp() nit: by > */ > static int test_setjmp(int i) > { > struct test_jmp_buf env; > int ret; > > env.val = -1; > ret = setjmp(env.env); > if (ret) > return ret ^ env.val; > test_longjmp(&env, i); > /* We should not arrive here */ > return 0x1000; > } > > Best regards > > Heinrich > Yes, this looks good. --Sean
On Mär 22 2021, Sean Anderson wrote: > int test_longjmp_ret(int i) > { > jmp_buf env; > int ret; > int foo = i; > > ret = setjmp(env); > if (ret) > return foo; > foo = 0x1000; > longjmp(env, i); > /* We should not arrive here */ > return foo; This is undefined. When modifying a non-volatile auto variable between setjmp and longjmp, there is no requirement that the value is preserved. Andreas.
On 24.03.21 10:18, Andreas Schwab wrote: > On Mär 22 2021, Sean Anderson wrote: > >> int test_longjmp_ret(int i) >> { >> jmp_buf env; >> int ret; >> int foo = i; >> >> ret = setjmp(env); >> if (ret) >> return foo; >> foo = 0x1000; >> longjmp(env, i); >> /* We should not arrive here */ >> return foo; > > This is undefined. When modifying a non-volatile auto variable between > setjmp and longjmp, there is no requirement that the value is preserved. > > Andreas. > Hello Andreas, thank you for reviewing. Your comment relates to the following paragraph in the C99 specification: "All accessible objects have values, and all other components of the abstract machine have state, as of the time the longjmp function was called, except that the values of objects of automatic storage duration that are local to the function containing the invocation of the corresponding setjmp macro that do not have volatile-qualified type and have been changed between the setjmp invocation and longjmp call are indeterminate." And foo is obviously "changed between the setjmp invocation and longjmp call". The current version of the patch is: https://patchwork.ozlabs.org/project/uboot/patch/20210323181127.32411-3-xypron.glpk@gmx.de/ So I guess we have to declare env as volatile in setjmp() in this version of the patch because it is changed between the setjmp and longjmp invocations? Best regards Heinrich
On Mär 24 2021, Heinrich Schuchardt wrote: > And foo is obviously "changed between the setjmp invocation and longjmp > call". > > The current version of the patch is: > https://patchwork.ozlabs.org/project/uboot/patch/20210323181127.32411-3-xypron.glpk@gmx.de/ > > So I guess we have to declare env as volatile in setjmp() in this > version of the patch because it is changed between the setjmp and > longjmp invocations? Yes, I think so, or make it static. Andreas.
On 24.03.21 13:39, Andreas Schwab wrote: > On Mär 24 2021, Heinrich Schuchardt wrote: > >> And foo is obviously "changed between the setjmp invocation and longjmp >> call". >> >> The current version of the patch is: >> https://patchwork.ozlabs.org/project/uboot/patch/20210323181127.32411-3-xypron.glpk@gmx.de/ >> >> So I guess we have to declare env as volatile in setjmp() in this >> version of the patch because it is changed between the setjmp and >> longjmp invocations? > > Yes, I think so, or make it static. The whole point of this variable during test is that it lives on the stack. So static is not what I am looking for. Actually adding volatile does not change the generated machine code because test_longjmp() is marked as noinline and therefore has its own stack frame separated from test_setjmp(). But adding volatile adds to the portability. So I will respin the series. Best regards Heinrich
diff --git a/test/lib/Makefile b/test/lib/Makefile index 97c11e35a8..a30f615aa9 100644 --- a/test/lib/Makefile +++ b/test/lib/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_EFI_LOADER) += efi_device_path.o obj-$(CONFIG_EFI_SECURE_BOOT) += efi_image_region.o obj-y += hexdump.o obj-y += lmb.o +obj-y += longjmp.o obj-$(CONFIG_CONSOLE_RECORD) += test_print.o obj-$(CONFIG_SSCANF) += sscanf.o obj-y += string.o diff --git a/test/lib/longjmp.c b/test/lib/longjmp.c new file mode 100644 index 0000000000..7571540ffc --- /dev/null +++ b/test/lib/longjmp.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Test setjmp(), longjmp() + * + * Copyright (c) 2021, Heinrich Schuchardt <xypron.glpk@gmx.de> + */ + +#include <common.h> +#include <test/lib.h> +#include <test/test.h> +#include <test/ut.h> +#include <asm/setjmp.h> + +/** + * test_longjmp_ret() - get longjmp() return value + * + * @i: value passed to longjmp() + * Return: value returned by longjmp() + */ +int test_longjmp_ret(int i) +{ + jmp_buf env; + int ret; + + ret = setjmp(env); + if (ret) + return ret; + longjmp(env, i); + /* We should not arrive here */ + return 0x1000; +} + +static int lib_test_longjmp(struct unit_test_state *uts) +{ + int i; + + for (i = -3; i < 0; ++i) + ut_asserteq(i, test_longjmp_ret(i)); + ut_asserteq(1, test_longjmp_ret(0)); + for (i = 1; i < 4; ++i) + ut_asserteq(i, test_longjmp_ret(i)); + return 0; +} +LIB_TEST(lib_test_longjmp, 0);
Provide a unit test for the longjmp() library function Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de> --- v2: no change --- test/lib/Makefile | 1 + test/lib/longjmp.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 test/lib/longjmp.c -- 2.30.2