Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit02531e8

Browse files
committed
Fix assorted bugs in ecpg's macro mechanism.
The code associated with EXEC SQL DEFINE was unreadable and full ofbugs, notably:* It'd attempt to free a non-malloced string if the ecpg programtries to redefine a macro that was defined on the command line.* Possible memory stomp if user writes "-D=foo".* Undef'ing or redefining a macro defined on the command line wouldchange the state visible to the next file, when multiple files arespecified on the command line. (While possibly that could have beenan intentional choice, the code clearly intends to revert to theoriginal macro state; it's just failing to consider this interaction.)* Missing "break" in defining a new macro meant that redefinitionof an existing name would cause an extra entry to be added to thedefinition list. While not immediately harmful, a subsequent undefwould result in the prior entry becoming visible again.* The interactions with input buffering are subtle and were entirelyundocumented.It's not that surprising that we hadn't noticed these bugs,because there was no test coverage at all of either the -Dcommand line switch or multiple input files. This patch addssuch coverage (in a rather hacky way I guess).In addition to the code bugs, the user documentation was confusedabout whether the -D switch defines a C macro or an ecpg one, andit failed to mention that you can write "-Dsymbol=value".These problems are old, so back-patch to all supported branches.Discussion:https://postgr.es/m/998011.1713217712@sss.pgh.pa.us
1 parentd9e4ee7 commit02531e8

File tree

11 files changed

+288
-80
lines changed

11 files changed

+288
-80
lines changed

‎doc/src/sgml/ecpg.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5687,6 +5687,14 @@ EXEC SQL UPDATE Tbl SET col = MYNUMBER;
56875687
embedded SQL query because in this case the embedded SQL precompiler is not
56885688
able to see this declaration.
56895689
</para>
5690+
5691+
<para>
5692+
If multiple input files are named on the <command>ecpg</command>
5693+
preprocessor's command line, the effects of <literal>EXEC SQL
5694+
DEFINE</literal> and <literal>EXEC SQL UNDEF</literal> do not carry
5695+
across files: each file starts with only the symbols defined
5696+
by <option>-D</option> switches on the command line.
5697+
</para>
56905698
</sect2>
56915699

56925700
<sect2 id="ecpg-ifdef">

‎doc/src/sgml/ref/ecpg-ref.sgml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,12 @@ PostgreSQL documentation
9393
</varlistentry>
9494

9595
<varlistentry>
96-
<term><option>-D <replaceable>symbol</replaceable></option></term>
96+
<term><option>-D <replaceable>symbol</replaceable>[=<replaceable>value</replaceable>]</option></term>
9797
<listitem>
9898
<para>
99-
Define a C preprocessor symbol.
99+
Define a preprocessor symbol, equivalently to the <command>EXEC SQL
100+
DEFINE</command> directive. If no <replaceable>value</replaceable> is
101+
specified, the symbol is defined with the value <literal>1</literal>.
100102
</para>
101103
</listitem>
102104
</varlistentry>

‎src/interfaces/ecpg/preproc/ecpg.c

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -81,35 +81,46 @@ add_include_path(char *path)
8181
}
8282
}
8383

