|
View:
New views
2 Messages
—
Rating Filter:
Alert me
|
|
|
Some bugfixes in ei_x_format in R13B02-1Hi all,
the attached patch fixes some bugs in functions that build terms from strings, called by ei_x_format and ei_x_format_wo_ver. It improves the parsing of lists, tuples, strings, atoms and digits. The file test_ei.c in attachement shows examples that ei_x_format doesn't parse correctly. In addition, I added support of hexadecimal representations of digit. This patch also fixes a bug in erl_call. When we use the option "-a 'Mod Fun Args'", the module and function are extracted and the remainings are passed to ei_x_format_wo_ver in order to build arguments before calling the function ei_rpc. The problem is that this function tries to replace all ~a,~s,~i... But in this context, it's a mistake. To avoid this behaviour, I added a new function, ei_x_parse, that transforms a string in erlang term without any replacement. Here is an example: * the following command returns an error instead of ["test"]: erl_call -sname bug_ei -s -a 'io_lib format ["~p", [test]]' I only tested this patch on linux but I hope that it works on other OS. Best regards, -- Christopher Faulet <christopher.faulet@...> --- lib/erl_interface/include/ei.h.orig 2009-10-06 21:45:09.000000000 +0200 +++ lib/erl_interface/include/ei.h 2009-10-06 21:46:22.000000000 +0200 @@ -500,6 +500,7 @@ int ei_x_format(ei_x_buff* x, const char* fmt, ...); int ei_x_format_wo_ver(ei_x_buff* x, const char *fmt, ...); +int ei_x_parse(ei_x_buff *x, const char* str); int ei_x_new(ei_x_buff* x); int ei_x_new_with_version(ei_x_buff* x); --- lib/erl_interface/src/prog/erl_call.c.orig 2009-10-06 21:46:10.000000000 +0200 +++ lib/erl_interface/src/prog/erl_call.c 2009-10-07 23:00:11.000000000 +0200 @@ -562,7 +562,7 @@ ei_x_new(&e); /* No version to ei_rpc() */ - if (ei_x_format_wo_ver(&e, args) < 0) { + if (ei_x_parse(&e, args) < 0) { /* FIXME no error message and why -1 ? */ exit(-1); } --- lib/erl_interface/src/encode/encode_atom.c.orig 2009-10-06 21:45:46.000000000 +0200 +++ lib/erl_interface/src/encode/encode_atom.c 2009-10-07 22:59:50.000000000 +0200 @@ -28,6 +28,7 @@ int ei_encode_atom_len(char *buf, int *index, const char *p, int len) { + int i; char *s = buf + *index; char *s0 = s; @@ -35,14 +36,18 @@ if (len > MAXATOMLEN) len = MAXATOMLEN; - if (!buf) s += 3; + if (!buf) s += 3 + len; else { put8(s,ERL_ATOM_EXT); put16be(s,len); - memmove(s,p,len); /* unterminated string */ + for (i = 0; i < len; ++i) { + if (p[i] != '\\' || p[i-1] == '\\') + put8(s, p[i]); + else + ++len; + } } - s += len; *index += s-s0; --- lib/erl_interface/src/encode/encode_string.c.orig 2009-10-06 21:45:58.000000000 +0200 +++ lib/erl_interface/src/encode/encode_string.c 2009-10-07 22:59:42.000000000 +0200 @@ -44,14 +44,18 @@ } else if (len <= 0xffff) { if (!buf) { - s += 3; + s += 3 + len; } else { put8(s,ERL_STRING_EXT); put16be(s,len); - memmove(s,p,len); /* unterminated string */ - } - s += len; + for (i = 0; i < len; ++i) { + if (p[i] != '\\' || p[i-1] == '\\') + put8(s, p[i]); + else + ++len; + } + } } else { if (!buf) { @@ -62,8 +66,12 @@ put32be(s,len); for (i=0; i<len; i++) { - put8(s,ERL_SMALL_INTEGER_EXT); - put8(s,p[i]); + if (p[i] != '\\' || p[i-1] == '\\') { + put8(s,ERL_SMALL_INTEGER_EXT); + put8(s,p[i]); + } + else + ++len; } put8(s,ERL_NIL_EXT); } --- lib/erl_interface/src/misc/ei_x_encode.c.orig 2009-10-06 21:45:34.000000000 +0200 +++ lib/erl_interface/src/misc/ei_x_encode.c 2009-10-07 22:59:22.000000000 +0200 @@ -93,7 +93,13 @@ int ei_x_encode_string(ei_x_buff* x, const char* s) { - return ei_x_encode_string_len(x, s, strlen(s)); + int len, i; + + for (i = 0, len = 0; s[i] != 0; ++i) { + if (s[i] != '\\' || s[i-1] == '\\') + ++len; + } + return ei_x_encode_string_len(x, s, len); } int ei_x_encode_string_len(ei_x_buff* x, const char* s, int len) @@ -197,7 +203,13 @@ int ei_x_encode_atom(ei_x_buff* x, const char* s) { - return ei_x_encode_atom_len(x, s, strlen(s)); + int len, i; + + for (i = 0, len = 0; s[i] != 0; ++i) { + if (s[i] != '\\' || s[i-1] == '\\') + ++len; + } + return ei_x_encode_atom_len(x, s, len); } int ei_x_encode_atom_len(ei_x_buff* x, const char* s, int len) --- lib/erl_interface/src/misc/ei_format.c.orig 2009-10-06 21:45:20.000000000 +0200 +++ lib/erl_interface/src/misc/ei_format.c 2009-10-07 22:58:54.000000000 +0200 @@ -71,29 +71,29 @@ int res; ei_x_buff x2; - while (isspace((int)*p)) - ++p; + for (; isspace((int)*p); ++p); + switch (*p) { case '~': res = pformat(&p, args, x); break; case '[': res = ei_x_new(&x2); - if (res >= 0) + if (res != -1) res = plist(&p, args, &x2, 0); if (res > 0) res = ei_x_encode_list_header(x, res); - if (res >= 0) + if (res != -1) res = ei_x_append(x, &x2); ei_x_free(&x2); break; case '{': res = ei_x_new(&x2); - if (res >= 0) + if (res != -1) res = ptuple(&p, args, &x2, 0); - if (res >= 0) + if (res != -1) res = ei_x_encode_tuple_header(x, res); - if (res >= 0) + if (res != -1) res = ei_x_append(x, &x2); ei_x_free(&x2); break; @@ -104,7 +104,7 @@ res = pquotedatom(&p, x); break; default: - if (isdigit((int)*p)) + if (*p == '-' || *p == '+' || isdigit((int)*p)) res = pdigit(&p, x); else if (islower((int)*p)) res = patom(&p, x); @@ -115,6 +115,7 @@ Variables */ } + *fmt = p; return res; } @@ -123,49 +124,58 @@ { const char* start = *fmt; char c; - int len; - - for (;;) { - c = *(*fmt)++; - if (isalnum((int) c) || (c == '_') || (c == '@')) - continue; - else + + for (;; ++(*fmt)) { + c = **fmt; + if (!isalnum((int)c) && c != '_' && c != '@') break; } - --(*fmt); - len = *fmt - start; - /* FIXME why truncate atom name and not fail?! */ - if (len > MAXATOMLEN) - len = MAXATOMLEN; - return ei_x_encode_atom_len(x, start, len); + return ei_x_encode_atom_len(x, start, *fmt - start); } /* Check if integer or float */ static int pdigit(const char** fmt, ei_x_buff* x) { - const char* start = *fmt; - char c; - int len, dotp=0; + const char* p = *fmt; + char* endp; + int is_double, base = 10; double d; long l; - for (;;) { - c = *(*fmt)++; - if (isdigit((int)c)) - continue; - else if (!dotp && (c == '.')) { - dotp = 1; - continue; - } else + /* skip the sign, if any */ + if (*p == '-' || *p == '+') + ++p; + + /* is double or not ? */ + for (is_double = 0;; ++p) { + if (*p == '.') { + is_double = 1; + break; + } + else if (*p == 'x' || *p == 'X') + base = 16; + else if (base == 10 && !isdigit((int)*p)) + break; + else if (base == 16 && !isxdigit((int)*p)) break; - } - --(*fmt); - len = *fmt - start; - if (dotp) { - sscanf(start, "%lf", &d); + } + + errno = 0; + + /* convert and encode a double value */ + if (is_double) { + d = strtod(*fmt, &endp); + if (errno == ERANGE) + return -1; + *fmt = endp; return ei_x_encode_double(x, d); - } else { - sscanf(start, "%ld", &l); + } + /* convert and encode a long value */ + else { + l = strtol(*fmt, &endp, base); + if (errno == ERANGE) + return -1; + *fmt = endp; return ei_x_encode_long(x, l); } } @@ -174,22 +184,24 @@ static int pstring(const char** fmt, ei_x_buff* x) { const char* start = ++(*fmt); /* skip first quote */ - char c; - int res; - - for (;;) { - c = *(*fmt)++; - if (c == '\0') + char c, p; + int res, escape; + + /* go to the end of string and count the number of escape chars */ + for (escape = 0;; ++(*fmt)) { + p = *((*fmt)-1); + c = **fmt; + if (!c) return -1; - if (c == '"') { - if (*((*fmt)-1) == '\\') - continue; - else - break; - } else - continue; + else if (c == '\\' && p != '\\') + ++escape; + else if (c == '"' && p != '\\') + break; } - res = ei_x_encode_string_len(x, start, *fmt - start - 1); + + /* encode the string */ + res = ei_x_encode_string_len(x, start, *fmt - start - escape); + ++(*fmt); /* skip last quote */ return res; } @@ -197,27 +209,29 @@ static int pquotedatom(const char** fmt, ei_x_buff* x) { const char* start = ++(*fmt); /* skip first quote */ - char c; - int res; - - for (;;) { - c = *(*fmt)++; - if (c == 0) + char c, p; + int res, escape; + + /* go to the end of atom and count the number of escape chars */ + for (escape = 0;; ++(*fmt)) { + p = *((*fmt)-1); + c = **fmt; + if (!c) return -1; - if (c == '\'') { - if (*((*fmt)-1) == '\\') - continue; - else - break; - } else - continue; - } - res = ei_x_encode_atom_len(x, start, *fmt - start - 1); + else if (c == '\'' && p != '\\') + break; + else if (c == '\\' && p != '\\') + ++escape; + } + + /* encode the string */ + res = ei_x_encode_atom_len(x, start, *fmt - start - escape); + ++(*fmt); /* skip last quote */ return res; } - /* + /* * The format letters are: * a - An atom * s - A string @@ -230,76 +244,89 @@ static int pformat(const char** fmt, union arg** args, ei_x_buff* x) { int res = 0; + + /* Return an error if there are no args (e.g. for an ei_x_parse call) */ + if (args == NULL) + return -1; + ++(*fmt); /* skip tilde */ - switch (*(*fmt)++) { + switch (**fmt) { case 'a': res = ei_x_encode_atom(x, (*args)->s); - (*args)++; + ++(*args); break; case 's': res = ei_x_encode_string(x, (*args)->s); - (*args)++; + ++(*args); break; case 'i': res = ei_x_encode_long(x, (*args)->l); - (*args)++; + ++(*args); break; case 'l': res = ei_x_encode_long(x, (*args)->l); - (*args)++; + ++(*args); break; case 'u': res = ei_x_encode_ulong(x, (*args)->u); - (*args)++; + ++(*args); break; case 'f': /* float is expanded to double (C calling conventions) */ case 'd': res = ei_x_encode_double(x, (*args)->d); - (*args)++; - break; + ++(*args); + break; default: res = -1; break; } + ++(*fmt); /* skip char after the tilde */ return res; } /* encode a tuple */ static int ptuple(const char** fmt, union arg** args, ei_x_buff* x, int size) { + const char *p = *fmt; + const char delimiter = **fmt; int res = 0; - const char* p = *fmt; - char after = *p++; - - if (after == '}') { - *fmt = p; + + if (!(*p)) + return size; + + /* ending of tuple */ + if (delimiter == '}') return size; - } - while (isspace((int)*p)) - ++p; - switch (*p++) { - case '}': - if (after == ',') + + /* skip white-space chars */ + for (++p; isspace((int)*p); ++p); + + switch (delimiter) { + case '{': /* beginning of tuple */ + if (*p == ',') res = -1; - else + else if (*p == '}') res = size; + else if ((res = eiformat(&p, args, x)) != -1) { + ++size; + for (; isspace((int)*p); ++p); + res = ptuple(&p, args, x, size); + } + p = (*p ? p+1 : p); /* skip the '}', if any */ break; - case ',': - if (after == ',' || after == '{') + case ',': /* next term of tuple */ + if (*p == ',' || *p == '}') res = -1; - else + else if ((res = eiformat(&p, args, x)) != -1) { + ++size; + for (; isspace((int)*p); ++p); res = ptuple(&p, args, x, size); + } break; - default: - --p; - res = eiformat(&p, args, x); - if (res >= 0) - res = ptuple(&p, args, x, size + 1); - break; - /* - Variables - */ + default: /* wrong delimiter */ + res = -1; } + *fmt = p; return res; } @@ -307,54 +334,63 @@ /* encode a list */ static int plist(const char** fmt, union arg** args, ei_x_buff* x, int size) { + const char *p = *fmt; + const char delimiter = **fmt; int res = 0; - const char* p = *fmt; - char after = *p++; - if (after == ']') - --p; - while (isspace((int)*p)) - ++p; - switch (*p++) { - case ']': - if (after == ',') + if (!*p) + return size; + + /* end of list */ + if (delimiter == ']') { + ei_x_encode_empty_list(x); + return size; + } + + /* skip white-space chars */ + for (++p; isspace((int)*p); ++p); + + switch (delimiter) { + case '[': /* beginning of list */ + if (*p == ',' || *p == '|') res = -1; - else { - if (after != '|') - ei_x_encode_empty_list(x); - res = size; + else if (*p == ']') + res = ei_x_encode_empty_list(x); + else if ((res = eiformat(&p, args, x)) != -1) { + ++size; + for (; isspace((int)*p); ++p); + res = plist(&p, args, x, size); } + p = (*p ? p+1 : p); /* skip the ']', if any */ break; - case '|': - if (after == '|' || after == ',') + case ',': /* next term of list */ + if (*p == ',' || *p == '|' || *p == ']') res = -1; - else + else if ((res = eiformat(&p, args, x)) != -1) { + ++size; + for (; isspace((int)*p); ++p); res = plist(&p, args, x, size); + } break; - case ',': - if (after == '|' || after == ',') - res = -1; - else + case '|': /* last term of list */ + if (*p == '[') { res = plist(&p, args, x, size); - break; - default: - --p; - res = eiformat(&p, args, x); - ++size; - if (res >= 0) { - if (after == '|') { - while (isspace((int)*p)) - ++p; + res = ((!res) ? 1 : res); /* if an empty sublist ? */ + } + else { + if ((res = eiformat(&p, args, x)) != -1) { + for (; isspace((int)*p); ++p); if (*p != ']') res = -1; - } else - res = plist(&p, args, x, size); - } + else + res = plist(&p, args, x, size); + } + } break; - /* - Variables - */ + default: /* wrong delimiter */ + res = -1; } + *fmt = p; return res; } @@ -429,17 +465,21 @@ int res; res = ei_x_encode_version(x); - if (res < 0) return res; + if (res == -1) return res; va_start(ap, fmt); res = read_args(fmt,ap,&args); saved_args = args; va_end(ap); - if (res < 0) { - return -1; + if (res == -1) { + return res; } res = eiformat(&fmt, &args, x); + /* We must be at the end of string */ + if (*fmt) { + res = -1; + } ei_free(saved_args); return res; @@ -456,11 +496,29 @@ res = read_args(fmt,ap,&args); saved_args = args; va_end(ap); - if (res < 0) { - return -1; + if (res == -1) { + return res; } + res = eiformat(&fmt, &args, x); + /* We must be at the end of string */ + if (*fmt) { + res = -1; + } ei_free(saved_args); return res; } + +int ei_x_parse(ei_x_buff *x, const char* str) +{ + int res; + + res = eiformat(&str, NULL, x); + + /* We must be at the end of string */ + if (*str) { + res = -1; + } + return res; +} /* gcc -I/usr/lib/erlang/lib/erl_interface-3.6.3/include \ -L/usr/lib/erlang/lib/erl_interface-3.6.3/lib \ test_ei.c -o test_ei_ko -lei_st */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ei.h> static unsigned int success = 0; static unsigned int failure = 0; #define TEST(expected, str, arg) \ { \ char *result = NULL; \ int res, index = 0; \ ei_x_buff x; \ \ \ ei_x_new(&x); \ res = ei_x_format(&x, str, arg); \ if (res != -1) \ { \ ei_decode_version(x.buff, &index, (int[]){0}); \ ei_s_print_term(&result, x.buff, &index); \ } \ else \ result = strdup("error"); \ ei_x_free(&x); \ \ fprintf(stdout, "%-15s", \ (!strcmp(result, expected)) ? \ (success++, "[SUCCEEDED]") : (failure++, "[FAILED]")); \ \ if (arg) \ fprintf(stdout, "- Test: %-6s,%-8s", str, arg); \ else \ fprintf(stdout, "- Test: %-15s", str); \ fprintf(stdout, "- Expected: %-15s", expected); \ fprintf(stdout, "- Result: %-15s\n", result); \ free(result); \ } int main(int argc, char *argv[]) { fprintf(stdout, "\nTUPLE:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("{a, b}", "{a,b}", NULL); TEST("{a, b}", "{a, b}", NULL); TEST("{a, b}", "{a ,b}", NULL); TEST("{a, b}", "{a , b}", NULL); TEST("error", "{a ,}b}", NULL); TEST("error", "{a ,]b}", NULL); TEST("error", "{a}b", NULL); TEST("error", "{a, {b ,}}", NULL); TEST("error", "{a, {}b}", NULL); TEST("{}", "{}", NULL); TEST("{{}}", "{{}}", NULL); TEST("{{a}}", "{{a}}", NULL); TEST("{{a}, {b}}", "{{a},{b}}", NULL); TEST("{{a, b}}", "{{a,b}}", NULL); fprintf(stdout, "\nLIST:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("error", "[,]", NULL); TEST("error", "[ ,]", NULL); TEST("error", "[, ]", NULL); TEST("error", "[ , ]", NULL); TEST("error", "[|]", NULL); TEST("error", "[ |]", NULL); TEST("error", "[| ]", NULL); TEST("error", "[ | ]", NULL); TEST("error", "[a|]", NULL); TEST("error", "[,a]", NULL); TEST("error", "[|a]", NULL); TEST("[a]", "[a|[]]", NULL); TEST("[[]]", "[[]|[]]", NULL); TEST("[[a]]", "[[a]]", NULL); TEST("[[a]]", "[[a]|[]]", NULL); TEST("[[a], b]", "[[a]|[b]]", NULL); TEST("[[a], [b]]", "[[a] ,[b]]", NULL); TEST("[a, b]", "[a ,b]", NULL); TEST("error", "[a]b", NULL); TEST("[a | b]", "[a|b]", NULL); TEST("[[a | b]]", "[[a|b]]", NULL); TEST("[[a, b]]", "[[a|[b]]]", NULL); TEST("[[a, b]]", "[[a,b]]", NULL); TEST("[a, b, c]", "[a,b|[c]]", NULL); TEST("[a, b | c]", "[a,b|c]", NULL); TEST("error", "[a|[b]|[c]]", NULL); TEST("error", "[a|b|c]", NULL); fprintf(stdout, "\nATOM:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("error", "a'any'", NULL); TEST("error", "a{any}", NULL); TEST("error", "a\\1", NULL); TEST("a1", "'a\\1'", NULL); fprintf(stdout, "\nSTRING:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("error", "\"str\"any", NULL); TEST("error", "\"str\"{any}", NULL); TEST("\"str1\"", "\"str\\1\"", NULL); fprintf(stdout, "\nDIGIT:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("-1", "-1", NULL); TEST("1", "+1", NULL); TEST("error", "1any", NULL); TEST("-1.000000", "-1.0", NULL); TEST("1.000000", "+1.0", NULL); TEST("error", "1.0any", NULL); TEST("100.000000", "1.0e2", NULL); fprintf(stdout, "\nDIGIT HEXA EXTENSION:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("error", "0x", NULL); TEST("10", "+0xa", NULL); TEST("-10.500000", "-0Xa.8", NULL); TEST("21.000000", "0xa.8p1", NULL); TEST("42.000000", "0xa.8P2", NULL); fprintf(stdout, "\nVARG:\n"); fprintf(stdout, "%s\n","----------------------------------"); TEST("error", "~aany", "toto"); TEST("atoma", "~a", "toto\\a"); TEST("'atom\\a'", "~a", "toto\\\\a"); TEST("\"stra\"", "~s", "str\\a"); TEST("\"str\\a\"", "~s", "str\\\\a"); fprintf(stdout, "\n ==> SUCCESS: %-5d FAILURE: %d\n", success, failure); return 0; } |
|
|
Re: Some bugfixes in ei_x_format in R13B02-1Hi Cristopher,
Thank your for pointing out these issues and supplying a patch for it. I will have a look at it as soon as I can. Regards, Björn-Egil Erlang/OTP christopher faulet wrote: > Hi all, > > the attached patch fixes some bugs in functions that build terms from > strings, called by ei_x_format and ei_x_format_wo_ver. It improves the > parsing of lists, tuples, strings, atoms and digits. The file test_ei.c > in attachement shows examples that ei_x_format doesn't parse correctly. > > In addition, I added support of hexadecimal representations of digit. > > This patch also fixes a bug in erl_call. When we use the option "-a 'Mod > Fun Args'", the module and function are extracted and the remainings are > passed to ei_x_format_wo_ver in order to build arguments before calling > the function ei_rpc. The problem is that this function tries to replace > all ~a,~s,~i... But in this context, it's a mistake. To avoid this > behaviour, I added a new function, ei_x_parse, that transforms a string > in erlang term without any replacement. Here is an example: > > * the following command returns an error instead of ["test"]: > erl_call -sname bug_ei -s -a 'io_lib format ["~p", [test]]' > > I only tested this patch on linux but I hope that it works on other OS. > > Best regards, > ________________________________________________________________ erlang-patches mailing list. See http://www.erlang.org/faq.html erlang-patches (at) erlang.org |
| Free embeddable forum powered by Nabble | Forum Help |