• too many nested evaluations (infinite loop?)

    From Jonathan Kelly@jonkelly@fastmail.fm to comp.lang.tcl on Sun Jun 22 10:17:31 2025
    From Newsgroup: comp.lang.tcl

    Hi,

    for starters, sorry - long post - but does the following trigger
    anything with someone that suggests what I should be looking for in my
    script?

    this is running on ubuntu, tcl version 8.6.14.

    I have a somewhat complicated script that its scanning lines from my
    webserver access logs to find bad actors and block them. The main
    process is a long if then else chain of regexp looking for known attack patterns. The script shuts itself down once a day after midnight, and is restarted by a cron job at 12.15am.

    Up to a certain point, it would run without this problem, and now it's
    coming up at least once a day.

    After running for some time it keeps throwing "too many nested
    evaluations (infinite loop?)" errors- and the places it throws the error
    from changes.

    the script is event based. This is open log file proc
    proc openAccessLog {} {
    log "[now] Opening log file"
    set ::accessLog [open "|tail -f -n 30 /var/log/apache2/access.log" r]
    fconfigure $::accessLog -blocking 0 -buffering line
    fileevent $::accessLog readable [list checkForError $::accessLog]

    #initial run after 2 minutes
    after 120000 clearExpired
    }

    it also runs a couple of event procs like this one

    proc stopper {} {
    set stop_file "/var/tmp/http.stop"
    if {[file exists $stop_file]} {
    log "[now] closing"
    file delete $stop_file
    saveSeen
    set ::stop "stop"
    } else {
    #log "." false
    }
    after 61000 stopper
    }

    and FYI,

    proc now {} {
    clock format [clock seconds] -format {%e/%m/%y %T}
    }

    a recent error is in this proc:

    too many nested evaluations (infinite loop?)
    while executing
    "ParseFormatArgs {*}$args"
    (procedure "::tcl::clock::format" line 6)
    invoked from within
    "clock format [clock seconds] -format {%e/%m/%y %T}"
    (procedure "now" line 2)
    invoked from within
    "now"
    (procedure "stopper" line 4)
    invoked from within
    "stopper"
    ("after" script)

    Also note this script is using ::http::geturl to talk to external APIs, ("https://api.abuseipdb.com/api/v2/check")
    and i THINK, this is where the problem starts. From the most recent
    crash, the first error was ...

    too many nested evaluations (infinite loop?)
    while executing
    "variable $token"
    (procedure "Finish" line 10)
    invoked from within
    "Finish $token $msg"
    (procedure "::http::Connected" line 231)
    invoked from within
    "::http::Connected $token $proto $phost $srvurl"
    (procedure "http::Connect" line 28)
    invoked from within
    "http::Connect ::http::250 https {} /api/v2/check?ipAddress=172.192.10.125&maxAgeInDays=30"

    thanks
    Jonathan.
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From saito@saitology9@gmail.com to comp.lang.tcl on Sun Jun 22 13:48:07 2025
    From Newsgroup: comp.lang.tcl

    On 6/21/2025 8:17 PM, Jonathan Kelly wrote:
    Hi,

    for starters, sorry - long post - but does the following trigger
    anything with someone that suggests what I should be looking for in my script?


    Hard to say without a more complete code snippet and lots of time. I
    suspect your "after" callbacks are interfering with each other, perhaps
    over the log file access. You already have two in the sample code, and
    there may be more, in ClearExpired, saveSeen, etc. How large does the
    log file get?

    Also note that the two errors do not seem to be related or due to the
    same root cause. The second one with http errors, do you have any
    handlers in there if the api is late in responding? You will need to add
    code to limit it (like max 5 tries or so) and then just give up on that
    call.





    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Jonathan Kelly@jonkelly@fastmail.fm to comp.lang.tcl on Mon Jun 23 05:27:37 2025
    From Newsgroup: comp.lang.tcl

    On 23/6/25 03:48, saito wrote:
    Hard to say without a more complete code snippet and lots of time. I
    suspect your "after" callbacks are interfering with each other, perhaps
    over the log file access.  You already have two in the sample code, and there may be more, in ClearExpired, saveSeen, etc. How large does the
    log file get?

    But isn't the TCL event loop single threaded?
    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From Rich@rich@example.invalid to comp.lang.tcl on Sun Jun 22 20:01:33 2025
    From Newsgroup: comp.lang.tcl

    Jonathan Kelly <jonkelly@fastmail.fm> wrote:
    On 23/6/25 03:48, saito wrote:
    Hard to say without a more complete code snippet and lots of time.
    I suspect your "after" callbacks are interfering with each other,
    perhaps over the log file access.  You already have two in the
    sample code, and there may be more, in ClearExpired, saveSeen, etc.
    How large does the log file get?

    But isn't the TCL event loop single threaded?

    It is, but you can still get into these situations (usually caused by a
    bug).

    You mentioned you were also making http calls. Is it possible that
    your log entries are arriving faster than the http calls complete (http
    is event driven behind the scenes, so calling into http to make a call
    will restart the event loop again) causing requests to 'stack up'?


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From saito@saitology9@gmail.com to comp.lang.tcl on Sun Jun 22 16:10:23 2025
    From Newsgroup: comp.lang.tcl

    On 6/22/2025 3:27 PM, Jonathan Kelly wrote:

    But isn't the TCL event loop single threaded?


    This is a good question. With event driven applications, you usually
    don't have a main line of thread that is executing constantly. In that
    case, yes, the events may not fire.

    However, with such applications, events are fired and processed
    repeatedly. So they may indeed interfere with each other.

    Here is a nice sample code. See how they intermingle:


    proc timer1 {} {puts -nonewline .; after 100 timer1}
    proc timer2 {} {puts TIMER....................; after 1000 timer2}

    after 1000 timer2; after 100 timer1


    --- Synchronet 3.21a-Linux NewsLink 1.2
  • From saito@saitology9@gmail.com to comp.lang.tcl on Sun Jun 22 16:14:28 2025
    From Newsgroup: comp.lang.tcl

    On 6/22/2025 4:10 PM, saito wrote:


    proc timer1 {} {puts -nonewline .; after 100 timer1}
    proc timer2 {} {puts TIMER....................; after 1000 timer2}

    after 1000 timer2; after 100 timer1


    Oops, clicked the send button too early. Please change what they print.
    --- Synchronet 3.21a-Linux NewsLink 1.2