84+
/*
85+
* Process a command line -D switch
86+
*/
8487
staticvoid
8588
add_preprocessor_define(char*define)
8689
{
87-
struct_defines*pd=defines;
88-
char*ptr,
89-
*define_copy=mm_strdup(define);
90+
/* copy the argument to avoid relying on argv storage */
91+
char*define_copy=mm_strdup(define);
92+
char*ptr;
93+
struct_defines*newdef;
9094

91-
defines=mm_alloc(sizeof(struct_defines));
95+
newdef=mm_alloc(sizeof(struct_defines));
9296

9397
/* look for = sign */
9498
ptr=strchr(define_copy,'=');
9599
if (ptr!=NULL)
96100
{
101+
/* symbol has a value */
97102
char*tmp;
98103

99-
/*symbol has a value */
100-
for (tmp=ptr-1;*tmp==' ';tmp--);
104+
/*strip any spaces between name and '=' */
105+
for (tmp=ptr-1;tmp >=define_copy&&*tmp==' ';tmp--);
101106
tmp[1]='\0';
102-
defines->olddef=define_copy;
103-
defines->newdef=ptr+1;
107+
108+
/*
109+
* Note we don't bother to separately malloc cmdvalue; it will never
110+
* be freed so that's not necessary.
111+
*/
112+
newdef->cmdvalue=ptr+1;
104113
}
105114
else
106115
{
107-
defines->olddef=define_copy;
108-
defines->newdef=mm_strdup("1");
116+
/* define it as "1"; again no need to malloc it */
117+
newdef->cmdvalue="1";
109118
}
110-
defines->pertinent= true;
111-
defines->used=NULL;
112-
defines->next=pd;
119+
newdef->name=define_copy;
120+
newdef->value=mm_strdup(newdef->cmdvalue);
121+
newdef->used=NULL;
122+
newdef->next=defines;
123+
defines=newdef;
113124
}
114125

115126
#defineECPG_GETOPT_LONG_REGRESSION1
@@ -346,6 +357,8 @@ main(int argc, char *const argv[])
346357
{
347358
structcursor*ptr;
348359
struct_defines*defptr;
360+
struct_defines*prevdefptr;
361+
struct_defines*nextdefptr;
349362
structtypedefs*typeptr;
350363

351364
/* remove old cursor definitions if any are still there */
@@ -373,28 +386,28 @@ main(int argc, char *const argv[])
373386
}
374387
cur=NULL;
375388

376-
/* remove non-pertinent old defines as well */
377-
while (defines&& !defines->pertinent)
389+
/* restore defines to their command-line state */
390+
prevdefptr=NULL;
391+
for (defptr=defines;defptr!=NULL;defptr=nextdefptr)
378392
{
379-
defptr=defines;
380-
defines=defines->next;
381-
382-
free(defptr->newdef);
383-
free(defptr->olddef);
384-
free(defptr);
385-
}
386-
387-
for (defptr=defines;defptr!=NULL;defptr=defptr->next)
388-
{
389-
struct_defines*this=defptr->next;
390-
391-
if (this&& !this->pertinent)
393+
nextdefptr=defptr->next;
394+
if (defptr->cmdvalue!=NULL)
392395
{
393-
defptr->next=this->next;
394-
395-
free(this->newdef);
396-
free(this->olddef);
397-
free(this);
396+
/* keep it, resetting the value */
397+
free(defptr->value);
398+
defptr->value=mm_strdup(defptr->cmdvalue);
399+
prevdefptr=defptr;
400+
}
401+
else
402+
{
403+
/* remove it */
404+
if (prevdefptr!=NULL)
405+
prevdefptr->next=nextdefptr;
406+
else
407+
defines=nextdefptr;
408+
free(defptr->name);
409+
free(defptr->value);
410+
free(defptr);
398411
}
399412
}
400413

‎src/interfaces/ecpg/preproc/pgc.l

Lines changed: 89 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,21 @@ char *token_start;
6969
staticint state_before_str_start;
7070
staticint state_before_str_stop;
7171

72-
struct_yy_buffer
72+
/*
73+
* State for handling include files and macro expansion. We use a new
74+
* flex input buffer for each level of include or macro, and create a
75+
* struct _yy_buffer to remember the previous level. There is not a struct
76+
* for the currently active input source; that state is kept in the global
77+
* variables YY_CURRENT_BUFFER, yylineno, and input_filename.
78+
*/
79+
staticstruct_yy_buffer
7380
{
7481
YY_BUFFER_STATEbuffer;
7582
longlineno;
7683
char *filename;
7784
struct_yy_buffer *next;
7885
} *yy_buffer =NULL;
7986

