OpenVAS Scanner  7.0.1~git
lint.c
Go to the documentation of this file.
1 /* Copyright (C) 2004 Michel Arboi
2  *
3  * SPDX-License-Identifier: GPL-2.0-only
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 #include "exec.h"
19 #include "nasl.h"
20 #include "nasl_debug.h"
21 #include "nasl_func.h"
22 #include "nasl_global_ctxt.h"
23 #include "nasl_init.h"
24 #include "nasl_lex_ctxt.h"
25 #include "nasl_tree.h"
26 #include "nasl_var.h"
27 
28 #include <string.h>
29 
30 #undef G_LOG_DOMAIN
31 
34 #define G_LOG_DOMAIN "lib nasl"
35 
39 typedef struct st_func_info
40 {
41  gchar *func_name;
42  gchar *caller_func;
43  gchar *caller_file;
44 } func_info;
45 
46 char *nasl_name;
47 
54 void
56 {
57  g_free (data->func_name);
58  g_free (data->caller_func);
59  g_free (data->caller_file);
60  memset (data, '\0', sizeof (func_info));
61 }
62 
69 void
70 add_predef_varname (GSList **defined_var)
71 {
72  int i;
73  gchar *keywords[] = {"ACT_UNKNOWN", "description", "NULL", "SCRIPT_NAME",
74  "COMMAND_LINE", "_FCT_ANON_ARGS", NULL};
75 
76  for (i = 0; keywords[i] != NULL; i++)
77  *defined_var = g_slist_prepend (*defined_var, keywords[i]);
78  add_nasl_library (defined_var);
79 }
80 
89 gint
90 list_cmp1 (gconstpointer lelem, gconstpointer data)
91 {
92  if (data)
93  {
94  gchar *lala = g_strdup (((func_info *) lelem)->func_name);
95  return g_strcmp0 (lala, data);
96  }
97  return -1;
98 }
99 
106 gint
107 reverse_search (GSList **def_func_tree, GSList *finfo)
108 {
109  func_info *fdata = finfo->data;
110  GSList *finfo_aux;
111 
112  // The file name is the original file to be tested. It is not an include.
113  if (!g_strcmp0 (fdata->caller_file, nasl_name)
114  && !g_str_has_suffix (nasl_name, ".inc"))
115  return 1;
116 
117  // The function is it self.
118  if (!g_strcmp0 (fdata->func_name, fdata->caller_func))
119  return 0;
120 
121  // I go up in the tree of called and defined functions.
122  if ((finfo_aux = g_slist_find_custom (*def_func_tree, fdata->caller_func,
123  (GCompareFunc) list_cmp1))
124  != NULL)
125  if (reverse_search (def_func_tree, finfo_aux))
126  return 1;
127 
128  return 0;
129 }
130 
139 gint
140 list_cmp (gconstpointer lelem, gconstpointer data)
141 {
142  if (data)
143  return g_strcmp0 (lelem, data);
144 
145  return -1;
146 }
147 
158 void
159 check_called_files (gpointer key, gpointer value, GSList **unusedfiles)
160 {
161  if (key != NULL)
162  if (!g_strcmp0 (value, "NO"))
163  *unusedfiles = g_slist_prepend (*unusedfiles, key);
164 }
165 
173 void
174 print_uncall_files (gpointer filename, gpointer lexic)
175 {
176  if (filename != NULL)
177  {
178  nasl_perror (lexic, "The included file '%s' is never used.",
179  (char *) filename);
180  lexic = NULL;
181  }
182 }
183 
189 tree_cell *
190 nasl_lint_def (lex_ctxt *lexic, tree_cell *st, int lint_mode,
191  GHashTable **include_files, GHashTable **func_fnames_tab,
192  gchar *err_fname, GSList **called_funcs, GSList **def_func_tree)
193 {
194  int i;
195  tree_cell *ret = FAKE_CELL;
196  char *incname = NULL;
197  gchar *tmp_filename = NULL;
198  nasl_func *pf;
199  static gchar *current_fun_def = NULL;
200 
201  if (st->type == NODE_FUN_CALL)
202  {
203  pf = get_func_ref_by_name (lexic, st->x.str_val);
204  if (pf == NULL)
205  {
206  g_hash_table_insert (*func_fnames_tab, g_strdup (st->x.str_val),
207  g_strdup (err_fname));
208  }
209 
210  /* Save in a list the name of the called function, the file where it
211  is called from, and the function where it is called from. This will
212  help to know if a called function is really needed, or it was just
213  called by another defined function which is never called. */
214  func_info *finfo = g_malloc0 (sizeof (func_info));
215  finfo->func_name = g_strdup (st->x.str_val);
216  finfo->caller_file = g_strdup (err_fname ? err_fname : nasl_name);
217  finfo->caller_func = g_strdup (current_fun_def);
218  *def_func_tree = g_slist_prepend (*def_func_tree, finfo);
219  }
220 
221  switch (st->type)
222  {
223  case NODE_FUN_DEF:
224  /* with lint_mode = 0 check if this function was declared twice*/
225  if (lint_mode == 0)
226  {
227  if (decl_nasl_func (lexic, st, lint_mode) == NULL)
228  ret = NULL;
229  return ret;
230  }
231  /* Check if it was already added */
232  if (!g_slist_find_custom (*called_funcs, st->x.str_val,
233  (GCompareFunc) list_cmp))
234  {
235  return FAKE_CELL;
236  }
237 
238  /* x.str_val = function name, [0] = argdecl, [1] = block */
239  decl_nasl_func (lexic, st, lint_mode);
240  current_fun_def = g_strdup (st->x.str_val);
241  incname = g_strdup (nasl_get_filename (st->x.str_val));
242  g_hash_table_replace (*include_files, incname, g_strdup ("NO"));
243  tmp_filename = g_strdup (nasl_get_filename (NULL));
244  err_fname = g_strdup (incname);
245  /* fallthrough */
246 
247  default:
248  for (i = 0; i < 4; i++)
249  if (st->link[i] != NULL && st->link[i] != FAKE_CELL)
250  if ((ret = nasl_lint_def (lexic, st->link[i], lint_mode,
251  include_files, func_fnames_tab, err_fname,
252  called_funcs, def_func_tree))
253  == NULL)
254  return NULL;
255 
256  if (st->type == NODE_FUN_DEF)
257  {
258  if (tmp_filename)
259  nasl_set_filename (tmp_filename);
260  g_free (tmp_filename);
261  }
262  return ret;
263  }
264 }
265 
269 tree_cell *
270 nasl_lint_call (lex_ctxt *lexic, tree_cell *st, GHashTable **include_files,
271  GHashTable **func_fnames_tab, gchar *err_fname,
272  GSList **called_funcs, GSList **def_func_tree)
273 {
274  int i;
275  tree_cell *ret = FAKE_CELL;
276  nasl_func *pf;
277  char *incname = NULL;
278  static int defined_flag = 0;
279 
283  if (st->type == NODE_FUN_DEF)
284  {
285  if (!g_slist_find_custom (*called_funcs, st->x.str_val,
286  (GCompareFunc) list_cmp))
287  {
288  return FAKE_CELL;
289  }
290  }
291 
292  switch (st->type)
293  {
294  case CONST_DATA:
295  case CONST_STR:
296  if (st->x.str_val != NULL && defined_flag == 1)
297  {
298  decl_nasl_func (lexic, st, 1);
299  defined_flag = 0;
300  }
301  return FAKE_CELL;
302 
303  case NODE_FUN_CALL:
304  pf = get_func_ref_by_name (lexic, st->x.str_val);
305  if (pf == NULL)
306  {
307  incname = g_hash_table_lookup (*func_fnames_tab, st->x.str_val);
308  incname ? nasl_set_filename (incname) : "unknown";
309  lexic->line_nb = st->line_nb;
310 
311  GSList *called_f_aux;
312  called_f_aux = g_slist_find_custom (*def_func_tree, st->x.str_val,
313  (GCompareFunc) list_cmp1);
314  if (called_f_aux != NULL)
315  if (reverse_search (def_func_tree, called_f_aux))
316  {
317  nasl_perror (lexic, "Undefined function '%s'\n", st->x.str_val);
318  return NULL;
319  }
320  }
321  if (*include_files && st->x.str_val)
322  {
323  if (g_hash_table_lookup (*include_files,
324  nasl_get_filename (st->x.str_val)))
325  {
326  incname = g_strdup (nasl_get_filename (st->x.str_val));
327  g_hash_table_replace (*include_files, incname, g_strdup ("YES"));
328  }
329  }
330  if (g_strcmp0 (st->x.str_val, "defined_func") == 0)
331  defined_flag = 1;
332  /* fallthrough */
333 
334  default:
335  for (i = 0; i < 4; i++)
336  if (st->link[i] != NULL && st->link[i] != FAKE_CELL)
337  if ((ret = nasl_lint_call (lexic, st->link[i], include_files,
338  func_fnames_tab, err_fname, called_funcs,
339  def_func_tree))
340  == NULL)
341  return NULL;
342  return ret;
343  }
344 }
345 
351 tree_cell *
352 nasl_lint_defvar (lex_ctxt *lexic, tree_cell *st, GHashTable **include_files,
353  GHashTable **func_fnames_tab, gchar *err_fname,
354  GSList **defined_var, GSList **called_funcs)
355 {
356  int i;
357  tree_cell *ret = FAKE_CELL;
358  static int defined_fn_mode = 0;
359  static int defined_var_mode = 0;
360  static int def_glob_var = 0;
361  static GSList *local_var_list = NULL;
362 
366  if (st->type == NODE_FUN_DEF)
367  {
368  if (!g_slist_find_custom (*called_funcs, st->x.str_val,
369  (GCompareFunc) list_cmp))
370  {
371  return FAKE_CELL;
372  }
373  }
374 
375  if ((defined_fn_mode == 1 || def_glob_var) && st->type != NODE_DECL)
376  {
377  defined_fn_mode = 0;
378  def_glob_var = 0;
379  }
380 
381  /* A variable will be defined, then set the mode variable. */
382  if ((st->type == NODE_AFF || st->type == EXPR_NOT || st->type == EXPR_INCR
383  || st->type == NODE_PLUS_EQ)
384  && defined_var_mode == 0)
385  defined_var_mode = 1;
386  else if ((st->type == NODE_FUN_DEF || st->type == NODE_LOCAL)
387  && defined_fn_mode == 0)
388  defined_fn_mode = 1;
389 
390  else if (st->type == NODE_GLOBAL)
391  def_glob_var = 1;
392 
393  /* The variable is being defined. Therefore is save into the
394  * global list only if was not previously added in local list.
395  */
396  else if ((st->type == NODE_VAR || st->type == NODE_ARRAY_EL)
397  && (defined_var_mode == 1 || defined_fn_mode == 1))
398  {
399  if (st->x.str_val != NULL)
400  {
401  if (!g_slist_find_custom (local_var_list, st->x.str_val,
402  (GCompareFunc) list_cmp))
403  *defined_var = g_slist_prepend (*defined_var, st->x.str_val);
404  defined_var_mode = 0;
405  }
406  }
410  else if (st->type == NODE_DECL && st->x.str_val != NULL)
411  {
412  if (defined_fn_mode == 1)
413  local_var_list = g_slist_prepend (local_var_list, st->x.str_val);
414  if (def_glob_var == 1)
415  *defined_var = g_slist_prepend (*defined_var, st->x.str_val);
416  }
417  /* Special case foreach. */
418  else if (st->type == NODE_FOREACH)
419  {
420  if (st->x.str_val != NULL)
421  *defined_var = g_slist_prepend (*defined_var, st->x.str_val);
422  }
423  // The variable is used. It checks if the variable was defined
424  else if (st->type == NODE_VAR && defined_var_mode == 0)
425  {
426  if (!g_slist_find_custom (*defined_var, st->x.str_val,
427  (GCompareFunc) list_cmp)
428  && !g_slist_find_custom (local_var_list, st->x.str_val,
429  (GCompareFunc) list_cmp))
430  {
431  lexic->line_nb = st->line_nb;
432  nasl_perror (lexic, "The variable %s was not declared",
433  st->x.str_val);
434  return NULL;
435  }
436  }
437 
438  for (i = 0; i < 4; i++)
439  if (st->link[i] != NULL && st->link[i] != FAKE_CELL)
440  if ((ret = nasl_lint_defvar (lexic, st->link[i], include_files,
441  func_fnames_tab, err_fname, defined_var,
442  called_funcs))
443  == NULL)
444  return NULL;
445 
449  if (st->type == NODE_FUN_DEF)
450  {
451  g_slist_free (local_var_list);
452  local_var_list = NULL;
453  }
454 
455  return ret;
456 }
460 tree_cell *
461 make_call_func_list (lex_ctxt *lexic, tree_cell *st, GSList **called_funcs)
462 {
463  int i;
464  tree_cell *ret = FAKE_CELL;
465  nasl_func *pf = NULL;
466 
467  switch (st->type)
468  {
469  case NODE_FUN_CALL:
470  pf = get_func_ref_by_name (lexic, st->x.str_val);
471  if (st->x.str_val && !pf)
472  {
473  *called_funcs =
474  g_slist_prepend (*called_funcs, g_strdup (st->x.str_val));
475  }
476  /* fallthrough */
477 
478  default:
479  for (i = 0; i < 4; i++)
480  if (st->link[i] != NULL && st->link[i] != FAKE_CELL)
481  if ((ret = make_call_func_list (lexic, st->link[i], called_funcs))
482  == NULL)
483  return NULL;
484  return ret;
485  }
486 }
487 
496 tree_cell *
498 {
499  lex_ctxt *lexic_aux;
500  tree_cell *ret = FAKE_CELL;
501  int lint_mode = 1;
502  GHashTable *include_files = NULL;
503  GHashTable *func_fnames_tab = NULL;
504  GSList *unusedfiles = NULL;
505  GSList *called_funcs = NULL;
506  GSList *def_func_tree = NULL;
507  gchar *err_fname = NULL;
508 
509  nasl_name = g_strdup (nasl_get_filename (st->x.str_val));
510  include_files =
511  g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
512  func_fnames_tab =
513  g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
514 
515  lexic_aux = init_empty_lex_ctxt ();
516  lexic_aux->script_infos = lexic->script_infos;
517  lexic_aux->oid = lexic->oid;
518 
519  /* Make a list of all called functions */
520  make_call_func_list (lexic_aux, st, &called_funcs);
521 
522  /* Loads all defined functions. */
523  if ((ret = nasl_lint_def (lexic_aux, st, lint_mode, &include_files,
524  &func_fnames_tab, err_fname, &called_funcs,
525  &def_func_tree))
526  == NULL)
527  goto fail;
528  /* Check if a called function was defined. */
529  if ((ret = nasl_lint_call (lexic_aux, st, &include_files, &func_fnames_tab,
530  err_fname, &called_funcs, &def_func_tree))
531  == NULL)
532  goto fail;
533 
534  /* Check if the included files are used or not. */
535  g_hash_table_foreach (include_files, (GHFunc) check_called_files,
536  &unusedfiles);
537  if (unusedfiles != NULL)
538  g_slist_foreach (unusedfiles, (GFunc) print_uncall_files, lexic_aux);
539  if ((g_slist_length (unusedfiles)) > 0)
540  {
541  ret = NULL;
542  goto fail;
543  }
544 
545  /* Now check that each function was loaded just once. */
546  lint_mode = 0;
547  if ((ret =
548  nasl_lint_def (lexic, st, lint_mode, &include_files, &func_fnames_tab,
549  err_fname, &called_funcs, &def_func_tree))
550  == NULL)
551  goto fail;
552 
553  /* Check if a variable was declared. */
554  GSList *defined_var = NULL;
555  add_predef_varname (&defined_var);
556  ret = nasl_lint_defvar (lexic_aux, st, &include_files, &func_fnames_tab,
557  err_fname, &defined_var, &called_funcs);
558  g_slist_free (defined_var);
559  defined_var = NULL;
560 
561 fail:
562  g_slist_free (called_funcs);
563  called_funcs = NULL;
564  g_slist_free_full (def_func_tree, (GDestroyNotify) free_list_func);
565  def_func_tree = NULL;
566  g_hash_table_destroy (include_files);
567  include_files = NULL;
568  g_hash_table_destroy (func_fnames_tab);
569  func_fnames_tab = NULL;
570  g_free (err_fname);
571  g_slist_free (unusedfiles);
572  unusedfiles = NULL;
573  free_lex_ctxt (lexic_aux);
574 
575  return ret;
576 }
#define FAKE_CELL
Definition: nasl_tree.h:119
struct TC * link[4]
Definition: nasl_tree.h:116
const char * nasl_get_filename(const char *function)
Definition: nasl_debug.c:69
char * nasl_name
Definition: lint.c:46
void free_list_func(func_info *data)
Free a func_info structure.
Definition: lint.c:55
short type
Definition: nasl_tree.h:106
gchar * caller_func
Definition: lint.c:42
struct st_func_info func_info
Define struct to store information about a called function.
char * str_val
Definition: nasl_tree.h:112
short line_nb
Definition: nasl_tree.h:107
void nasl_set_filename(const char *filename)
Definition: nasl_debug.c:97
gint list_cmp1(gconstpointer lelem, gconstpointer data)
This function is called by g_slist_find_custom.
Definition: lint.c:90
struct script_infos * script_infos
Definition: nasl_lex_ctxt.h:41
gchar * caller_file
Definition: lint.c:43
void free_lex_ctxt(lex_ctxt *c)
Definition: nasl_lex_ctxt.c:55
Define struct to store information about a called function.
Definition: lint.c:39
tree_cell * nasl_lint_call(lex_ctxt *lexic, tree_cell *st, GHashTable **include_files, GHashTable **func_fnames_tab, gchar *err_fname, GSList **called_funcs, GSList **def_func_tree)
Check if a called function was defined.
Definition: lint.c:270
lex_ctxt * init_empty_lex_ctxt()
Definition: nasl_lex_ctxt.c:32
Definition: nasl_tree.h:104
union TC::@2 x
void add_nasl_library(GSList **list)
Add "built-in" variables to a list.
Definition: nasl_init.c:514
void nasl_perror(lex_ctxt *lexic, char *msg,...)
Definition: nasl_debug.c:120
tree_cell * nasl_lint_defvar(lex_ctxt *lexic, tree_cell *st, GHashTable **include_files, GHashTable **func_fnames_tab, gchar *err_fname, GSList **defined_var, GSList **called_funcs)
Consider all cases in which a variable is set, and add it to a list. If a variable is read...
Definition: lint.c:352
void check_called_files(gpointer key, gpointer value, GSList **unusedfiles)
This function is called by g_hash_table_foreach to check if an include file was used or not...
Definition: lint.c:159
tree_cell * nasl_lint_def(lex_ctxt *lexic, tree_cell *st, int lint_mode, GHashTable **include_files, GHashTable **func_fnames_tab, gchar *err_fname, GSList **called_funcs, GSList **def_func_tree)
Loads all defined functions. Also, It constructs a tree of called functions to help recognize a not d...
Definition: lint.c:190
tree_cell * nasl_lint(lex_ctxt *lexic, tree_cell *st)
Search for errors in a nasl script.
Definition: lint.c:497
gint list_cmp(gconstpointer lelem, gconstpointer data)
This function is called by g_slist_find_custom.
Definition: lint.c:140
gint reverse_search(GSList **def_func_tree, GSList *finfo)
Check if an undefined called function is needed or not. This is the case in which the function is cal...
Definition: lint.c:107
gchar * func_name
Definition: lint.c:41
void print_uncall_files(gpointer filename, gpointer lexic)
It shows a msg for unused included files.
Definition: lint.c:174
const char * oid
Definition: nasl_lex_ctxt.h:42
tree_cell * make_call_func_list(lex_ctxt *lexic, tree_cell *st, GSList **called_funcs)
Make a list of all called functions.
Definition: lint.c:461
tree_cell * decl_nasl_func(lex_ctxt *lexic, tree_cell *decl_node, int lint_mode)
Definition: nasl_func.c:78
nasl_func * get_func_ref_by_name(lex_ctxt *ctxt, const char *name)
Definition: nasl_func.c:94
void add_predef_varname(GSList **defined_var)
Add keywords to the varnames list.
Definition: lint.c:70