Skip to contentSkip to conversation

parse/ast: ensure saved event handlers really do get restored

PATCH New Paul Eggleton 1 participant 2 messages Aug 24, 2018

lore
Share & tools
lore
#0 lore raw

cover parse/ast: ensure saved event handlers really do get restored

The following changes since commit 49c3fd2489867c09dec6919a25b53d935a8204bb:

bitbake: Bump version 1.39.0 -> 1.39.1 (2018-08-23 09:02:49 +0100)

are available in the Git repository at:

git://git.openembedded.org/bitbake-contrib paule/fix-event-save-restore
http://cgit.openembedded.org/bitbake-contrib/log/?h=paule/fix-event-save-restore

Paul Eggleton (1):
parse/ast: ensure saved event handlers really do get restored

 lib/bb/parse/ast.py | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/1 parse/ast: ensure saved event handlers really do get restored

In finalize() we save event handlers, register the ones relevant to the recipe being finalised, trigger events, and then restore the handlers so that one recipe's custom handlers (actually implemented within a class inherited by the recipe) do not affect other recipes. However, if an exception occurs during parsing, the saved handlers were not being restored. Use a try...finally block to ensure that the handlers are always restored.

This issue became apparent since in OpenEmbedded-Core we have recently introduced a find_intercepts() handler for the bb.event.RecipePreFinalise event in image-postinst-intercepts.bbclass that images and old-style SDK recipes will end up inheriting. So far it doesn't seem that the the error has manifested itself in normal builds, but when parsing OE-Core recipes in the OE layer index it has:
core-image-rt-* image recipes were parsed which in the default configuration raise SkipRecipe. The next non-image recipe that is parsed will trigger a real exception, because the find_intercepts() handler is still registered and gets fired, but in the context of the new recipe the POSTINST_INTERCEPTS_PATHS variable is not set, and the code in find_intercepts() is written with the reasonable assumption that that isn't possible given that the class itself sets a default, and thus it fails.

---
 lib/bb/parse/ast.py | 37 +++++++++++++++++++------------------
 1 file changed, 19 insertions(+), 18 deletions(-)
lib/bb/parse/ast.py +19 -18
index 6690dc51..9d20c323 100644
@@ -343,30 +343,31 @@ def runAnonFuncs(d):
 
 def finalize(fn, d, variant = None):
     saved_handlers = bb.event.get_handlers().copy()
+    try:
+        for var in d.getVar('__BBHANDLERS', False) or []:
+            # try to add the handler
+            handlerfn = d.getVarFlag(var, "filename", False)
+            if not handlerfn:
+                bb.fatal("Undefined event handler function '%s'" % var)
+            handlerln = int(d.getVarFlag(var, "lineno", False))
+            bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
 
-    for var in d.getVar('__BBHANDLERS', False) or []:
-        # try to add the handler
-        handlerfn = d.getVarFlag(var, "filename", False)
-        if not handlerfn:
-            bb.fatal("Undefined event handler function '%s'" % var)
-        handlerln = int(d.getVarFlag(var, "lineno", False))
-        bb.event.register(var, d.getVar(var, False), (d.getVarFlag(var, "eventmask") or "").split(), handlerfn, handlerln)
-
-    bb.event.fire(bb.event.RecipePreFinalise(fn), d)
+        bb.event.fire(bb.event.RecipePreFinalise(fn), d)
 
-    bb.data.expandKeys(d)
-    runAnonFuncs(d)
+        bb.data.expandKeys(d)
+        runAnonFuncs(d)
 
-    tasklist = d.getVar('__BBTASKS', False) or []
-    bb.event.fire(bb.event.RecipeTaskPreProcess(fn, list(tasklist)), d)
-    bb.build.add_tasks(tasklist, d)
+        tasklist = d.getVar('__BBTASKS', False) or []
+        bb.event.fire(bb.event.RecipeTaskPreProcess(fn, list(tasklist)), d)
+        bb.build.add_tasks(tasklist, d)
 
-    bb.parse.siggen.finalise(fn, d, variant)
+        bb.parse.siggen.finalise(fn, d, variant)
 
-    d.setVar('BBINCLUDED', bb.parse.get_file_depends(d))
+        d.setVar('BBINCLUDED', bb.parse.get_file_depends(d))
 
-    bb.event.fire(bb.event.RecipeParsed(fn), d)
-    bb.event.set_handlers(saved_handlers)
+        bb.event.fire(bb.event.RecipeParsed(fn), d)
+    finally:
+        bb.event.set_handlers(saved_handlers)
 
 def _create_variants(datastores, names, function, onlyfinalise):
     def create_variant(name, orig_d, arg = None):
Signature · 1 line
2.17.1