From: Andreas L. <av...@lo...> - 2008-12-03 08:46:19
|
"Donal K. Fellows" <don...@ma...> wrote: > 2) Is the matching algorithm this: > [lrange $pattern 0 end] eq [lrange $errcode 0 [llength $pattern]-1] > If so, that's acceptable as that's practical to implement. I'm very relieved and happy, that this globbing-a-list bungle has been replaced by something appropriate for lists. Thanks to Fredderic for not giving up so quickly and instead pushing a simpler alternative than mine. I'm (slightly) unhappy, that the "as {msgVar optsVar}" was dropped. Since these vars outlive their particular handler block (unlike with all the other languages' try-catches) a central declaration of them would have been better, and would have made the vars available to the finally block even if no specific handler matched. A few minor questions about implementation (I'm just curious): How does the byte-coded "lrange" thing deal with bad lists (i.e. something like "{fsg fds}dsfa {" ) ? The TIP specifies that no errors be thrown for non-list errorCodes or patterns. Will bytecode compilation work, if the codes for "on" or the list prefixes for "trap" are results of substitutions? like: try {...} on $::customrc {} {...} |
From: Andreas L. <av...@lo...> - 2008-12-04 16:07:54
|
"Donal K. Fellows" <don...@ma...> wrote: > I can *deny* this. :-) Apart from everything else, it is significantly > more awkward to implement since you'd have to push a special catch > context just when doing the listRangeImm. And anyway... I now feel guilty for having stepped this loose :-) Would it be feasible to sanity-check the errorCode just once (and independent of actual handlers), and in the BAD-case replace it with something else? Another ugly workaround could be to make the match check like this: Canonify the pattern (i.e. lrange 0 end) and see if it's entirely equal to the errorCode or if "$canonifiedpattern *" glob-matches the errorCode. Wow, did I just suggest to use glob on a list??? *gasp* It's ok, it's a fundamentally different thing. I believe that for two canonical lists, this type of check is equivalent to a sublist check (they differ only for bad lists). If I'm wrong here, then forget this second paragraph altogether. > The errorcode is documented to be a list on the [return] manpage and has > been for many years, though according to DGP it is a bug that this is > not currently enforced. Probably because nobody tried to do it. intercepting bad errorCodes at the respective commands is surely not safe enough. Assuming that [try] makes use of the [catch]-infra- structure, catch would be the appropriate place to spot bad errorCodes and perhaps repair them like regexp {\S+} ... I am quite sure that bad errorCodes shall never circumvent the finally block. |
From: Donal K. F. <don...@ma...> - 2008-12-03 10:43:40
|
Andreas Leitgeb wrote: > A few minor questions about implementation (I'm just curious): > How does the byte-coded "lrange" thing deal with bad lists > (i.e. something like "{fsg fds}dsfa {" ) ? The TIP specifies > that no errors be thrown for non-list errorCodes or patterns. Ooops, missed that. I'll change that when I call the vote because it's not a good decision. The list interpretation of error codes has been assumed for well over a decade, so a non-list error code is an error itself. > Will bytecode compilation work, if the codes for "on" or > the list prefixes for "trap" are results of substitutions? > like: try {...} on $::customrc {} {...} We'll spill those cases to the interpreted version. That's normal for bytecoded commands. Donal. |
From: Joe E. <jen...@fl...> - 2008-12-03 19:16:54
|
Donal K. Fellows wrote: > Andreas Leitgeb wrote: > > A few minor questions about implementation (I'm just curious): > > How does the byte-coded "lrange" thing deal with bad lists > > (i.e. something like "{fsg fds}dsfa {" ) ? The TIP specifies > > that no errors be thrown for non-list errorCodes or patterns. > > Ooops, missed that. I'll change that when I call the vote because it's > not a good decision. The list interpretation of error codes has been > assumed for well over a decade, so a non-list error code is an error itself. The current specification (r1.7, section "Handlers", "Notes & clarifications", bullet point 5): | If any errorcode happens to be not a list, a trap handler will be unable | to process it. looks right to me. If you rephrase it, please ensure that the new text continues to specify that in the following: proc throw-bad-errorinfo {} { return -code error -errorinfo "not { a list" "bad" } try { throw-bad-errorinfo } trap {whatever} {} { # (1) } on error {msg opts} { # (2) } finally { # (3) } clauses (2) and (3) are executed. --JE |
From: Joe E. <jen...@fl...> - 2008-12-03 19:31:52
|
[I wrote] > The current specification (r1.7, section "Handlers", "Notes & clarifications" > bullet point 5): [...] looks right to me. > If you rephrase it, please ensure that [...] Oh, that *was* the revised text. Please ignore previous message. --JE |
From: Twylite <tw...@cr...> - 2008-12-04 07:48:25
|
Hi, > Donal K. Fellows wrote: > >> Andreas Leitgeb wrote: >> >>> A few minor questions about implementation (I'm just curious): >>> How does the byte-coded "lrange" thing deal with bad lists >>> (i.e. something like "{fsg fds}dsfa {" ) ? The TIP specifies >>> that no errors be thrown for non-list errorCodes or patterns. >>> >> Ooops, missed that. I'll change that when I call the vote because it's >> not a good decision. The list interpretation of error codes has been >> assumed for well over a decade, so a non-list error code is an error itself. >> > > If you rephrase it, please ensure that the new text > continues to specify that in the following: > > } on error {msg opts} { > # (2) > } finally { > # (3) > } > > clauses (2) and (3) are executed. > Thanks Joe - I didn't get a chance to response to Donal yesterday. What I said (or intended to say) in the TIP was that the [try] itself must not die horrible if it encounters an errorcode that is not a list. This would imo be a bug in [try] unless error/return/throw force their errorcode argument to be a list (which they don't). And it would be a Bad Thing because then someone doing something stupid lower down the stack can blow up your anti-blowup control structure. Two ways of handling this: (1) If errorcode is not a list, then trap handlers must determine that there is no match, and let the error fall through to the next handlers and be processed or propagated as normal. I _think_ that's what Donal's rewrite is saying, but I'm not certain? DKF - can you confirm this? (2) Update the implementations of error & return so that a non-list error code raises an appropriate error at that point, rather than allowing arbitrary strings that can blow up the [try] later. Regards, Trevor |
From: Donal K. F. <don...@ma...> - 2008-12-04 10:02:14
|
Twylite wrote: > Two ways of handling this: > (1) If errorcode is not a list, then trap handlers must determine that > there is no match, and let the error fall through to the next handlers > and be processed or propagated as normal. I _think_ that's what Donal's > rewrite is saying, but I'm not certain? > DKF - can you confirm this? I can *deny* this. :-) Apart from everything else, it is significantly more awkward to implement since you'd have to push a special catch context just when doing the listRangeImm. And anyway... > (2) Update the implementations of error & return so that a non-list > error code raises an appropriate error at that point, rather than > allowing arbitrary strings that can blow up the [try] later. The errorcode is documented to be a list on the [return] manpage and has been for many years, though according to DGP it is a bug that this is not currently enforced. Probably because nobody tried to do it. Donal. |
From: Twylite <tw...@cr...> - 2008-12-04 10:16:16
|
Hi, >> I _think_ that's what Donal's rewrite is saying, but I'm not certain? >> DKF - can you confirm this? >> > I can *deny* this. :-) Apart from everything else, it is significantly > more awkward to implement since you'd have to push a special catch > context just when doing the listRangeImm. And anyway... > Right - can you please flex your admin muscles and clarify that in the TIP. It's not merely that "trap can't process it", it is that a TCL_ERROR with "-errorcode not a list" is an exception that will be raised if a trap handler is checked. Also please clarify for my understanding (and to answer Joe's question/statement) whether "finally" will run if this happens (your answer implies not: if you don't have a special catch context for listRangeImm then you can't stop the exception from propagating so that you can do the finally, depending on how the entire function is being written). Side question: if you're working in C code there is no "catch context" -- you just get a non-zero return value. I had imagined the bytecode would be similar? > The errorcode is documented to be a list on the [return] manpage and has > been for many years, though according to DGP it is a bug that this is > not currently enforced. Probably because nobody tried to do it. > I think this bug needs to be fixed then. There's a good chance that nobody has tried to do this because there is little use of errorcode. As its use increases we're going to encounter problems. Regards, Twylite |
From: Twylite <tw...@cr...> - 2008-12-04 10:54:39
|
> Side question: if you're working in C code there is no "catch context" > -- you just get a non-zero return value. I had imagined the bytecode > would be similar? > Never mind. But there need to be bigger health warnings on tclExecute.c and tclCompile.c. > I think this bug needs to be fixed then. There's a good chance that > nobody has tried to do this because there is little use of errorcode. > As its use increases we're going to encounter problems. > Of course this is easier said than done. Everything calls down to "void Tcl_SetObjErrorCode(Tcl_Interp *interp, Tcl_Obj *errorObjPtr)" which makes for one convenient place to fix the problem, but the function is published in the stubs table and returns (void) ... which makes it tricky to fix. One could fix TclProcessReturn() to check valuePtr just before calling Tcl_SetObjErrorCode (context below) ... if (valuePtr != NULL) { Tcl_SetObjErrorCode(interp, valuePtr); } ... which would at least make this safe at a script level, so that only C code calling Tcl_SetObjErrorCode directly can mess things up. Regards, Twylite |
From: Donal K. F. <don...@ma...> - 2008-12-04 12:26:25
|
Twylite wrote: >> Side question: if you're working in C code there is no "catch context" >> -- you just get a non-zero return value. I had imagined the bytecode >> would be similar? >> > Never mind. But there need to be bigger health warnings on > tclExecute.c and tclCompile.c. I don't think they make letters that large except in books by Douglas Adams... > Of course this is easier said than done. Everything calls down to "void > Tcl_SetObjErrorCode(Tcl_Interp *interp, Tcl_Obj *errorObjPtr)" which > makes for one convenient place to fix the problem, but the function is > published in the stubs table and returns (void) ... which makes it > tricky to fix. While I know how to fix such things through stub-table rearrangement (and I've done such in parts of Tk) they're pretty ugly to do. What we *can* do is make sure that Tcl code doesn't mess this up through [error], [return] (and [throw]). I don't think anyone is actually generating bad error codes anyway; at the C level, the convenient API produces proper lists. > One could fix TclProcessReturn() to check valuePtr just before calling > Tcl_SetObjErrorCode (context below) ... [...] > ... which would at least make this safe at a script level, so that only > C code calling Tcl_SetObjErrorCode directly can mess things up. Things are fairly messy in this area. Donal. |
From: Donal K. F. <don...@ma...> - 2008-12-04 14:37:35
|
Twylite wrote: > Right - can you please flex your admin muscles and clarify that in the > TIP. It's not merely that "trap can't process it", it is that a > TCL_ERROR with "-errorcode not a list" is an exception that will be > raised if a trap handler is checked. I'll think about how to implement the correction. > Also please clarify for my understanding (and to answer Joe's > question/statement) whether "finally" will run if this happens (your > answer implies not: if you don't have a special catch context for > listRangeImm then you can't stop the exception from propagating so that > you can do the finally, depending on how the entire function is being > written). We'll make sure that 'finally' always runs. It's not a handler, and the 'finally' semantics are important. More of a concern is what happens when you hit a resource limit or the interpreter is unwound or deleted but there the issue is that the interpreter is just unable to execute commands; a finally clause could run, but would have to do nothing that involves commands... ;-) > Side question: if you're working in C code there is no "catch context" > -- you just get a non-zero return value. I had imagined the bytecode > would be similar? The bytecode engine is rather more complex than that. IIRC, each instruction is in the context of an error handler; the default one just makes the current "script evaluation" exit, but [catch] (and [try]) puts a different one in place around its protected code. (Or maybe there's no handler by default, but that's dealt with the same as if there was a default handler that does what I described. Whatever.) What that means is that if you have a fairly complex structural piece of Tcl inside a [catch], Tcl can handle any errors inside it very quickly. Or it could except for generation of errorinfo traces. The break and continue exceptions are handled through a very similar (but slightly more optimized) mechanism. Donal. |