80-
staticchar *old;
81-
8287
/*
8388
* Vars for handling ifdef/elif/endif constructs. preproc_tos is the current
8489
* nesting depth of such constructs, and stacked_if_value[preproc_tos] is the
@@ -426,6 +431,8 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
426431

427432
%{
428433
/* code to execute during start of each call of yylex()*/
434+
char *newdefsymbol =NULL;
435+
429436
token_start =NULL;
430437
%}
431438

@@ -957,6 +964,7 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
957964
}
958965

959966
{identifier}{
967+
/* First check to see if it's a define symbol to expand */
960968
if (!isdefine())
961969
{
962970
intkwvalue;
@@ -1149,17 +1157,23 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
11491157
yytext[i+1] ='\0';
11501158

11511159

1152-
for (ptr = defines; ptr !=NULL; ptr2 = ptr, ptr = ptr->next)
1160+
/* Find and unset any matching define; should be only 1 */
1161+
for (ptr = defines; ptr; ptr2 = ptr, ptr = ptr->next)
11531162
{
1154-
if (strcmp(yytext, ptr->olddef) ==0)
1163+
if (strcmp(yytext, ptr->name) ==0)
11551164
{
1156-
if (ptr2 ==NULL)
1157-
defines = ptr->next;
1158-
else
1159-
ptr2->next = ptr->next;
1160-
free(ptr->newdef);
1161-
free(ptr->olddef);
1162-
free(ptr);
1165+
free(ptr->value);
1166+
ptr->value =NULL;
1167+
/* We cannot forget it if there's a cmdvalue */
1168+
if (ptr->cmdvalue ==NULL)
1169+
{
1170+
if (ptr2 ==NULL)
1171+
defines = ptr->next;
1172+
else
1173+
ptr2->next = ptr->next;
1174+
free(ptr->name);
1175+
free(ptr);
1176+
}
11631177
break;
11641178
}
11651179
}
@@ -1364,11 +1378,17 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
13641378
;
13651379
yytext[i+1] ='\0';
13661380

1367-
for (defptr = defines;
1368-
defptr !=NULL &&
1369-
strcmp(yytext, defptr->olddef) !=0;
1370-
defptr = defptr->next)
1371-
/* skip */ ;
1381+
/* Does a definition exist? */
1382+
for (defptr = defines; defptr; defptr = defptr->next)
1383+
{
1384+
if (strcmp(yytext, defptr->name) ==0)
1385+
{
1386+
/* Found it, but is it currently undefined? */
1387+
if (defptr->value ==NULL)
1388+
defptr =NULL;/* pretend it's not found */
1389+
break;
1390+
}
1391+
}
13721392

13731393
this_active = (defptr ? ifcond : !ifcond);
13741394
stacked_if_value[preproc_tos].active =
@@ -1389,7 +1409,7 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
13891409
yyterminate();
13901410
}
13911411
<def_ident>{identifier} {
1392-
old =mm_strdup(yytext);
1412+
newdefsymbol =mm_strdup(yytext);
13931413
BEGIN(def);
13941414
startlit();
13951415
}
@@ -1398,26 +1418,31 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
13981418
yyterminate();
13991419
}
14001420
<def>{space}*";"{
1401-
struct_defines *ptr, *this;
1421+
struct_defines *ptr;
14021422

1423+
/* Does it already exist? */
14031424
for (ptr = defines; ptr !=NULL; ptr = ptr->next)
14041425
{
1405-
if (strcmp(old, ptr->olddef) ==0)
1406-
{
1407-
free(ptr->newdef);
1408-
ptr->newdef =mm_strdup(literalbuf);
1409-
}
1426+
if (strcmp(newdefsymbol, ptr->name) ==0)
1427+
{
1428+
free(ptr->value);
1429+
ptr->value =mm_strdup(literalbuf);
1430+
/* Don't leak newdefsymbol */
1431+
free(newdefsymbol);
1432+
break;
1433+
}
14101434
}
14111435
if (ptr ==NULL)
14121436
{
1413-
this = (struct_defines *)mm_alloc(sizeof(struct_defines));
1414-
1415-
/* initial definition */
1416-
this->olddef = old;
1417-
this->newdef =mm_strdup(literalbuf);
1418-
this->next = defines;
1419-
this->used =NULL;
1420-
defines =this;
1437+
/* Not present, make a new entry */
1438+
ptr = (struct_defines *)mm_alloc(sizeof(struct_defines));
1439+
1440+
ptr->name = newdefsymbol;
1441+
ptr->value =mm_strdup(literalbuf);
1442+
ptr->cmdvalue =NULL;
1443+
ptr->used =NULL;
1444+
ptr->next = defines;
1445+
defines = ptr;
14211446
}
14221447

14231448
BEGIN(C);
@@ -1434,6 +1459,7 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
14341459
<<EOF>>{
14351460
if (yy_buffer ==NULL)
14361461
{
1462+
/* No more input */
14371463
if ( preproc_tos >0 )
14381464
{
14391465
preproc_tos =0;
@@ -1443,16 +1469,20 @@ cppline{space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+
14431469
}
14441470
else
14451471
{
1472+
/* Revert to previous input source */
14461473
struct_yy_buffer *yb = yy_buffer;
14471474
int i;
14481475
struct_defines *ptr;
14491476

1477+
/* Check to see if we are exiting a macro value */
14501478
for (ptr = defines; ptr; ptr = ptr->next)
1479+
{
14511480
if (ptr->used == yy_buffer)
14521481
{
14531482
ptr->used =NULL;
1454-
break;
1483+
break;/* there can't be multiple matches */
14551484
}
1485+
}
14561486

14571487
if (yyin !=NULL)
14581488
fclose(yyin);
@@ -1677,15 +1707,24 @@ ecpg_isspace(char ch)
16771707
returnfalse;
16781708
}
16791709

1680-
staticboolisdefine(void)
1710+
/*
1711+
* If yytext matches a define symbol, begin scanning the symbol's value
1712+
* and return true
1713+
*/
1714+
staticbool
1715+
isdefine(void)
16811716
{
16821717
struct_defines *ptr;
16831718

16841719
/* is it a define? */
16851720
for (ptr = defines; ptr; ptr = ptr->next)
16861721
{
1687-
if (strcmp(yytext, ptr->olddef) ==0 && ptr->used ==NULL)
1722+
/* notice we do not match anything being actively expanded */
1723+
if (strcmp(yytext, ptr->name) ==0 &&
1724+
ptr->value !=NULL &&
1725+
ptr->used ==NULL)
16881726
{
1727+
/* Save state associated with the current buffer */
16891728
struct_yy_buffer *yb;
16901729

16911730
yb =mm_alloc(sizeof(struct_yy_buffer));
@@ -1694,18 +1733,30 @@ static bool isdefine(void)
16941733
yb->lineno = yylineno;
16951734
yb->filename =mm_strdup(input_filename);
16961735
yb->next = yy_buffer;
1736+
yy_buffer = yb;
16971737

1698-
ptr->used = yy_buffer = yb;
1738+
/* Mark symbol as being actively expanded */
1739+
ptr->used = yb;
16991740

1700-
yy_scan_string(ptr->newdef);
1741+
/*
1742+
* We use yy_scan_string which will copy the value, so there's
1743+
* no need to worry about a possible undef happening while we
1744+
* are still scanning it.
1745+
*/
1746+
yy_scan_string(ptr->value);
17011747
returntrue;
17021748
}
17031749
}
17041750

17051751
returnfalse;
17061752
}
17071753

1708-
staticboolisinformixdefine(void)
1754+
/*
1755+
* Handle replacement of INFORMIX built-in defines. This works just
1756+
* like isdefine() except for the source of the string to scan.
1757+
*/
1758+
staticbool
1759+
isinformixdefine(void)
17091760
{
17101761
constchar *new =NULL;
17111762

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp