From 6f6bd650358a154d78b403a048f937d9e55f08a4 Mon Sep 17 00:00:00 2001 From: stefan schippers Date: Thu, 19 Jan 2023 02:46:45 +0100 Subject: [PATCH] fflush() all stdio buffers before calling fork(). End child processes with _exit() instead of exit() to avoid double fflushing in parent i/o streams --- XSchemWin/XSchemWin.vcxproj | 2 ++ src/actions.c | 14 +++++------ src/psprint.c | 8 +++---- src/save.c | 46 +++++++++++++++++++++++++++++-------- src/xschem.h | 2 +- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/XSchemWin/XSchemWin.vcxproj b/XSchemWin/XSchemWin.vcxproj index a1fde5c6..a601fc21 100644 --- a/XSchemWin/XSchemWin.vcxproj +++ b/XSchemWin/XSchemWin.vcxproj @@ -223,6 +223,7 @@ + @@ -257,6 +258,7 @@ + diff --git a/src/actions.c b/src/actions.c index 6ae8dde8..b1eb2f93 100644 --- a/src/actions.c +++ b/src/actions.c @@ -273,16 +273,16 @@ void new_xschem_process(const char *cell, int symbol) fprintf(errfp, "new_xschem_process(): executable not found\n"); return; } - + fflush(NULL); /* flush all stdio streams before process forking */ /* double fork method to avoid zombies 20180925*/ - if ( (pid1 = fork()) ) { + if ( (pid1 = fork()) > 0 ) { /* parent process */ waitpid(pid1, &status, 0); - } else if (!pid1) { + } else if (pid1 == 0) { /* child process */ - if ( (pid2 = fork()) ) { - exit(0); /* --> child of child will be reparented to init */ - } else if (!pid2) { + if ( (pid2 = fork()) > 0 ) { + _exit(0); /* --> child of child will be reparented to init */ + } else if (pid2 == 0) { /* child of child */ if(!cell || !cell[0]) { if(!symbol) @@ -303,7 +303,7 @@ void new_xschem_process(const char *cell, int symbol) } else { /* error */ fprintf(errfp, "new_xschem_process(): fork error 1\n"); - tcleval("exit"); + _exit(1); } } else { /* error */ diff --git a/src/psprint.c b/src/psprint.c index fddd8bd1..692a554e 100644 --- a/src/psprint.c +++ b/src/psprint.c @@ -142,22 +142,23 @@ void ps_drawPNG(xRect* r, double x1, double y1, double x2, double y2, int rot, i size_t fileSize = 0; int quality=100; const char *quality_attr; + size_t image_data_len; quality_attr = get_tok_value(r->prop_ptr, "jpeg_quality", 0); if(quality_attr[0]) quality = atoi(quality_attr); my_strdup(59, &filter, get_tok_value(r->prop_ptr, "filter", 0)); - my_strdup2(1183, &image_data64_ptr, get_tok_value(r->prop_ptr, "image_data", 0)); + image_data_len = my_strdup2(1183, &image_data64_ptr, get_tok_value(r->prop_ptr, "image_data", 0)); if (filter) { size_t filtersize = 0; char* filterdata = NULL; closure.buffer = NULL; - filterdata = (char*)base64_decode(image_data64_ptr, strlen(image_data64_ptr), &filtersize); + filterdata = (char*)base64_decode(image_data64_ptr, image_data_len, &filtersize); filter_data(filterdata, filtersize, (char**)&closure.buffer, &data_size, filter); my_free(1661, &filterdata); } else { - closure.buffer = base64_decode(image_data64_ptr, strlen(image_data64_ptr), &data_size); + closure.buffer = base64_decode(image_data64_ptr, image_data_len, &data_size); } my_free(1664, &filter); my_free(1184, &image_data64_ptr); @@ -220,7 +221,6 @@ void ps_drawPNG(xRect* r, double x1, double y1, double x2, double y2, int rot, i if(rot==2) fprintf(fd, "180 rotate\n"); if(rot==3) fprintf(fd, "270 rotate\n"); fprintf(fd, "%g %g scale\n", (X_TO_PS(x2) - X_TO_PS(x1))*0.97, (Y_TO_PS(y2) - Y_TO_PS(y1))*0.97); - fprintf(fd, "%g\n", (double)png_size_x); fprintf(fd, "%g\n", (double)png_size_y); fprintf(fd, "8\n"); diff --git a/src/save.c b/src/save.c index 19a092cb..47e818ae 100644 --- a/src/save.c +++ b/src/save.c @@ -64,7 +64,7 @@ int filter_data(const char *din, const size_t ilen, { int p1[2]; /* parent -> child, 0: read, 1: write */ int p2[2]; /* child -> parent, 0: read, 1: write */ - int ret = 0; + int ret = 0, wstatus; pid_t pid; size_t bufsize = 32768, oalloc = 0, n = 0; @@ -77,6 +77,13 @@ int filter_data(const char *din, const size_t ilen, dbg(1, "filter_data(): ilen=%ld, cmd=%s\n", ilen, cmd); pipe(p1); pipe(p2); + + dbg(1, "p1[0] = %d\n", p1[0]); + dbg(1, "p1[1] = %d\n", p1[1]); + dbg(1, "p2[0] = %d\n", p2[0]); + dbg(1, "p2[1] = %d\n", p2[1]); + + signal(SIGPIPE, SIG_IGN); /* so attempting write/read a broken pipe won't kill program */ /* * p2 @@ -85,26 +92,39 @@ int filter_data(const char *din, const size_t ilen, * ------------------- p1[1] ---------> p1[0] ------------------- * p1 */ + fflush(NULL); /* flush all stdio streams before process forking */ if( (pid = fork()) == 0) { + #if 1 char **av; int ac; + #endif /* child */ close(p1[1]); /* only read from p1 */ close(p2[0]); /* only write to p2 */ close(0); /* dup2(p1[0],0); */ /* connect read side of read pipe to stdin */ dup(p1[0]); + close(p1[0]); close(1); /* dup2(p2[1],1); */ /* connect write side of write pipe to stdout */ dup(p2[1]); + close(p2[1]); - + #if 1 av = parse_cmd_string(cmd, &ac); if(execvp(av[0], av) == -1) { + #endif + + #if 0 + if(execl("/bin/sh", "sh", "-c", cmd, (char *) NULL) == -1) { + #endif + + #if 0 + if(system(cmd) == -1) { + #endif + fprintf(stderr, "error: conversion failed\n"); - close(p1[0]); - close(p2[1]); ret = 1; } - exit(ret); + _exit(ret); } /* parent */ close(p1[0]); /*only write to p1 */ @@ -139,9 +159,13 @@ int filter_data(const char *din, const size_t ilen, fprintf(stderr, "no data read\n"); ret = 1; } - waitpid(pid, NULL, 0); /* write for child process to finish and unzombie it */ + waitpid(pid, &wstatus, 0); /* write for child process to finish and unzombie it */ close(p2[0]); signal(SIGPIPE, SIG_DFL); /* restore default SIGPIPE signal action */ + + if(WIFEXITED(wstatus)) dbg(1, "Child exited normally\n"); + dbg(1, "Child exit status=%d\n", WEXITSTATUS(wstatus)); + if(WIFSIGNALED(wstatus))dbg(1, "Child was terminated by signal\n"); return ret; } #else /* anyone wanting to write a similar function for windows Welcome! */ @@ -2391,12 +2415,13 @@ void push_undo(void) #elif HAS_PIPE==1 my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO); pipe(pd); + fflush(NULL); /* flush all stdio streams before process forking */ if((pid = fork()) ==0) { /* child process */ close(pd[1]); /* close write side of pipe */ if(!(diff_fd=freopen(diff_name,"w", stdout))) /* redirect stdout to file diff_name */ { dbg(1, "push_undo(): problems opening file %s \n",diff_name); - tcleval("exit"); + _exit(1); } /* the following 2 statements are a replacement for dup2() which is not c89 @@ -2411,7 +2436,7 @@ void push_undo(void) execlp("gzip", "gzip", "--fast", "-c", NULL); /* replace current process with comand */ /* never gets here */ fprintf(errfp, "push_undo(): problems with execlp\n"); - tcleval("exit"); + _exit(1); } close(pd[0]); /* close read side of pipe */ fd=fdopen(pd[1],"w"); @@ -2491,12 +2516,13 @@ void pop_undo(int redo, int set_modify_status) #elif HAS_PIPE==1 my_snprintf(diff_name, S(diff_name), "%s/undo%d", xctx->undo_dirname, xctx->cur_undo_ptr%MAX_UNDO); pipe(pd); + fflush(NULL); /* flush all stdio streams before process forking */ if((pid = fork())==0) { /* child process */ close(pd[0]); /* close read side of pipe */ if(!(diff_fd=freopen(diff_name,"r", stdin))) /* redirect stdin from file name */ { dbg(1, "pop_undo(): problems opening file %s \n",diff_name); - tcleval("exit"); + _exit(1); } /* connect write side of pipe to stdout */ #if HAS_DUP2 @@ -2508,7 +2534,7 @@ void pop_undo(int redo, int set_modify_status) execlp("gzip", "gzip", "-d", "-c", NULL); /* replace current process with command */ /* never gets here */ dbg(1, "pop_undo(): problems with execlp\n"); - tcleval("exit"); + _exit(1); } close(pd[1]); /* close write side of pipe */ fd=fdopen(pd[0],"r"); diff --git a/src/xschem.h b/src/xschem.h index f781d272..47e3a740 100644 --- a/src/xschem.h +++ b/src/xschem.h @@ -1077,7 +1077,6 @@ extern Xschem_ctx *xctx; extern void draw_image(int dr, xRect *r, double *x1, double *y1, double *x2, double *y2, int rot, int flip); extern int filter_data(const char *din, const size_t ilen, char **dout, size_t *olen, const char *cmd); -extern cairo_status_t png_reader(void* in_closure, unsigned char* out_data, unsigned int length); extern int embed_rawfile(const char *rawfile); extern int read_rawfile_from_attr(const char *b64s, size_t length, const char *type); extern int raw_read_from_attr(const char *type); @@ -1170,6 +1169,7 @@ extern void hash_wire(int what, int n, int incremental); extern void hash_instances(void); /* 20171203 insert instance bbox in spatial hash table */ #if HAS_CAIRO==1 +extern cairo_status_t png_reader(void* in_closure, unsigned char* out_data, unsigned int length); extern int text_bbox_nocairo(const char * str,double xscale, double yscale, short rot, short flip, int hcenter, int vcenter, double x1,double y1, double *rx1, double *ry1,