asn1c icon indicating copy to clipboard operation
asn1c copied to clipboard

Enumerated constraints appear broken

Open bknotwell opened this issue 2 years ago • 7 comments

The NativeEnumerated_constraint is defined to asm_generic_no_constraint. Not sure if this is intentional or not but I've attached a minimal example below to illustrate the issue:

FruitModule DEFINITIONS ::=

BEGIN
FruitId ::= ENUMERATED { apple(1), orange(2) }

Fruit ::= SEQUENCE {
   fruit FruitId
}
END
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <Fruit.h>

int main(void) {
    Fruit_t fruit;
    Fruit_t fruitbad;
    int ret;
    char errbuf[128];
    size_t errlen = sizeof(errbuf);

    memset(&fruit, 0, sizeof(Fruit_t));
    memset(&fruitbad, 0, sizeof(Fruit_t));

    fruit.fruit = FruitId_orange;
    fruitbad.fruit = 42;

    ret = asn_check_constraints(&asn_DEF_Fruit, &fruit,
                                errbuf, &errlen);
    if(ret) {
        fprintf(stderr, "Fruit validation failed(unexpected): %s\n", errbuf);
    }
    ret = asn_check_constraints(&asn_DEF_Fruit, &fruitbad,
                                errbuf, &errlen);
    if(ret) {
        fprintf(stderr, "Fruitbad validation failed(expected): %s\n", errbuf);
    }
    return 0; 
}

bknotwell avatar Feb 11 '23 19:02 bknotwell

The second fprintf should execute but it doesn't as the second constraints check returns zero.

bknotwell avatar Feb 11 '23 19:02 bknotwell

While the following program does what I want, I don't know if it's architecturally correct. If it's not, it's a workaround for a bug. Otherwise, I'd recommend updating the user's guide to show three things:

  • how to write custom validators for enumerated values.
  • that you need to count N fields forward to set the correct general_constraints function pointer. NOTE: a less ugly way to do this would add something like #define fruitId 0 to the Fruit.h file so developers would put the field name in the elements array instead of the raw integer.
  • the function protocol for the general_constraints call.
#include <string.h>
#include <sys/types.h>
#include <Fruit.h>

static int validate_fruit(const asn_TYPE_descriptor_t *td, const void *sptr,
                          asn_app_constraint_failed_f *ctfailcb, void* app_key) {
    long value;
    if(! sptr) {
        ASN__CTFAIL(app_key, td, sptr,
                    "%s: value not given (%s:%d)",
                    td->name, __FILE__, __LINE__);
        return -1;
    }

    value = *(const long*)sptr;

    if(value == FruitId_orange || value == FruitId_apple)
        return 0;

    ASN__CTFAIL(app_key, td, sptr,
                "%s: constraint failed (%s:%d)",
                td->name, __FILE__, __LINE__);
    return -1;
}

int main(void) {
    Fruit_t fruit;
    Fruit_t fruitbad;
    int ret;
    char errbuf[128];
    size_t errlen = sizeof(errbuf);

    memset(&fruit, 0, sizeof(Fruit_t));
    memset(&fruitbad, 0, sizeof(Fruit_t));

    fruit.fruit = FruitId_orange;;
    fruitbad.fruit = 42;

    asn_DEF_Fruit.elements[0].encoding_constraints.general_constraints = validate_fruit;

    ret = asn_check_constraints(&asn_DEF_Fruit, &fruit,
                                errbuf, &errlen);
    if(ret)
        fprintf(stderr, "Fruit validation failed(unexpected): %s\n", errbuf);

    ret = asn_check_constraints(&asn_DEF_Fruit, &fruitbad,
                                errbuf, &errlen);
    if(ret)
        fprintf(stderr, "Fruitbad validation failed(expected): %s\n", errbuf);

    return 0; 
}

bknotwell avatar Feb 12 '23 01:02 bknotwell

Thinking about it a bit, there is an easy way to generate validators for enums that requires zero cleverness in the code generator--build a switch statement and avoid the difficulty of assembling a correct set of if statements.:

static int validate_fruit(const asn_TYPE_descriptor_t *td, const void *sptr,
                          asn_app_constraint_failed_f *ctfailcb, void* app_key) {
    e_FruitId value;
    if(! sptr) {
        ASN__CTFAIL(app_key, td, sptr,
                    "%s: value not given (%s:%d)",
                    td->name, __FILE__, __LINE__);
        return -1;
    }

    value = *(e_FruitId*)sptr;

    switch(value) {
    case FruitId_orange:
    case FruitId_apple:
        return 0;
    }

    ASN__CTFAIL(app_key, td, sptr,
                "%s: constraint failed (%s:%d)",
                td->name, __FILE__, __LINE__);
    return -1;
}

bknotwell avatar Feb 12 '23 02:02 bknotwell

@bknotwell thanks for reporting. Would you consider submitting a PR?

mouse07410 avatar Feb 27 '23 04:02 mouse07410

I'll take a look at the code. I suspect it'll be doable.

mtbakerguy avatar Mar 09 '23 20:03 mtbakerguy

https://github.com/mouse07410/asn1c/pull/121

bknotwell avatar Mar 10 '23 05:03 bknotwell

To speed up merging of #121, could you please fix the CI, so it passes the tests?

mouse07410 avatar Mar 14 '23 00:03 mouse07410