From aaa67989504610bfb4cedd463e17d80c5927095a Mon Sep 17 00:00:00 2001 From: Giles Atkinson <“gatk555@gmail.com”> Date: Wed, 8 Jun 2022 10:00:24 +0100 Subject: [PATCH] Fix bugs found while investigating Bug #585 (convergence failure only on Linux). In dctran.c make it impossible for a transient simulation to run far past its end time and fix an infinite loop attempting to remove the automatically-inserted ending breakpoint. In outitf.c fix memory corruption if the simulation does over-run (change suggested by Holger Vogt). --- src/frontend/outitf.c | 14 ++++++++++---- src/spicelib/analysis/dctran.c | 30 ++++++++++++++++-------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/frontend/outitf.c b/src/frontend/outitf.c index 2381f727a..17ae50c28 100644 --- a/src/frontend/outitf.c +++ b/src/frontend/outitf.c @@ -1150,11 +1150,17 @@ vlength2delta(int len) double timerel = ft_curckt->ci_ckt->CKTtime / ft_curckt->ci_ckt->CKTfinalTime; /* return an estimate of the appropriate number of time points, if more than 20% of the anticipated total time has passed */ - if (timerel > 0.2) - return (int)(len / timerel) - len + 1; - /* If not, just double the available memory */ - else + if (timerel > 0.2) { + int proposed = (int)(len / timerel) - len + 1; + + if (proposed > 0) + return proposed; + return 16; // Probably enough as past end of simulation. + } else { + /* If not, just double the available memory */ + return len; + } } /* op */ else if (ft_curckt->ci_ckt->CKTmode & MODEDCOP) { diff --git a/src/spicelib/analysis/dctran.c b/src/spicelib/analysis/dctran.c index e8a86b044..5f63a80f9 100644 --- a/src/spicelib/analysis/dctran.c +++ b/src/spicelib/analysis/dctran.c @@ -466,9 +466,8 @@ DCtran(CKTcircuit *ckt, /* gtri - end - wbk - Update event queues/data for accepted timepoint */ #endif ckt->CKTstat->STAToldIter = ckt->CKTstat->STATnumIter; - if(check_autostop("tran") || - fabs(ckt->CKTtime - ckt->CKTfinalTime) < ckt->CKTminBreak || - AlmostEqualUlps( ckt->CKTtime, ckt->CKTfinalTime, 100 ) ) { + if (check_autostop("tran") || + ckt->CKTfinalTime - ckt->CKTtime < ckt->CKTminBreak) { #ifdef STEPDEBUG printf(" done: time is %g, final time is %g, and tol is %g\n", ckt->CKTtime, ckt->CKTfinalTime, ckt->CKTminBreak); @@ -590,21 +589,24 @@ resume: /* gtri - end - wbk - Add Breakpoint stuff */ /* gtri - begin - wbk - Modify Breakpoint stuff */ - /* Throw out any permanent breakpoint times <= current time */ - for (;;) { + /* Throw out any permanent breakpoint with time <= current time or in the + * very near future, unless it the final stop break. + */ #ifdef STEPDEBUG - printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n",ckt->CKTbreaks[0], ckt->CKTtime, ckt->CKTminBreak); + printf(" brk_pt: %g ckt_time: %g ckt_min_break: %g\n", + ckt->CKTbreaks[0], ckt->CKTtime, ckt->CKTminBreak); #endif - if(AlmostEqualUlps(ckt->CKTbreaks[0], ckt->CKTtime, 100) || - ckt->CKTbreaks[0] <= ckt->CKTtime + ckt->CKTminBreak) { + while ((ckt->CKTbreaks[0] <= ckt->CKTtime + ckt->CKTminBreak || + AlmostEqualUlps(ckt->CKTbreaks[0], ckt->CKTtime, 100)) && + ckt->CKTbreaks[0] < ckt->CKTfinalTime) { #ifdef STEPDEBUG - printf("throwing out permanent breakpoint times <= current time (brk pt: %g)\n",ckt->CKTbreaks[0]); - printf(" ckt_time: %g ckt_min_break: %g\n",ckt->CKTtime, ckt->CKTminBreak); + printf("throwing out permanent breakpoint times <= current time " + "(brk pt: %g)\n", + ckt->CKTbreaks[0]); + printf(" ckt_time: %g ckt_min_break: %g\n", + ckt->CKTtime, ckt->CKTminBreak); #endif - CKTclrBreak(ckt); - } else { - break; - } + CKTclrBreak(ckt); } /* Force the breakpoint if appropriate */ if(ckt->CKTtime + ckt->CKTdelta > ckt->CKTbreaks[0]) {