From 8ebd2410b0a9d2f4383f51ea2164adf5e50163c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?= <grubba@grubba.org> Date: Thu, 25 Feb 2016 20:01:04 +0100 Subject: [PATCH] Runtime: Potential race condition fix. Wait for the compiler to complete before complaining about attempts to clone unfinished programs. Thanks to Jeff Hungerford <hungerf3-roxen3@house.ofdoom.com> for the report. Potential fix for [Pike mailinglist 14495]/[LysLysKOM 21645192] --- src/object.c | 51 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/src/object.c b/src/object.c index 98e9f6ce33..76d30b88a5 100644 --- a/src/object.c +++ b/src/object.c @@ -118,8 +118,24 @@ PMOD_EXPORT struct object *low_clone(struct program *p) { struct object *o; - if(!(p->flags & PROGRAM_PASS_1_DONE)) - Pike_error("Attempting to clone an unfinished program\n"); + if(!(p->flags & PROGRAM_PASS_1_DONE)) { + /* It might be compiling in a different thread. + * Wait for the compiler to finish. + * Note that this does not block if we are the compiler thread. + */ + lock_pike_compiler(); + /* We now have the compiler lock. + * Three posibilities: + * * The compiler was busy compiling the program in + * a different thread and has now finished. + * * We are the thread that is compiling the program. + * * The program is a remnant from a failed compilation. + */ + unlock_pike_compiler(); + if(!(p->flags & PROGRAM_PASS_1_DONE)) { + Pike_error("Attempting to clone an unfinished program\n"); + } + } #ifdef PROFILING p->num_clones++; @@ -344,12 +360,34 @@ PMOD_EXPORT struct object *debug_clone_object(struct program *p, int args) { ONERROR tmp; struct object *o; + + /* NB: The following test is somewhat redundant, since it is + * also performed by low_clone() below. The problem is + * that the PROGRAM_NEEDS_PARENT check inbetween needs + * this check to have been performed before. + */ + if(!(p->flags & PROGRAM_PASS_1_DONE)) { + /* It might be compiling in a different thread. + * Wait for the compiler to finish. + * Note that this does not block if we are the compiler thread. + */ + lock_pike_compiler(); + /* We now have the compiler lock. + * Three posibilities: + * * The compiler was busy compiling the program in + * a different thread and has now finished. + * * We are the thread that is compiling the program. + * * The program is a remnant from a failed compilation. + */ + unlock_pike_compiler(); + if(!(p->flags & PROGRAM_PASS_1_DONE)) { + Pike_error("Attempting to clone an unfinished program\n"); + } + } + if(p->flags & PROGRAM_NEEDS_PARENT) Pike_error("Parent lost, cannot clone program.\n"); - if(!(p->flags & PROGRAM_PASS_1_DONE)) - Pike_error("Attempting to clone an unfinished program\n"); - o=low_clone(p); if (!args) { push_object(o); @@ -400,9 +438,6 @@ PMOD_EXPORT struct object *parent_clone_object(struct program *p, debug_malloc_touch(o); } - if(!(p->flags & PROGRAM_PASS_1_DONE)) - Pike_error("Attempting to clone an unfinished program\n"); - if(p->flags & PROGRAM_USES_PARENT) { add_ref( PARENT_INFO(o)->parent=parent ); -- GitLab