From 9243921cbb496e10ae741d42d89b44cf5da68df4 Mon Sep 17 00:00:00 2001 From: Berthold Stoeger Date: Fri, 31 May 2024 18:51:03 +0200 Subject: [PATCH] test: fix subtle bug in testplan.cpp testplan.cpp had a subtle bug since converting from a fixed-size cylinder table to a dynamic cylinder table. As noted in equipment.h, pointers to cylinders are *not* stable when the cylinder table grows. Therefore, a construct such as cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); can give dangling cyl0 and cyl1 pointers. This was not an issue with the old table code, since it had a rather liberal allocation pattern. However, when switching to std::vector<>, the problem becomes active. To "fix" this, simply access the highest index first. Of course, this should never be done in real code! Therefore, add a comment at each instance. Quickly checked all other get_or_create_cylinder() calls and they seemed to be safe. Signed-off-by: Berthold Stoeger --- tests/testplan.cpp | 50 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/tests/testplan.cpp b/tests/testplan.cpp index 856206111..d6caaba2b 100644 --- a/tests/testplan.cpp +++ b/tests/testplan.cpp @@ -52,9 +52,12 @@ void setupPlan(struct diveplan *dp) struct gasmix ean36 = {{360}, {0}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 36000; cyl0->type.workingpressure.mbar = 232000; @@ -83,9 +86,12 @@ void setupPlanVpmb45m30mTx(struct diveplan *dp) struct gasmix ean50 = {{500}, {0}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 24000; cyl0->type.workingpressure.mbar = 232000; @@ -114,9 +120,12 @@ void setupPlanVpmb60m10mTx(struct diveplan *dp) struct gasmix tx50_15 = {{500}, {150}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 24000; cyl0->type.workingpressure.mbar = 232000; @@ -163,8 +172,11 @@ void setupPlanVpmb60m30minEan50(struct diveplan *dp) struct gasmix bottomgas = {{210}, {0}}; struct gasmix ean50 = {{500}, {0}}; pressure_t po2 = {1600}; - cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); + cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 36000; cyl0->type.workingpressure.mbar = 232000; @@ -189,8 +201,11 @@ void setupPlanVpmb60m30minTx(struct diveplan *dp) struct gasmix bottomgas = {{180}, {450}}; struct gasmix ean50 = {{500}, {0}}; pressure_t po2 = {1600}; - cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); + cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 36000; cyl0->type.workingpressure.mbar = 232000; @@ -239,9 +254,12 @@ void setupPlanVpmb100m60min(struct diveplan *dp) struct gasmix ean50 = {{500}, {0}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 200000; cyl0->type.workingpressure.mbar = 232000; @@ -269,9 +287,12 @@ void setupPlanVpmb100m10min(struct diveplan *dp) struct gasmix ean50 = {{500}, {0}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 60000; cyl0->type.workingpressure.mbar = 232000; @@ -321,10 +342,13 @@ void setupPlanVpmb100mTo70m30min(struct diveplan *dp) struct gasmix ean50 = {{500}, {0}}; struct gasmix oxygen = {{1000}, {0}}; pressure_t po2 = {1600}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl3 = get_or_create_cylinder(&dive, 3); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); - cylinder_t *cyl3 = get_or_create_cylinder(&dive, 3); cyl0->gasmix = bottomgas; cyl0->type.size.mliter = 36000; cyl0->type.workingpressure.mbar = 232000; @@ -357,8 +381,11 @@ void setupPlanSeveralGases(struct diveplan *dp) struct gasmix ean36 = {{360}, {0}}; struct gasmix tx11_50 = {{110}, {500}}; - cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); + cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cyl0->gasmix = ean36; cyl0->type.size.mliter = 36000; cyl0->type.workingpressure.mbar = 232000; @@ -386,9 +413,12 @@ void setupPlanCcr(struct diveplan *dp) struct gasmix diluent = {{200}, {210}}; struct gasmix ean53 = {{530}, {0}}; struct gasmix tx19_33 = {{190}, {330}}; + // Note: we add the highest-index cylinder first, because + // pointers to cylinders are not stable when reallocating. + // For testing OK - don't do this in actual code! + cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cylinder_t *cyl0 = get_or_create_cylinder(&dive, 0); cylinder_t *cyl1 = get_or_create_cylinder(&dive, 1); - cylinder_t *cyl2 = get_or_create_cylinder(&dive, 2); cyl0->gasmix = diluent; cyl0->depth = gas_mod(diluent, po2, &dive, M_OR_FT(3, 10)); cyl0->type.size.mliter = 3000;