vstakhov / libucl

Universal configuration library parser
BSD 2-Clause "Simplified" License
1.62k stars 140 forks source link

Can not register variable during parse? #25

Open IngwiePhoenix opened 10 years ago

IngwiePhoenix commented 10 years ago

Hey. I wanted to implement a .var macro. In fact, I sat down and wrote a small math algorithm that'd find the key and value for me (which works!). However, when I then try to call register_variable, I get a segfault. Here is what the debugger pointed me to:

* thread #1: tid = 0x584133, 0x0000000100006b6d basic`ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, value=0x00007fff5fbfd8c0) + 77 at ucl_parser.c:1834, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #0: 0x0000000100006b6d basic`ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, value=0x00007fff5fbfd8c0) + 77 at ucl_parser.c:1834
   1831 
   1832     /* Find whether a variable already exists */
   1833     LL_FOREACH (parser->variables, cur) {
-> 1834         if (strcmp (cur->var, var) == 0) {
   1835             new = cur;
   1836             break;
   1837         }
(lldb) bt
* thread #1: tid = 0x584133, 0x0000000100006b6d basic`ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, value=0x00007fff5fbfd8c0) + 77 at ucl_parser.c:1834, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x0000000100006b6d basic`ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, value=0x00007fff5fbfd8c0) + 77 at ucl_parser.c:1834
    frame #1: 0x000000010000143d basic`printer(data=0x000000010020049c, len=8, ud=0x00007fff5fbfdaf0) + 701 at basic.c:66
    frame #2: 0x0000000100007c6e basic`ucl_state_machine(parser=0x0000000100200000) + 2654 at ucl_parser.c:1754
    frame #3: 0x0000000100006f19 basic`ucl_parser_add_chunk(parser=0x0000000100200000, data=0x0000000100200330, len=374) + 361 at ucl_parser.c:1905
    frame #4: 0x00000001000017ff basic`main(argc=1, argv=0x00007fff5fbffb48) + 911 at basic.c:131

The function from which I am calling this:

bool
printer(const unsigned char *data, size_t len, void* ud) {
    struct ucl_parser* parser = (struct ucl_parser*)ud;
    char key[len];
    char value[len];
    bool now_value=false;
    int left_length;
    for(int i=0; i<len; i++) {
        if(now_value == false && data[i] != '=') {
            // no equal sign, write to key.
            key[i]=data[i];
        } else if(now_value == false && data[i] == '=') {
            // Equal sign. I.e.: key=value
            key[i]='\0';
            now_value=true;
            left_length=i+1; // length starts at 0, but its really above null.
        } else if(now_value == false && data[i] == ' ' && data[i+1] == '=') {
            // Space and equal. I.e.: key = value
            key[i]='\0';
            left_length=i+1; // length starts at 0, but its really above null.
            i++; // Advance till after the equal sign.
            now_value=true;
        } else if(now_value == true && data[i] == ' ' && data[i-1] == '=') {
            // Space after equal, skip.
            continue;
        } else if(now_value == true) {
            // Value, write to it.
            value[( len-(i+(len-i))+(left_length-(len-i)) )]=data[i];
            printf("i:%d, di:%c, formular:%d\n", i, data[i], ( len-(i+(len-i))+(left_length-(len-i)) ));
            /*printf(
                "( %d-(%d+(%d-%d))+(%d-(%d-%d)) )\n",
                len, i, len, i, left_length, len, i
            );*/
        }
    }
    // Make it NULL terminated.
    value[len]='\0';
    // print
    //printf("VAR: %s=%s\n", key, value);
    ucl_parser_register_variable(parser, key, value);
    return true;
}

key and value are properly NULL terminated, at least they should be! I see nothing that says different with the printfs. But during variable registration, I get the segfault.

Any soltution?

--- Want to back this issue? **[Post a bounty on it!](https://www.bountysource.com/issues/2061907-can-not-register-variable-during-parse?utm_campaign=plugin&utm_content=tracker%2F483345&utm_medium=issues&utm_source=github)** We accept bounties via [Bountysource](https://www.bountysource.com/?utm_campaign=plugin&utm_content=tracker%2F483345&utm_medium=issues&utm_source=github).
vstakhov commented 10 years ago

As far as I see from your backtrace, your struct ucl_parser * pointer has different values:

ucl_state_machine(parser=0x0000000100200000)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, ...
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Obviously, it is not correct.

IngwiePhoenix commented 10 years ago

Turns out the way I had passed the parser as user-data was not right. I used &parser - but was supposed to cast it to void* instead. now it works. :)

"Yo Dawg, I heard you like C++, so I added C++ to your build system, so you have to compile before you compile.“ -StackOverflow, Matt Joiner ( http://stackoverflow.com/a/5025525/2423150 )

Am 08.05.2014 um 22:45 schrieb Vsevolod Stakhov notifications@github.com:

As far as I see from your backtrace, your struct ucl_parser * pointer has different values:

ucl_state_machine(parser=0x0000000100200000) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ucl_parser_register_variable(parser=0x00007fff5fbfdaf0, var=0x00007fff5fbfd8d0, ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Obviously, it is not correct.

— Reply to this email directly or view it on GitHub.

vstakhov commented 10 years ago

If you use C++, then you always need reinterpret_cast to void * to interact with C. This is the most ugly requirement, but it comes from C not from C++.

IngwiePhoenix commented 10 years ago

Okay, I then just cheated. XD

(void*)parser;

And got no error.

"Yo Dawg, I heard you like C++, so I added C++ to your build system, so you have to compile before you compile.“ -StackOverflow, Matt Joiner ( http://stackoverflow.com/a/5025525/2423150 )

Am 09.05.2014 um 11:30 schrieb Vsevolod Stakhov notifications@github.com:

If you use C++, then you always need reinterpret_cast to void * to interact with C. This is the most ugly requirement, but it comes from C not from C++.

— Reply to this email directly or view it on GitHub.

vstakhov commented 10 years ago

C style cast works exactly the same as C++ reinterpret_cast, however, it breaks C++ types interface and auto in particular, hence I'd not recommend to use C style casts in C++.