db: move return_values to use raw SQL
[smatch.git] / smatch_db.c
blob06ebb5bc907f30dc89db400d5dca52a4fa0ab0f0
1 /*
2 * smatch/smatch_db.c
4 * Copyright (C) 2010 Dan Carpenter.
6 * Licensed under the Open Software License version 1.1
8 */
10 #include <string.h>
11 #include <errno.h>
12 #include <sqlite3.h>
13 #include "smatch.h"
14 #include "smatch_slist.h"
15 #include "smatch_extra.h"
17 #define sql_insert(table, values...) \
18 do { \
19 if (option_info) { \
20 sm_prefix(); \
21 sm_printf("SQL: insert into " #table " values (" values); \
22 sm_printf(");\n"); \
23 } \
24 } while (0)
26 static sqlite3 *db;
28 struct def_callback {
29 int hook_type;
30 void (*callback)(const char *name, struct symbol *sym, char *key, char *value);
32 ALLOCATOR(def_callback, "definition db hook callbacks");
33 DECLARE_PTR_LIST(callback_list, struct def_callback);
34 static struct callback_list *callbacks;
36 struct member_info_callback {
37 int owner;
38 void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state);
40 ALLOCATOR(member_info_callback, "caller_info callbacks");
41 DECLARE_PTR_LIST(member_info_cb_list, struct member_info_callback);
42 static struct member_info_cb_list *member_callbacks;
44 struct returned_state_callback {
45 void (*callback)(int return_id, char *return_ranges, struct expression *return_expr, struct state_list *slist);
47 ALLOCATOR(returned_state_callback, "returned state callbacks");
48 DECLARE_PTR_LIST(returned_state_cb_list, struct returned_state_callback);
49 static struct returned_state_cb_list *returned_state_callbacks;
51 struct returned_member_callback {
52 int owner;
53 void (*callback)(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state);
55 ALLOCATOR(returned_member_callback, "returned member callbacks");
56 DECLARE_PTR_LIST(returned_member_cb_list, struct returned_member_callback);
57 static struct returned_member_cb_list *returned_member_callbacks;
59 struct call_implies_callback {
60 int type;
61 void (*callback)(struct expression *arg, char *value);
63 ALLOCATOR(call_implies_callback, "call_implies callbacks");
64 DECLARE_PTR_LIST(call_implies_cb_list, struct call_implies_callback);
65 static struct call_implies_cb_list *call_implies_cb_list;
67 void sql_exec(int (*callback)(void*, int, char**, char**), const char *sql)
69 char *err = NULL;
70 int rc;
72 if (option_no_db || !db)
73 return;
75 rc = sqlite3_exec(db, sql, callback, 0, &err);
76 if (rc != SQLITE_OK) {
77 fprintf(stderr, "SQL error #2: %s\n", err);
78 fprintf(stderr, "SQL: '%s'\n", sql);
82 void sql_insert_return_states(int return_id, const char *return_ranges,
83 int type, int param, const char *key, const char *value)
85 sql_insert(return_states, "'%s', '%s', %d, '%s', %d, %d, %d, '%s', '%s'",
86 get_filename(), get_function(), return_id, return_ranges,
87 fn_static(), type, param, key, value);
90 void sql_insert_function_ptr(const char *fn, const char *struct_name)
92 sql_insert(function_ptr, "'%s', '%s', '%s'", get_filename(), fn,
93 struct_name);
96 void sql_insert_return_values(const char *return_values)
98 sql_insert(return_values, "'%s', '%s', %d, '%s'", get_filename(),
99 get_function(), fn_static(), return_values);
102 void add_definition_db_callback(void (*callback)(const char *name, struct symbol *sym, char *key, char *value), int type)
104 struct def_callback *def_callback = __alloc_def_callback(0);
106 def_callback->hook_type = type;
107 def_callback->callback = callback;
108 add_ptr_list(&callbacks, def_callback);
112 * These call backs are used when the --info option is turned on to print struct
113 * member information. For example foo->bar could have a state in
114 * smatch_extra.c and also check_user.c.
116 void add_member_info_callback(int owner, void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state))
118 struct member_info_callback *member_callback = __alloc_member_info_callback(0);
120 member_callback->owner = owner;
121 member_callback->callback = callback;
122 add_ptr_list(&member_callbacks, member_callback);
125 void add_returned_state_callback(void (*fn)(int return_id, char *return_ranges, struct expression *returned_expr, struct state_list *slist))
127 struct returned_state_callback *callback = __alloc_returned_state_callback(0);
129 callback->callback = fn;
130 add_ptr_list(&returned_state_callbacks, callback);
133 void add_returned_member_callback(int owner, void (*callback)(int return_id, char *return_ranges, char *printed_name, struct smatch_state *state))
135 struct returned_member_callback *member_callback = __alloc_returned_member_callback(0);
137 member_callback->owner = owner;
138 member_callback->callback = callback;
139 add_ptr_list(&returned_member_callbacks, member_callback);
142 void add_db_fn_call_callback(int type, void (*callback)(struct expression *arg, char *value))
144 struct call_implies_callback *cb = __alloc_call_implies_callback(0);
146 cb->type = type;
147 cb->callback = callback;
148 add_ptr_list(&call_implies_cb_list, cb);
151 static struct symbol *return_type;
152 static struct range_list *return_range_list;
153 static int db_return_callback(void *unused, int argc, char **argv, char **azColName)
155 if (argc != 1)
156 return 0;
157 if (option_debug)
158 sm_msg("return type %d", type_positive_bits(return_type));
159 str_to_rl(return_type, argv[0], &return_range_list);
160 return 0;
163 struct range_list *db_return_vals(struct expression *expr)
165 struct symbol *sym;
166 static char sql_filter[1024];
168 if (expr->type != EXPR_CALL)
169 return NULL;
170 if (expr->fn->type != EXPR_SYMBOL)
171 return NULL;
172 return_type = get_type(expr);
173 if (!return_type)
174 return NULL;
175 sym = expr->fn->symbol;
176 if (!sym)
177 return NULL;
179 if (sym->ctype.modifiers & MOD_STATIC) {
180 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
181 get_filename(), sym->ident->name);
182 } else {
183 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
184 sym->ident->name);
187 return_range_list = NULL;
188 run_sql(db_return_callback, "select return from return_values where %s",
189 sql_filter);
190 return return_range_list;
193 static void match_call_hack(struct expression *expr)
195 char *name;
198 * we just want to record something in the database so that if we have
199 * two calls like: frob(4); frob(some_unkown); then on the receiving
200 * side we know that sometimes frob is called with unknown parameters.
203 name = get_fnptr_name(expr->fn);
204 if (!name)
205 return;
206 sm_msg("info: call_marker '%s' %s", name, is_static(expr->fn) ? "static" : "global");
207 free_string(name);
210 static void print_struct_members(char *fn, char *global_static, struct expression *expr, int param, struct state_list *slist,
211 void (*callback)(char *fn, char *global_static, int param, char *printed_name, struct smatch_state *state))
213 struct sm_state *sm;
214 char *name;
215 struct symbol *sym;
216 int len;
217 char printed_name[256];
218 int is_address = 0;
220 expr = strip_expr(expr);
221 if (expr->type == EXPR_PREOP && expr->op == '&') {
222 expr = strip_expr(expr->unop);
223 is_address = 1;
226 name = expr_to_var_sym(expr, &sym);
227 if (!name || !sym)
228 goto free;
230 len = strlen(name);
231 FOR_EACH_PTR(slist, sm) {
232 if (sm->sym != sym)
233 continue;
234 if (strncmp(name, sm->name, len) || sm->name[len] == '\0')
235 continue;
236 if (is_address)
237 snprintf(printed_name, sizeof(printed_name), "$$->%s", sm->name + len + 1);
238 else
239 snprintf(printed_name, sizeof(printed_name), "$$%s", sm->name + len);
240 callback(fn, global_static, param, printed_name, sm->state);
241 } END_FOR_EACH_PTR(sm);
242 free:
243 free_string(name);
246 static void match_call_info(struct expression *expr)
248 struct member_info_callback *cb;
249 struct expression *arg;
250 struct state_list *slist;
251 char *name;
252 int i;
253 char *gs;
255 name = get_fnptr_name(expr->fn);
256 if (!name)
257 return;
259 if (is_static(expr->fn))
260 gs = (char *)"static";
261 else
262 gs = (char *)"global";
264 FOR_EACH_PTR(member_callbacks, cb) {
265 slist = get_all_states(cb->owner);
266 i = 0;
267 FOR_EACH_PTR(expr->args, arg) {
268 print_struct_members(name, gs, arg, i, slist, cb->callback);
269 i++;
270 } END_FOR_EACH_PTR(arg);
271 free_slist(&slist);
272 } END_FOR_EACH_PTR(cb);
274 free_string(name);
277 static int get_param(int param, char **name, struct symbol **sym)
279 struct symbol *arg;
280 int i;
282 i = 0;
283 FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
285 * this is a temporary hack to work around a bug (I think in sparse?)
286 * 2.6.37-rc1:fs/reiserfs/journal.o
287 * If there is a function definition without parameter name found
288 * after a function implementation then it causes a crash.
289 * int foo() {}
290 * int bar(char *);
292 if (arg->ident->name < (char *)100)
293 continue;
294 if (i == param && arg->ident->name) {
295 *name = arg->ident->name;
296 *sym = arg;
297 return TRUE;
299 i++;
300 } END_FOR_EACH_PTR(arg);
302 return FALSE;
305 static struct state_list *final_states;
306 static int prev_func_id = -1;
307 static int db_callback(void *unused, int argc, char **argv, char **azColName)
309 int func_id;
310 long type;
311 long param;
312 char *name = NULL;
313 struct symbol *sym = NULL;
314 struct def_callback *def_callback;
316 if (argc != 5)
317 return 0;
319 func_id = atoi(argv[0]);
320 errno = 0;
321 type = strtol(argv[1], NULL, 10);
322 param = strtol(argv[2], NULL, 10);
323 if (errno)
324 return 0;
326 if (prev_func_id == -1)
327 prev_func_id = func_id;
328 if (func_id != prev_func_id) {
329 merge_slist(&final_states, __pop_fake_cur_slist());
330 __push_fake_cur_slist();
331 __unnullify_path();
332 prev_func_id = func_id;
335 if (type == INTERNAL)
336 return 0;
337 if (param >= 0 && !get_param(param, &name, &sym))
338 return 0;
340 FOR_EACH_PTR(callbacks, def_callback) {
341 if (def_callback->hook_type == type)
342 def_callback->callback(name, sym, argv[3], argv[4]);
343 } END_FOR_EACH_PTR(def_callback);
345 return 0;
348 static void get_direct_callers(struct symbol *sym)
350 char sql_filter[1024];
352 if (sym->ctype.modifiers & MOD_STATIC) {
353 snprintf(sql_filter, 1024,
354 "file = '%s' and function = '%s' order by function_id;",
355 get_filename(), sym->ident->name);
356 } else {
357 snprintf(sql_filter, 1024,
358 "function = '%s' and static = 0 order by function_id;",
359 sym->ident->name);
362 run_sql(db_callback, "select function_id, type, parameter, key, value from caller_info"
363 " where %s", sql_filter);
366 static char *ptr_name;
367 static int get_ptr_name(void *unused, int argc, char **argv, char **azColName)
369 if (!ptr_name)
370 ptr_name = alloc_string(argv[0]);
371 return 0;
374 static void get_function_pointer_callers(struct symbol *sym)
376 char sql_filter[1024];
378 if (sym->ctype.modifiers & MOD_STATIC) {
379 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
380 get_filename(), sym->ident->name);
381 } else {
382 snprintf(sql_filter, 1024, "function = '%s';",
383 sym->ident->name);
386 ptr_name = NULL;
387 run_sql(get_ptr_name, "select ptr from function_ptr where %s", sql_filter);
388 if (!ptr_name)
389 return;
391 run_sql(db_callback, "select function_id, type, parameter, key, value from caller_info"
392 " where function = '%s' order by function_id", ptr_name);
394 free_string(ptr_name);
397 static void match_data_from_db(struct symbol *sym)
399 struct sm_state *sm;
401 if (!sym || !sym->ident || !sym->ident->name)
402 return;
404 __push_fake_cur_slist();
405 __unnullify_path();
406 prev_func_id = -1;
408 get_direct_callers(sym);
409 get_function_pointer_callers(sym);
411 merge_slist(&final_states, __pop_fake_cur_slist());
413 FOR_EACH_PTR(final_states, sm) {
414 __set_sm(sm);
415 } END_FOR_EACH_PTR(sm);
417 free_slist(&final_states);
420 static void match_function_assign(struct expression *expr)
422 struct expression *right = expr->right;
423 struct symbol *sym;
424 char *fn_name;
425 char *ptr_name;
427 if (right->type == EXPR_PREOP && right->op == '&')
428 right = strip_expr(right->unop);
429 if (right->type != EXPR_SYMBOL)
430 return;
431 sym = get_type(right);
432 if (!sym || sym->type != SYM_FN)
433 return;
435 fn_name = expr_to_var(right);
436 ptr_name = get_fnptr_name(expr->left);
437 if (!fn_name || !ptr_name)
438 goto free;
440 sql_insert_function_ptr(fn_name, ptr_name);
442 free:
443 free_string(fn_name);
444 free_string(ptr_name);
447 static struct expression *call_implies_call_expr;
448 static int call_implies_callbacks(void *unused, int argc, char **argv, char **azColName)
450 struct call_implies_callback *cb;
451 struct expression *arg = NULL;
452 int type;
453 int param;
455 if (argc != 4)
456 return 0;
458 type = atoi(argv[1]);
459 param = atoi(argv[2]);
461 FOR_EACH_PTR(call_implies_cb_list, cb) {
462 if (cb->type != type)
463 continue;
464 if (param != -1) {
465 arg = get_argument_from_call_expr(call_implies_call_expr->args, param);
466 if (!arg)
467 continue;
469 cb->callback(arg, argv[3]);
470 } END_FOR_EACH_PTR(cb);
472 return 0;
475 static void match_call_implies(struct expression *expr)
477 struct symbol *sym;
478 static char sql_filter[1024];
480 if (expr->fn->type != EXPR_SYMBOL)
481 return;
482 sym = expr->fn->symbol;
483 if (!sym)
484 return;
486 if (sym->ctype.modifiers & MOD_STATIC) {
487 snprintf(sql_filter, 1024, "file = '%s' and function = '%s';",
488 get_filename(), sym->ident->name);
489 } else {
490 snprintf(sql_filter, 1024, "function = '%s' and static = 0;",
491 sym->ident->name);
494 call_implies_call_expr = expr;
495 run_sql(call_implies_callbacks,
496 "select function, type, parameter, value from call_implies where %s",
497 sql_filter);
498 return;
501 static void print_initializer_list(struct expression_list *expr_list,
502 struct symbol *struct_type)
504 struct expression *expr;
505 struct symbol *base_type;
506 char struct_name[256];
508 FOR_EACH_PTR(expr_list, expr) {
509 if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
510 print_initializer_list(expr->idx_expression->expr_list, struct_type);
511 continue;
513 if (expr->type != EXPR_IDENTIFIER)
514 continue;
515 if (!expr->expr_ident)
516 continue;
517 if (!expr->ident_expression || !expr->ident_expression->symbol_name)
518 continue;
519 base_type = get_type(expr->ident_expression);
520 if (!base_type || base_type->type != SYM_FN)
521 continue;
522 snprintf(struct_name, sizeof(struct_name), "(struct %s)->%s",
523 struct_type->ident->name, expr->expr_ident->name);
524 sql_insert_function_ptr(expr->ident_expression->symbol_name->name,
525 struct_name);
526 } END_FOR_EACH_PTR(expr);
529 static void global_variable(struct symbol *sym)
531 struct symbol *struct_type;
533 if (!sym->ident)
534 return;
535 if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
536 return;
537 struct_type = get_base_type(sym);
538 if (!struct_type)
539 return;
540 if (struct_type->type == SYM_ARRAY) {
541 struct_type = get_base_type(struct_type);
542 if (!struct_type)
543 return;
545 if (struct_type->type != SYM_STRUCT || !struct_type->ident)
546 return;
547 print_initializer_list(sym->initializer->expr_list, struct_type);
550 static void match_return_info(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist)
552 sql_insert_return_states(return_id, return_ranges, INTERNAL, -1, "", "");
555 static int return_id;
556 static void match_function_def(struct symbol *sym)
558 return_id = 0;
561 static void call_return_state_hooks_compare(struct expression *expr)
563 struct returned_state_callback *cb;
564 struct state_list *slist;
565 char *return_ranges;
566 int final_pass_orig = final_pass;
568 __push_fake_cur_slist();
570 final_pass = 0;
571 __split_whole_condition(expr);
572 final_pass = final_pass_orig;
574 return_ranges = alloc_sname("1");
576 return_id++;
577 slist = __get_cur_slist();
578 FOR_EACH_PTR(returned_state_callbacks, cb) {
579 cb->callback(return_id, return_ranges, expr, slist);
580 } END_FOR_EACH_PTR(cb);
582 __push_true_states();
583 __use_false_states();
585 return_ranges = alloc_sname("0");;
586 return_id++;
587 slist = __get_cur_slist();
588 FOR_EACH_PTR(returned_state_callbacks, cb) {
589 cb->callback(return_id, return_ranges, expr, slist);
590 } END_FOR_EACH_PTR(cb);
592 __merge_true_states();
593 __pop_fake_cur_slist();
596 static int call_return_state_hooks_split_possible(struct expression *expr)
598 struct returned_state_callback *cb;
599 struct state_list *slist;
600 struct range_list *rl;
601 char *return_ranges;
602 struct sm_state *sm;
603 struct sm_state *tmp;
604 int ret = 0;
605 int nr_possible, nr_states;
607 sm = get_sm_state_expr(SMATCH_EXTRA, expr);
608 if (!sm || !sm->merged)
609 return 0;
611 /* bail if it gets too complicated */
612 nr_possible = ptr_list_size((struct ptr_list *)sm->possible);
613 nr_states = ptr_list_size((struct ptr_list *)__get_cur_slist());
614 if (nr_possible >= 100)
615 return 0;
616 if (nr_states * nr_possible >= 1000)
617 return 0;
619 FOR_EACH_PTR(sm->possible, tmp) {
620 if (tmp->merged)
621 continue;
623 ret = 1;
624 __push_fake_cur_slist();
626 overwrite_states_using_pool(tmp);
628 rl = cast_rl(cur_func_return_type(), estate_rl(tmp->state));
629 return_ranges = show_rl(rl);
631 return_id++;
632 slist = __get_cur_slist();
633 FOR_EACH_PTR(returned_state_callbacks, cb) {
634 cb->callback(return_id, return_ranges, expr, slist);
635 } END_FOR_EACH_PTR(cb);
637 __pop_fake_cur_slist();
638 } END_FOR_EACH_PTR(tmp);
640 return ret;
643 static void call_return_state_hooks(struct expression *expr)
645 struct returned_state_callback *cb;
646 struct state_list *slist;
647 struct range_list *rl;
648 char *return_ranges;
649 int nr_states;
651 expr = strip_expr(expr);
653 if (!expr) {
654 return_ranges = alloc_sname("");
655 } else if (is_condition(expr)) {
656 call_return_state_hooks_compare(expr);
657 return;
658 } else if (call_return_state_hooks_split_possible(expr)) {
659 return;
660 } else if (get_implied_rl(expr, &rl)) {
661 rl = cast_rl(cur_func_return_type(), rl);
662 return_ranges = show_rl(rl);
663 } else {
664 rl = alloc_whole_rl(cur_func_return_type());
665 return_ranges = show_rl(rl);
668 return_id++;
669 slist = __get_cur_slist();
670 nr_states = ptr_list_size((struct ptr_list *)__get_cur_slist());
671 FOR_EACH_PTR(returned_state_callbacks, cb) {
672 if (nr_states < 10000)
673 cb->callback(return_id, return_ranges, expr, slist);
674 else
675 cb->callback(return_id, return_ranges, expr, NULL);
676 } END_FOR_EACH_PTR(cb);
679 static void print_returned_struct_members(int return_id, char *return_ranges, struct expression *expr, struct state_list *slist)
681 struct returned_member_callback *cb;
682 struct state_list *my_slist;
683 struct sm_state *sm;
684 struct symbol *type;
685 char *name;
686 char member_name[256];
687 int len;
689 type = get_type(expr);
690 if (!type || type->type != SYM_PTR)
691 return;
692 type = get_real_base_type(type);
693 if (!type || type->type != SYM_STRUCT)
694 return;
695 name = expr_to_var(expr);
696 if (!name)
697 return;
699 member_name[sizeof(member_name) - 1] = '\0';
700 strcpy(member_name, "$$");
702 len = strlen(name);
703 FOR_EACH_PTR(returned_member_callbacks, cb) {
704 my_slist = get_all_states_slist(cb->owner, slist);
705 FOR_EACH_PTR(my_slist, sm) {
706 if (strncmp(sm->name, name, len) != 0)
707 continue;
708 if (strncmp(sm->name + len, "->", 2) != 0)
709 continue;
710 strncpy(member_name + 2, sm->name + len, sizeof(member_name) - 2);
711 cb->callback(return_id, return_ranges, member_name, sm->state);
712 } END_FOR_EACH_PTR(sm);
713 free_slist(&my_slist);
714 } END_FOR_EACH_PTR(cb);
716 free_string(name);
719 static void match_end_func_info(struct symbol *sym)
721 if (__path_is_null())
722 return;
723 call_return_state_hooks(NULL);
726 void open_smatch_db(void)
728 #ifdef SQLITE_OPEN_READONLY
729 int rc;
731 if (option_no_db)
732 return;
734 rc = sqlite3_open_v2("smatch_db.sqlite", &db, SQLITE_OPEN_READONLY, NULL);
735 if (rc != SQLITE_OK) {
736 option_no_db = 1;
737 return;
739 return;
740 #else
741 option_no_db = 1;
742 return;
743 #endif
746 void register_definition_db_callbacks(int id)
748 add_hook(&match_function_def, FUNC_DEF_HOOK);
750 if (option_info) {
751 add_hook(&match_call_info, FUNCTION_CALL_HOOK);
752 add_hook(&match_call_hack, FUNCTION_CALL_HOOK);
753 add_hook(&match_function_assign, ASSIGNMENT_HOOK);
754 add_hook(&match_function_assign, GLOBAL_ASSIGNMENT_HOOK);
755 add_hook(&global_variable, BASE_HOOK);
756 add_hook(&global_variable, DECLARATION_HOOK);
757 add_returned_state_callback(match_return_info);
758 add_returned_state_callback(print_returned_struct_members);
759 add_hook(&call_return_state_hooks, RETURN_HOOK);
760 add_hook(&match_end_func_info, END_FUNC_HOOK);
763 if (option_no_db)
764 return;
766 add_hook(&match_data_from_db, FUNC_DEF_HOOK);
767 add_hook(&match_call_implies, FUNCTION_CALL_HOOK);
770 char *get_variable_from_key(struct expression *arg, char *key, struct symbol **sym)
772 char buf[256];
773 char *tmp;
775 if (strcmp(key, "$$") == 0)
776 return expr_to_var_sym(arg, sym);
778 if (strcmp(key, "*$$") == 0) {
779 if (arg->type == EXPR_PREOP && arg->op == '&') {
780 arg = strip_expr(arg->unop);
781 return expr_to_var_sym(arg, sym);
782 } else {
783 tmp = expr_to_var_sym(arg, sym);
784 if (!tmp)
785 return NULL;
786 snprintf(buf, sizeof(buf), "*%s", tmp);
787 free_string(tmp);
788 return alloc_string(buf);
792 if (arg->type == EXPR_PREOP && arg->op == '&') {
793 arg = strip_expr(arg->unop);
794 tmp = expr_to_var_sym(arg, sym);
795 if (!tmp)
796 return NULL;
797 snprintf(buf, sizeof(buf), "%s.%s", tmp, key + 4);
798 return alloc_string(buf);
801 tmp = expr_to_var_sym(arg, sym);
802 if (!tmp)
803 return NULL;
804 snprintf(buf, sizeof(buf), "%s%s", tmp, key + 2);
805 free_string(tmp);
806 return alloc_string(buf);