VirtualBox

source: vbox/trunk/src/bldprogs/VBoxCompilerPlugInsGcc.cpp@ 57003

Last change on this file since 57003 was 57003, checked in by vboxsync, 10 years ago

gccplugin: New attribute iprt_format_maybe_null for dealing with semaphore, critsect and lock validation naming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 26.5 KB
Line 
1/* $Id: VBoxCompilerPlugInsGcc.cpp 57003 2015-07-19 00:35:01Z vboxsync $ */
2/** @file
3 * gccplugin - GCC plugin for checking IPRT format strings.
4 */
5
6/*
7 * Copyright (C) 2006-2015 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*********************************************************************************************************************************
19* Header Files *
20*********************************************************************************************************************************/
21#include <stdio.h>
22#include <iprt/cdefs.h>
23#include <iprt/stdarg.h>
24
25#include "plugin.h"
26#include "basic-block.h"
27#include "gimple.h"
28#include "tree.h"
29#include "tree-pass.h"
30#include "cp/cp-tree.h"
31
32#include "VBoxCompilerPlugIns.h"
33
34
35/*********************************************************************************************************************************
36* Global Variables *
37*********************************************************************************************************************************/
38/** License indicator. */
39int plugin_is_GPL_compatible;
40
41
42/*********************************************************************************************************************************
43* Defined Constants And Macros *
44*********************************************************************************************************************************/
45/** Convencience macro not present in earlier gcc versions. */
46#ifndef VAR_P
47# define VAR_P(a_hNode) (TREE_CODE(a_hNode) == VAR_DECL)
48#endif
49
50
51/** For use with messages.
52 * @todo needs some more work... Actually, seems we're a bit handicapped by
53 * working on gimplified stuff. */
54#define MY_LOC(a_hPreferred, a_pState) EXPR_LOC_OR_LOC(a_hPreferred, (a_pState)->hFmtLoc)
55
56
57
58/*********************************************************************************************************************************
59* Internal Functions *
60*********************************************************************************************************************************/
61static bool MyPassGateCallback(void);
62static unsigned int MyPassExecuteCallback(void);
63static tree AttributeHandler(tree *, tree, tree, int, bool *);
64
65
66/*********************************************************************************************************************************
67* Global Variables *
68*********************************************************************************************************************************/
69/** Plug-in info. */
70static const struct plugin_info g_PlugInInfo =
71{
72 .version = "0.0.0-ALPHA",
73 .help = "Implements the __iprt_format__ attribute for checking format strings and arguments."
74};
75
76/** My pass. */
77static struct gimple_opt_pass g_MyPass =
78{
79 .pass =
80 {
81 .type = GIMPLE_PASS,
82 .name = "*iprt-format-checks", /* asterisk = no dump */
83 .optinfo_flags = 0,
84 .gate = MyPassGateCallback,
85 .execute = MyPassExecuteCallback,
86 .sub = NULL,
87 .next = NULL,
88 .static_pass_number = 0,
89 .tv_id = TV_NONE,
90 .properties_required = 0,
91 .properties_provided = 0,
92 .properties_destroyed = 0,
93 .todo_flags_start = 0,
94 .todo_flags_finish = 0,
95 }
96};
97
98/** The registration info for my pass. */
99static const struct register_pass_info g_MyPassInfo =
100{
101 .pass = &g_MyPass.pass,
102 .reference_pass_name = "ssa",
103 .ref_pass_instance_number = 1,
104 .pos_op = PASS_POS_INSERT_BEFORE,
105};
106
107
108/** Attribute specifications. */
109static const struct attribute_spec g_AttribSpecs[] =
110{
111 {
112 .name = "iprt_format",
113 .min_length = 2,
114 .max_length = 2,
115 .decl_required = false,
116 .type_required = true,
117 .function_type_required = true,
118 .handler = AttributeHandler,
119 .affects_type_identity = false
120 },
121 {
122 .name = "iprt_format_maybe_null",
123 .min_length = 2,
124 .max_length = 2,
125 .decl_required = false,
126 .type_required = true,
127 .function_type_required = true,
128 .handler = AttributeHandler,
129 .affects_type_identity = false
130 },
131 { NULL, 0, 0, false, false, false, NULL, false } /* just in case */
132};
133
134
135#ifdef DEBUG
136
137/**
138 * Debug function for printing the scope of a decl.
139 * @param hDecl Declaration to print scope for.
140 */
141static void dprintScope(tree hDecl)
142{
143# if 0 /* later? */
144 tree hScope = CP_DECL_CONTEXT(hDecl);
145 if (hScope == global_namespace)
146 return;
147 if (TREE_CODE(hScope) == RECORD_TYPE)
148 hScope = TYPE_NAME(hScope);
149
150 /* recurse */
151 dprintScope(hScope);
152
153 /* name the scope. */
154 dprintf("::%s", DECL_NAME(hScope) ? IDENTIFIER_POINTER(DECL_NAME(hScope)) : "<noname>");
155# endif
156}
157
158
159/**
160 * Debug function for printing a declaration.
161 * @param hDecl The declaration to print.
162 */
163static void dprintDecl(tree hDecl)
164{
165 enum tree_code const enmDeclCode = TREE_CODE(hDecl);
166 tree const hType = TREE_TYPE(hDecl);
167 enum tree_code const enmTypeCode = hType ? TREE_CODE(hType) : (enum tree_code)-1;
168#if 0
169 if ( enmTypeCode == RECORD_TYPE
170 && enmDeclCode == TYPE_DECL
171 && DECL_ARTIFICIAL(hDecl))
172 dprint_class(hType);
173#endif
174
175 dprintf("%s ", tree_code_name[enmDeclCode]);
176 dprintScope(hDecl);
177 dprintf("::%s", DECL_NAME(hDecl) ? IDENTIFIER_POINTER(DECL_NAME(hDecl)) : "<noname>");
178 if (hType)
179 dprintf(" type %s", tree_code_name[enmTypeCode]);
180 dprintf(" @%s:%d", DECL_SOURCE_FILE(hDecl), DECL_SOURCE_LINE(hDecl));
181}
182
183#endif /* DEBUG */
184
185
186static location_t MyGetLocationPlusColumnOffset(location_t hLoc, unsigned int offColumn)
187{
188 /*
189 * Skip NOOPs, reserved locations and macro expansion.
190 */
191 if ( offColumn != 0
192 && hLoc >= RESERVED_LOCATION_COUNT
193 && !linemap_location_from_macro_expansion_p(line_table, hLoc))
194 {
195#if __GNUC__ >= 5 /** @todo figure this... */
196 /*
197 * There is an API for doing this, nice.
198 */
199 location_t hNewLoc = linemap_position_for_loc_and_offset(line_table, hLoc, offColumn);
200 if (hNewLoc && hNewLoc != hLoc)
201 {
202 dprintf("MyGetLocationPlusColumnOffset: hNewLoc=%#x hLoc=%#x offColumn=%u\n", hNewLoc, hLoc, offColumn);
203 return hNewLoc;
204 }
205
206#else
207 /*
208 * Have to do the job ourselves, it seems. This is a bit hairy...
209 */
210 line_map const *pMap = NULL;
211 location_t hLoc2 = linemap_resolve_location(line_table, hLoc, LRK_SPELLING_LOCATION, &pMap);
212 if (hLoc2)
213 hLoc = hLoc2;
214
215 /* Guard against wrap arounds and overlaps. */
216 if ( hLoc + offColumn > MAP_START_LOCATION(pMap) /** @todo Use MAX_SOURCE_LOCATION? */
217 && ( pMap == LINEMAPS_LAST_ORDINARY_MAP(line_table)
218 || hLoc + offColumn < MAP_START_LOCATION((pMap + 1))))
219 {
220 /* Calc new column and check that it's within the valid range. */
221 unsigned int uColumn = SOURCE_COLUMN(pMap, hLoc) + offColumn;
222 if (uColumn < RT_BIT_32(ORDINARY_MAP_NUMBER_OF_COLUMN_BITS(pMap)))
223 {
224 /* Try add the position. If we get a valid result, replace the location. */
225 source_location hNewLoc = linemap_position_for_line_and_column((line_map *)pMap, SOURCE_LINE(pMap, hLoc), uColumn);
226 if ( hNewLoc <= line_table->highest_location
227 && linemap_lookup(line_table, hNewLoc) != NULL)
228 {
229 dprintf("MyGetLocationPlusColumnOffset: hNewLoc=%#x hLoc=%#x offColumn=%u uColumn=%u\n",
230 hNewLoc, hLoc, offColumn, uColumn);
231 return hNewLoc;
232 }
233 }
234 }
235#endif
236 }
237 dprintf("MyGetLocationPlusColumnOffset: taking fallback\n");
238 return hLoc;
239}
240
241
242static location_t MyGetFormatStringLocation(PVFMTCHKSTATE pState, const char *pszLoc)
243{
244 location_t hLoc = pState->hFmtLoc;
245 intptr_t offString = pszLoc - pState->pszFmt;
246 if ( offString >= 0
247 && !linemap_location_from_macro_expansion_p(line_table, hLoc))
248 {
249 unsigned uCol = 1 + offString;
250 expanded_location XLoc = expand_location_to_spelling_point(hLoc);
251 int cchLine = 0;
252#if __GNUC__ >= 5 /** @todo figure this... */
253 const char *pszLine = location_get_source_line(XLoc, &cchLine);
254#else
255 const char *pszLine = location_get_source_line(XLoc);
256 if (pszLine)
257 {
258 const char *pszEol = strpbrk(pszLine, "\n\r");
259 if (!pszEol)
260 pszEol = strchr(pszLine, '\0');
261 cchLine = (int)(pszEol - pszLine);
262 }
263#endif
264 if (pszLine)
265 {
266 /** @todo Adjust the position by parsing the source. */
267 pszLine += XLoc.column - 1;
268 cchLine -= XLoc.column - 1;
269 }
270
271 hLoc = MyGetLocationPlusColumnOffset(hLoc, uCol);
272 }
273 return hLoc;
274}
275
276
277/**
278 * Non-recursive worker for MyCheckFormatRecursive.
279 *
280 * This will attempt to result @a hFmtArg into a string literal which it then
281 * passes on to MyCheckFormatString for the actual analyzis.
282 *
283 * @param pState The format string checking state.
284 * @param hFmtArg The format string node.
285 */
286DECL_NO_INLINE(static, void) MyCheckFormatNonRecursive(PVFMTCHKSTATE pState, tree hFmtArg)
287{
288 dprintf("checker: hFmtArg=%p %s\n", hFmtArg, tree_code_name[TREE_CODE(hFmtArg)]);
289
290 /*
291 * Try resolve variables into constant strings.
292 */
293 if (VAR_P(hFmtArg))
294 {
295 hFmtArg = decl_constant_value(hFmtArg);
296 STRIP_NOPS(hFmtArg); /* Used as argument and assigned call result. */
297 dprintf("checker1: variable => hFmtArg=%p %s\n", hFmtArg, tree_code_name[TREE_CODE(hFmtArg)]);
298 }
299
300 /*
301 * Fend off NULLs.
302 */
303 if (integer_zerop(hFmtArg))
304 {
305 if (pState->fMaybeNull)
306 VFmtChkVerifyEndOfArgs(pState, 0);
307 else
308 error_at(MY_LOC(hFmtArg, pState), "Format string should not be NULL");
309 }
310 /*
311 * Need address expression to get any further.
312 */
313 else if (TREE_CODE(hFmtArg) != ADDR_EXPR)
314 dprintf("checker1: Not address expression (%s)\n", tree_code_name[TREE_CODE(hFmtArg)]);
315 else
316 {
317 pState->hFmtLoc = EXPR_LOC_OR_LOC(hFmtArg, pState->hFmtLoc);
318 hFmtArg = TREE_OPERAND(hFmtArg, 0);
319
320 /*
321 * Deal with fixed string indexing, if possible.
322 */
323 HOST_WIDE_INT off = 0;
324 if ( TREE_CODE(hFmtArg) == ARRAY_REF
325 && TREE_INT_CST(TREE_OPERAND(hFmtArg, 1)).fits_shwi() )
326 {
327 off = TREE_INT_CST(TREE_OPERAND(hFmtArg, 1)).to_shwi();
328 if (off < 0)
329 {
330 dprintf("checker1: ARRAY_REF, off=%ld\n", off);
331 return;
332 }
333 hFmtArg = TREE_OPERAND(hFmtArg, 0);
334 dprintf("checker1: ARRAY_REF => hFmtArg=%p %s, off=%ld\n", hFmtArg, tree_code_name[TREE_CODE(hFmtArg)], off);
335 }
336
337 /*
338 * Deal with static const char g_szFmt[] = "qwerty"; Take care as
339 * the actual string constant may not necessarily include the terminator.
340 */
341 tree hArraySize = NULL_TREE;
342 if ( VAR_P(hFmtArg)
343 && TREE_CODE(TREE_TYPE(hFmtArg)) == ARRAY_TYPE)
344 {
345 tree hArrayInitializer = decl_constant_value(hFmtArg);
346 if ( hArrayInitializer != hFmtArg
347 && TREE_CODE(hArrayInitializer) == STRING_CST)
348 {
349 hArraySize = DECL_SIZE_UNIT(hFmtArg);
350 hFmtArg = hArrayInitializer;
351 }
352 }
353
354 /*
355 * Are we dealing with a string literal now?
356 */
357 if (TREE_CODE(hFmtArg) != STRING_CST)
358 dprintf("checker1: Not string literal (%s)\n", tree_code_name[TREE_CODE(hFmtArg)]);
359 else if (TYPE_MAIN_VARIANT(TREE_TYPE(TREE_TYPE(hFmtArg))) != char_type_node)
360 warning_at(pState->hFmtLoc, 0, "expected 'char' type string literal");
361 else
362 {
363 /*
364 * Yes we are, so get the pointer to the string and its length.
365 */
366 const char *pszFmt = TREE_STRING_POINTER(hFmtArg);
367 int cchFmt = TREE_STRING_LENGTH(hFmtArg);
368
369 /* Adjust cchFmt to the initialized array size if appropriate. */
370 if (hArraySize != NULL_TREE)
371 {
372 if (TREE_CODE(hArraySize) != INTEGER_CST)
373 warning_at(pState->hFmtLoc, 0, "Expected integer array size (not %s)", tree_code_name[TREE_CODE(hArraySize)]);
374 else if (!TREE_INT_CST(hArraySize).fits_shwi())
375 warning_at(pState->hFmtLoc, 0, "Unexpected integer overflow in array size constant");
376 else
377 {
378 HOST_WIDE_INT cbArray = TREE_INT_CST(hArraySize).to_shwi();
379 if ( cbArray <= 0
380 || cbArray != (int)cbArray)
381 warning_at(pState->hFmtLoc, 0, "Unexpected integer array size constant value: %ld", cbArray);
382 else if (cchFmt > cbArray)
383 {
384 dprintf("checker1: cchFmt=%d => cchFmt=%ld (=cbArray)\n", cchFmt, cbArray);
385 cchFmt = (int)cbArray;
386 }
387 }
388 }
389
390 /* Apply the offset, if given. */
391 if (off)
392 {
393 if (off >= cchFmt)
394 {
395 dprintf("checker1: off=%ld >= cchFmt=%d -> skipping\n", off, cchFmt);
396 return;
397 }
398 pszFmt += off;
399 cchFmt -= (int)off;
400 }
401
402 /*
403 * Check for unterminated strings.
404 */
405 if ( cchFmt < 1
406 || pszFmt[cchFmt - 1] != '\0')
407 warning_at(pState->hFmtLoc, 0, "Unterminated format string (cchFmt=%d)", cchFmt);
408 /*
409 * Call worker to check the actual string.
410 */
411 else
412 MyCheckFormatCString(pState, pszFmt);
413 }
414 }
415}
416
417
418/**
419 * Deal recursively with special format string constructs.
420 *
421 * This will call MyCheckFormatNonRecursive to validate each format string.
422 *
423 * @param pState The format string checking state.
424 * @param hFmtArg The format string node.
425 */
426static void MyCheckFormatRecursive(PVFMTCHKSTATE pState, tree hFmtArg)
427{
428 /*
429 * Catch wrong attribute use.
430 */
431 if (hFmtArg == NULL_TREE)
432 error_at(pState->hFmtLoc, "IPRT format attribute is probably used incorrectly (hFmtArg is NULL)");
433 /*
434 * NULL format strings may cause crashes.
435 */
436 else if (integer_zerop(hFmtArg))
437 {
438 if (pState->fMaybeNull)
439 VFmtChkVerifyEndOfArgs(pState, 0);
440 else
441 error_at(MY_LOC(hFmtArg, pState), "Format string should not be NULL");
442 }
443 /*
444 * Check both branches of a ternary operator.
445 */
446 else if (TREE_CODE(hFmtArg) == COND_EXPR)
447 {
448 MyCheckFormatRecursive(pState, TREE_OPERAND(hFmtArg, 1));
449 MyCheckFormatRecursive(pState, TREE_OPERAND(hFmtArg, 2));
450 }
451 /*
452 * Strip coercion.
453 */
454 else if ( CONVERT_EXPR_P(hFmtArg)
455 && TYPE_PRECISION(TREE_TYPE(hFmtArg)) == TYPE_PRECISION(TREE_TYPE(TREE_OPERAND(hFmtArg, 0))) )
456 MyCheckFormatRecursive(pState, TREE_OPERAND(hFmtArg, 0));
457 /*
458 * We're good, hand it to the non-recursive worker.
459 */
460 else
461 MyCheckFormatNonRecursive(pState, hFmtArg);
462}
463
464
465/**
466 * Execute my pass.
467 * @returns Flags indicates stuff todo, we return 0.
468 */
469static unsigned int MyPassExecuteCallback(void)
470{
471 dprintf("MyPassExecuteCallback:\n");
472
473 /*
474 * Enumerate the basic blocks.
475 */
476 basic_block hBasicBlock;
477 FOR_EACH_BB(hBasicBlock)
478 {
479 dprintf(" hBasicBlock=%p\n", hBasicBlock);
480
481 /*
482 * Enumerate the statements in the current basic block.
483 * We're interested in calls to functions with the __iprt_format__ attribute.
484 */
485 for (gimple_stmt_iterator hStmtItr = gsi_start_bb(hBasicBlock); !gsi_end_p(hStmtItr); gsi_next(&hStmtItr))
486 {
487 gimple const hStmt = gsi_stmt(hStmtItr);
488 enum gimple_code const enmCode = gimple_code(hStmt);
489#ifdef DEBUG
490 unsigned const cOps = gimple_num_ops(hStmt);
491 dprintf(" hStmt=%p %s (%d) ops=%d\n", hStmt, gimple_code_name[enmCode], enmCode, cOps);
492 for (unsigned iOp = 0; iOp < cOps; iOp++)
493 {
494 tree const hOp = gimple_op(hStmt, iOp);
495 if (hOp)
496 dprintf(" %02d: %p, code %s(%d)\n", iOp, hOp, tree_code_name[TREE_CODE(hOp)], TREE_CODE(hOp));
497 else
498 dprintf(" %02d: NULL_TREE\n", iOp);
499 }
500#endif
501 if (enmCode == GIMPLE_CALL)
502 {
503 /*
504 * Check if the function type has the __iprt_format__ attribute.
505 */
506 tree const hFn = gimple_call_fn(hStmt);
507 tree const hFnType = gimple_call_fntype(hStmt);
508 tree const hAttr = lookup_attribute("iprt_format", TYPE_ATTRIBUTES(hFnType));
509 tree const hAttrMaybe0 = lookup_attribute("iprt_format_maybe_null", TYPE_ATTRIBUTES(hFnType));
510#ifdef DEBUG
511 tree const hFnDecl = gimple_call_fndecl(hStmt);
512 dprintf(" hFn =%p %s(%d); args=%d\n",
513 hFn, tree_code_name[TREE_CODE(hFn)], TREE_CODE(hFn), gimple_call_num_args(hStmt));
514 if (hFnDecl)
515 dprintf(" hFnDecl=%p %s(%d) type=%p %s:%d\n", hFnDecl, tree_code_name[TREE_CODE(hFnDecl)],
516 TREE_CODE(hFnDecl), TREE_TYPE(hFnDecl), DECL_SOURCE_FILE(hFnDecl), DECL_SOURCE_LINE(hFnDecl));
517 if (hFnType)
518 dprintf(" hFnType=%p %s(%d)\n", hFnType, tree_code_name[TREE_CODE(hFnType)], TREE_CODE(hFnType));
519#endif
520 if (hAttr || hAttrMaybe0)
521 {
522 /*
523 * Yeah, it has the attribute!
524 */
525 tree const hAttrArgs = hAttr ? TREE_VALUE(hAttr) : TREE_VALUE(hAttrMaybe0);
526 VFMTCHKSTATE State;
527 State.iFmt = TREE_INT_CST(TREE_VALUE(hAttrArgs)).to_shwi();
528 State.iArgs = TREE_INT_CST(TREE_VALUE(TREE_CHAIN(hAttrArgs))).to_shwi();
529 State.pszFmt = NULL;
530 State.fMaybeNull = hAttr == NULL_TREE;
531 State.hStmt = hStmt;
532 State.hFmtLoc = gimple_location(hStmt);
533 dprintf(" %s() __iprt_format%s__(iFmt=%ld, iArgs=%ld)\n",
534 DECL_NAME(hFnDecl) ? IDENTIFIER_POINTER(DECL_NAME(hFnDecl)) : "<unamed>",
535 State.fMaybeNull ? "_maybe_null" : "", State.iFmt, State.iArgs);
536
537 MyCheckFormatRecursive(&State, gimple_call_arg(hStmt, State.iFmt - 1));
538 }
539 }
540 }
541 }
542 return 0;
543}
544
545
546/**
547 * Gate callback for my pass that indicates whether it should execute or not.
548 * @returns true to execute.
549 */
550static bool MyPassGateCallback(void)
551{
552 dprintf("MyPassGateCallback:\n");
553 return true;
554}
555
556
557/**
558 * Validate the use of an attribute.
559 *
560 * @returns ??
561 * @param phOnNode The node the attribute is being used on.
562 * @param hAttrName The attribute name.
563 * @param hAttrArgs The attribute arguments.
564 * @param fFlags Some kind of flags...
565 * @param pfDontAddAttrib Whether to add the attribute to this node or not.
566 */
567static tree AttributeHandler(tree *phOnNode, tree hAttrName, tree hAttrArgs, int fFlags, bool *pfDontAddAttrib)
568{
569 dprintf("AttributeHandler: name=%s fFlags=%#x", IDENTIFIER_POINTER(hAttrName), fFlags);
570 long iFmt = TREE_INT_CST(TREE_VALUE(hAttrArgs)).to_shwi();
571 long iArgs = TREE_INT_CST(TREE_VALUE(TREE_CHAIN(hAttrArgs))).to_shwi();
572 dprintf(" iFmt=%ld iArgs=%ld", iFmt, iArgs);
573
574 tree hType = *phOnNode;
575 dprintf(" hType=%p %s(%d)\n", hType, tree_code_name[TREE_CODE(hType)], TREE_CODE(hType));
576
577 if (pfDontAddAttrib)
578 *pfDontAddAttrib = false;
579 return NULL_TREE;
580}
581
582
583/**
584 * Called when we can register attributes.
585 *
586 * @param pvEventData Ignored.
587 * @param pvUser Ignored.
588 */
589static void RegisterAttributesEvent(void *pvEventData, void *pvUser)
590{
591 NOREF(pvEventData); NOREF(pvUser);
592 dprintf("RegisterAttributesEvent: pvEventData=%p\n", pvEventData);
593
594 register_attribute(&g_AttribSpecs[0]);
595 register_attribute(&g_AttribSpecs[1]);
596}
597
598
599/**
600 * The plug-in entry point.
601 *
602 * @returns 0 to indicate success?
603 * @param pPlugInInfo Plugin info structure.
604 * @param pGccVer GCC Version.
605 */
606int plugin_init(plugin_name_args *pPlugInInfo, plugin_gcc_version *pGccVer)
607{
608 dprintf("plugin_init: %s\n", pPlugInInfo->full_name);
609 dprintf("gcc version: basever=%s datestamp=%s devphase=%s revision=%s\n",
610 pGccVer->basever, pGccVer->datestamp, pGccVer->devphase, pGccVer->revision);
611
612 /* Ask for callback in which we may register the attribute. */
613 register_callback(pPlugInInfo->base_name, PLUGIN_ATTRIBUTES, RegisterAttributesEvent, NULL /*pvUser*/);
614
615 /* Register our pass. */
616 register_callback(pPlugInInfo->base_name, PLUGIN_PASS_MANAGER_SETUP, NULL, (void *)&g_MyPassInfo);
617
618 /* Register plug-in info. */
619 register_callback(pPlugInInfo->base_name, PLUGIN_INFO, NULL, (void *)&g_PlugInInfo);
620
621 return 0;
622}
623
624
625
626
627/*
628 *
629 * Functions used by the common code.
630 * Functions used by the common code.
631 * Functions used by the common code.
632 *
633 */
634
635void VFmtChkWarnFmt(PVFMTCHKSTATE pState, const char *pszLoc, const char *pszFormat, ...)
636{
637 char szTmp[1024];
638 va_list va;
639 va_start(va, pszFormat);
640 vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
641 va_end(va);
642
643 /* display the warning. */
644 warning_at(MyGetFormatStringLocation(pState, pszLoc), 0, "%s", szTmp);
645}
646
647
648void VFmtChkErrFmt(PVFMTCHKSTATE pState, const char *pszLoc, const char *pszFormat, ...)
649{
650 char szTmp[1024];
651 va_list va;
652 va_start(va, pszFormat);
653 vsnprintf(szTmp, sizeof(szTmp), pszFormat, va);
654 va_end(va);
655
656 /* display the warning. */
657 error_at(MyGetFormatStringLocation(pState, pszLoc), "%s", szTmp);
658}
659
660
661
662void VFmtChkVerifyEndOfArgs(PVFMTCHKSTATE pState, unsigned iArg)
663{
664 dprintf("VFmtChkVerifyEndOfArgs: iArg=%u iArgs=%ld cArgs=%u\n", iArg, pState->iArgs, gimple_call_num_args(pState->hStmt));
665 if (pState->iArgs > 0)
666 {
667 iArg += pState->iArgs - 1;
668 unsigned cArgs = gimple_call_num_args(pState->hStmt);
669 if (iArg == cArgs)
670 { /* fine */ }
671 else if (iArg < cArgs)
672 {
673 tree hArg = gimple_call_arg(pState->hStmt, iArg);
674 if (cArgs - iArg > 1)
675 error_at(MY_LOC(hArg, pState), "%u extra arguments not consumed by format string", cArgs - iArg);
676 else if ( TREE_CODE(hArg) != INTEGER_CST
677 || !TREE_INT_CST(hArg).fits_shwi()
678 || TREE_INT_CST(hArg).to_shwi() != -99) /* ignore final dummy argument: ..., -99); */
679 error_at(MY_LOC(hArg, pState), "one extra argument not consumed by format string");
680 }
681 /* This should be handled elsewhere, but just in case. */
682 else if (iArg - 1 == cArgs)
683 error_at(pState->hFmtLoc, "one argument too few");
684 else
685 error_at(pState->hFmtLoc, "%u arguments too few", iArg - cArgs);
686 }
687}
688
689
690bool VFmtChkRequirePresentArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
691{
692 if (pState->iArgs > 0)
693 {
694 iArg += pState->iArgs - 1;
695 unsigned cArgs = gimple_call_num_args(pState->hStmt);
696 if (iArg >= cArgs)
697 {
698 VFmtChkErrFmt(pState, pszLoc, "Missing argument! %s", pszMessage);
699 return false;
700 }
701 }
702 return true;
703}
704
705
706bool VFmtChkRequireIntArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
707{
708 if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
709 {
710 /** @todo type check. */
711 return true;
712 }
713 return false;
714}
715
716
717bool VFmtChkRequireStringArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
718{
719 if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
720 {
721 /** @todo type check. */
722 return true;
723 }
724 return false;
725}
726
727
728bool VFmtChkRequireVaListPtrArg(PVFMTCHKSTATE pState, const char *pszLoc, unsigned iArg, const char *pszMessage)
729{
730 if (VFmtChkRequirePresentArg(pState, pszLoc, iArg, pszMessage))
731 {
732 /** @todo type check. */
733 return true;
734 }
735 return false;
736}
737
738
739void VFmtChkHandleReplacementFormatString(PVFMTCHKSTATE pState, const char *pszPctM, unsigned iArg)
740{
741 if (pState->iArgs > 0)
742 {
743 pState->iFmt = pState->iArgs + iArg;
744 pState->iArgs = pState->iFmt + 1;
745 pState->fMaybeNull = false;
746 MyCheckFormatRecursive(pState, gimple_call_arg(pState->hStmt, pState->iFmt - 1));
747 }
748}
749
750
751const char *VFmtChkGetFmtLocFile(PVFMTCHKSTATE pState)
752{
753 return LOCATION_FILE(pState->hFmtLoc);
754}
755
756
757unsigned int VFmtChkGetFmtLocLine(PVFMTCHKSTATE pState)
758{
759 return LOCATION_LINE(pState->hFmtLoc);
760}
761
762
763unsigned int VFmtChkGetFmtLocColumn(PVFMTCHKSTATE pState)
764{
765 return LOCATION_COLUMN(pState->hFmtLoc);
766}
767
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette