libyang icon indicating copy to clipboard operation
libyang copied to clipboard

must violation error due to lyxp_set overwrite during comparison

Open Haititi opened this issue 3 years ago • 0 comments

Hi !

container test {
     list server {
         key "name";
         unique "ip port";
         leaf name {
             type string;
         }
         leaf ip {
             type inet:ip-address;
         }
         leaf port {
             type inet:port-number;
         }
     }

    leaf server_name {
        type string;
        must '. = /test/server/name';
    }
}

I get a must-violation error after adding the must statement here. This happens when the server list contains more than one child, and the child we are looking for is not the first one.

After analysis, i could find the problem between functions moveto_op_comp() and moveto_op_comp_item() . I will try to explain the problem:

struct lysp_set server_name = ...; // type is LYXP_SET_NODE_SET, contains "server_name" data node.
struct lysp_set names = ...; // type is LYXP_SET_NODE_SET, contains all the "server/name" data nodes.
moveto_op_comp(&server_name, &names, "=");
  • First call, set1 is server_name, set2 is names. On first call, both sets are of type LYXP_SET_NODE_SET, so moveto_op_comp() will loop over set1 and will call moveto_op_comp_item(set1, i, set2, op, 0, &result) (here, switch_operands is false). moveto_op_comp_item() will cast set1[0] to a string and store it in a new set tmp1 (i will call it tmp1-server_name[0] from now on). Then it calls moveto_op_comp(tmp1-server_name[0], set2, op).

  • Second call, set1 is tmp1-server_name[0], set2 is names. On second call, set1 is of type LYXP_SET_STRING, and set2 is of type LYXP_SET_NODE_SET. This time, moveto_op_comp() will loop over set2 and will call moveto_op_comp_item(set2, i, set1, op, 1, &result) (here, switch_operands is true).

  • First loop on moveto_op_comp_item(), set1 is names, set2 is tmp1-server_name[0]; Same casting as described above, tmp1-names[0] is created. Then it calls moveto_op_comp(set2, tmp1-server_name[0], op) due to switch_operands = true.

  • Third call, set1 tmp1-server_name[0], set2 is tmp1-names[0]. We have 2 strings that we compare. The result will be false. Here is the problem : the result will be stored in set1 which is tmp1-server_name[0], which mean the server name will be overwritten.

  • We return to the previous loop. On second loop on moveto_op_comp_item(), set1 is names, set2 is tmp1-server_name[0] which has been overwritten, so the following comparison will also fail.

I don't know it's if the best way to fix that, but I think moveto_op_comp() should be updated to also received a ly_bool *result in order to store the result. Then we would just call set_fill_boolean(set, result) in eval_relational_expr() and eval_equality_expr() to get back the same behavior.

thank you for your help.

Haititi avatar Aug 29 '22 14:08 Haititi