Skip to content

Commit f081eea

Browse files
authored
Merge pull request #100 from jayrm/bugfix-699
fbc: sf.net #699: fix new[0] causing infinite loop when calling constructor/destructor list
2 parents b477477 + 84f11d6 commit f081eea

File tree

6 files changed

+283
-24
lines changed

6 files changed

+283
-24
lines changed

changelog.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Version 1.06.0
7373
- #801: *@(expr) solved to (expr) did not cleanly remove null ptr checks allowing invalid datatype assignment with -exx. *PTRCHK(@expr) solves to (expr).
7474
- #880: Overload binary operators now support covariant arguments, overloaded procedure resolution changed especially with respect to CONST and non-CONST parameters
7575
- Fix for debugging lines in include files but not in procedures. Filename debugging information added for module level statements in included files.
76+
- #699: fix new[0] causing infinite loop when calling constructor/destructor list
7677

7778

7879
Version 1.05.0

src/compiler/ast-helper.bas

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,70 @@ end function
284284
'' loops
285285
''
286286

287+
'' While Counter:
288+
''
289+
'' CNT = INIVALUE
290+
'' WHILE( CNT )
291+
'' <user code>
292+
'' CNT -= 1
293+
'' WEND
294+
295+
function astBuildWhileCounterBegin _
296+
( _
297+
byval tree as ASTNODE ptr, _
298+
byval cnt as FBSYMBOL ptr, _
299+
byval label as FBSYMBOL ptr, _
300+
byval exitlabel as FBSYMBOL ptr, _
301+
byval initexpr as ASTNODE ptr, _
302+
byval flush_label as integer _
303+
) as ASTNODE ptr
304+
305+
'' counter = initvalue
306+
tree = astNewLINK( tree, astBuildVarAssign( cnt, initexpr ) )
307+
308+
'' do
309+
tree = astNewLINK( tree, astNewLABEL( label, flush_label ) )
310+
311+
'' if( counter = 0 ) then
312+
'' goto exitlabel
313+
'' end if
314+
tree = astNewLINK( tree, _
315+
astBuildBranch( _
316+
astNewBOP( AST_OP_EQ, astNewVAR( cnt ), astNewCONSTi( 0 ) ), _
317+
exitlabel, TRUE ) )
318+
319+
function = tree
320+
end function
321+
322+
function astBuildWhileCounterEnd _
323+
( _
324+
byval tree as ASTNODE ptr, _
325+
byval cnt as FBSYMBOL ptr, _
326+
byval label as FBSYMBOL ptr, _
327+
byval exitlabel as FBSYMBOL ptr, _
328+
byval flush_label as integer _
329+
) as ASTNODE ptr
330+
331+
'' counter -= 1
332+
tree = astNewLINK( tree, astBuildVarInc( cnt, -1 ) )
333+
334+
'' goto label
335+
tree = astNewLINK( tree, astNewBranch( AST_OP_JMP, label ) )
336+
337+
'' loop
338+
tree = astNewLINK( tree, astNewLABEL( exitlabel, flush_label ) )
339+
340+
function = tree
341+
end function
342+
343+
'' For:
344+
''
345+
'' CNT = INIVALUE
346+
'' DO
347+
'' <user code>
348+
'' CNT += 1
349+
'' LOOP UNTIL CNT=ENDVALUE
350+
287351
function astBuildForBegin _
288352
( _
289353
byval tree as ASTNODE ptr, _

src/compiler/ast-node-mem.bas

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ function astNewMEM _
3232
end if
3333

3434
'' when clearing/moving more than IR_MEMBLOCK_MAXLEN bytes, take
35-
'' the adress-of and let emit() do the rest
36-
if( lgt > blkmaxlen ) then
35+
'' the adress-of and let emit() do the rest, or if blkmaxlen = 0,
36+
'' then emit() always handles it, even when lgt=0
37+
if( (lgt > blkmaxlen) or (blkmaxlen = 0) ) then
3738
l = astNewADDROF( l )
3839

3940
if( op = AST_OP_MEMMOVE ) then
@@ -60,34 +61,39 @@ private function hCallCtorList _
6061
byval subtype as FBSYMBOL ptr _
6162
) as ASTNODE ptr
6263

63-
dim as FBSYMBOL ptr cnt = any, label = any, iter = any
64+
dim as FBSYMBOL ptr cnt = any, label = any, exitlabel = any, iter = any
6465
dim as ASTNODE ptr tree = any
6566

66-
cnt = symbAddTempVar( FB_DATATYPE_INTEGER )
67+
cnt = symbAddTempVar( FB_DATATYPE_UINT )
6768
label = symbAddLabel( NULL )
69+
exitlabel = symbAddLabel( NULL )
6870
iter = symbAddTempVar( typeAddrOf( dtype ), subtype )
6971

7072
'' iter = @vector[0]
7173
tree = astBuildVarAssign( iter, astNewVAR( tmp ), AST_OPOPT_ISINI )
7274

73-
'' for cnt = 0 to elements-1
75+
'' while( cnt )
7476
'' Note: Using a non-flushing LABEL here because the LABEL node will
7577
'' end up as part of an expression tree, not as a "standalone statement"
76-
tree = astBuildForBegin( tree, cnt, label, 0, FALSE /' non-flushing '/ )
78+
tree = astBuildWhileCounterBegin( tree, cnt, label, exitlabel, elementsexpr, FALSE /' non-flushing '/ )
7779

7880
'' ctor( *iter )
7981
tree = astNewLINK( tree, astBuildCtorCall( subtype, astBuildVarDeref( iter ) ) )
8082

8183
'' iter += 1
8284
tree = astNewLINK( tree, astBuildVarInc( iter, 1 ) )
8385

84-
'' next
85-
tree = astBuildForEnd( tree, cnt, label, elementsexpr )
86+
'' wend
87+
tree = astBuildWhileCounterEnd( tree, cnt, label, exitlabel, FALSE )
8688

8789
'' Wrap into LOOP node so astCloneTree() can clone the label and update
8890
'' the loop code, because it's part of the new[] expression, and not
8991
'' a standalone statement.
90-
function = astNewLOOP( label, tree )
92+
tree = astNewLOOP( label, tree )
93+
94+
tree = astNewLOOP( exitlabel, tree )
95+
96+
function = tree
9197
end function
9298

9399
private function hElements _
@@ -130,6 +136,7 @@ function astBuildNewOp _
130136

131137
dim as ASTNODE ptr lenexpr = any, tree = any
132138
dim as integer save_elmts = any, init = any, elementstreecount = any
139+
dim as FBSYMBOL ptr exitlabel = any
133140

134141
init = INIT_NONE
135142
tree = NULL
@@ -199,7 +206,7 @@ function astBuildNewOp _
199206
if( save_elmts ) then
200207
'' length + sizeof( integer ) (to store the vector size)
201208
lenexpr = astNewBOP( AST_OP_ADD, lenexpr, _
202-
astNewCONSTi( typeGetSize( FB_DATATYPE_INTEGER ), FB_DATATYPE_UINT ) )
209+
astNewCONSTi( typeGetSize( FB_DATATYPE_UINT ), FB_DATATYPE_UINT ) )
203210
end if
204211

205212
newexpr = rtlMemNewOp( op, lenexpr, dtype, subtype )
@@ -211,20 +218,27 @@ function astBuildNewOp _
211218
'' tempptr = new( len )
212219
tree = astNewLINK( tree, astBuildVarAssign( tmp, newexpr, AST_OPOPT_ISINI ) )
213220

221+
'' if( tempptr <> NULL ) then
222+
exitlabel = symbAddLabel( NULL )
223+
224+
'' handle like IIF, we don't want dtors called if tempptr was never allocated
225+
tree = astNewLINK( tree, _
226+
astBuildBranch( astNewBOP( AST_OP_NE, astNewVAR( tmp ), astNewCONSTi( 0 ) ), exitlabel, FALSE, TRUE ) )
227+
214228
'' save elements count?
215229
if( save_elmts ) then
216230
'' *tempptr = elements
217231
tree = astNewLINK( tree, _
218232
astNewASSIGN( _
219-
astNewDEREF( astNewVAR( tmp, , typeAddrOf( FB_DATATYPE_INTEGER ) ) ), _
233+
astNewDEREF( astNewVAR( tmp, , typeAddrOf( FB_DATATYPE_UINT ) ) ), _
220234
hElements( elementsexpr, elementstreecount ), _
221235
AST_OPOPT_ISINI ) )
222236

223-
'' tempptr += len( integer )
237+
'' tempptr += len( uinteger )
224238
tree = astNewLINK( tree, _
225239
astNewSelfBOP( AST_OP_ADD_SELF, _
226240
astNewVAR( tmp, , typeAddrOf( FB_DATATYPE_VOID ) ), _
227-
astNewCONSTi( typeGetSize( FB_DATATYPE_INTEGER ) ), _
241+
astNewCONSTi( typeGetSize( FB_DATATYPE_UINT ) ), _
228242
NULL ) )
229243
end if
230244

@@ -257,29 +271,40 @@ function astBuildNewOp _
257271

258272
end select
259273

260-
function = astNewLINK( tree, initexpr )
274+
'' *tempptr = initializers
275+
tree = astNewLINK( tree, initexpr )
276+
277+
'' end if
278+
tree = astNewLINK( tree, astNewLABEL( exitlabel, FALSE ) )
279+
280+
'' because this is an expression, exitlabel must be cloned with a new label
281+
'' instead of just copied. astNewLOOP() allows this (but naming could be better).
282+
tree = astNewLOOP( exitlabel, tree )
283+
284+
function = tree
261285
end function
262286

263287
private function hCallDtorList( byval ptrexpr as ASTNODE ptr ) as ASTNODE ptr
264-
dim as FBSYMBOL ptr cnt = any, label = any, iter = any, elmts = any
288+
dim as FBSYMBOL ptr cnt = any, label = any, exitlabel = any, iter = any, elmts = any
265289
dim as ASTNODE ptr tree = any, expr = any
266290

267291
cnt = symbAddTempVar( FB_DATATYPE_INTEGER )
268292
label = symbAddLabel( NULL )
293+
exitlabel = symbAddLabel( NULL )
269294
iter = symbAddTempVar( ptrexpr->dtype, ptrexpr->subtype )
270295
elmts = symbAddTempVar( FB_DATATYPE_INTEGER )
271296

272297
'' DELETE[]'s counter is at: cast(integer ptr, vector)[-1]
273298

274-
'' elmts = *cast( integer ptr, cast( any ptr, vector ) + -sizeof( integer ) )
299+
'' elmts = *cast( uinteger ptr, cast( any ptr, vector ) + -sizeof( uinteger ) )
275300
'' (using AST_CONVOPT_DONTCHKPTR to support derived UDT pointers)
276301
tree = astBuildVarAssign( _
277302
elmts, _
278303
astNewDEREF( _
279-
astNewCONV( typeAddrOf( FB_DATATYPE_INTEGER ), NULL, _
304+
astNewCONV( typeAddrOf( FB_DATATYPE_UINT ), NULL, _
280305
astNewBOP( AST_OP_ADD, _
281306
astCloneTree( ptrexpr ), _
282-
astNewCONSTi( -typeGetSize( FB_DATATYPE_INTEGER ) ) ), _
307+
astNewCONSTi( -typeGetSize( FB_DATATYPE_UINT ) ) ), _
283308
AST_CONVOPT_DONTCHKPTR ) ), _
284309
AST_OPOPT_ISINI )
285310

@@ -291,17 +316,17 @@ private function hCallDtorList( byval ptrexpr as ASTNODE ptr ) as ASTNODE ptr
291316
AST_OPOPT_DEFAULT or AST_OPOPT_DOPTRARITH ), _
292317
AST_OPOPT_ISINI ) )
293318

294-
'' for cnt = 0 to elmts-1
295-
tree = astBuildForBegin( tree, cnt, label, 0 )
319+
'' while( counter )
320+
tree = astBuildWhileCounterBegin( tree, cnt, label, exitlabel, astNewVAR( elmts ) )
296321

297322
'' iter -= 1
298323
tree = astNewLINK( tree, astBuildVarInc( iter, -1 ) )
299324

300325
'' dtor( *iter )
301326
tree = astNewLINK( tree, astBuildVarDtorCall( astBuildVarDeref( iter ) ) )
302327

303-
'' next
304-
tree = astBuildForEnd( tree, cnt, label, astNewVAR( elmts ) )
328+
'' wend
329+
tree = astBuildWhileCounterEnd( tree, cnt, label, exitlabel )
305330

306331
function = tree
307332
end function

src/compiler/ast.bi

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,25 @@ declare function astBuildDtorCall _
11741174
byval ignore_virtual as integer = FALSE _
11751175
) as ASTNODE ptr
11761176

1177+
declare function astBuildWhileCounterBegin _
1178+
( _
1179+
byval tree as ASTNODE ptr, _
1180+
byval cnt as FBSYMBOL ptr, _
1181+
byval label as FBSYMBOL ptr, _
1182+
byval exitlabel as FBSYMBOL ptr, _
1183+
byval initexpr as ASTNODE ptr, _
1184+
byval flush_label as integer = TRUE _
1185+
) as ASTNODE ptr
1186+
1187+
declare function astBuildWhileCounterEnd _
1188+
( _
1189+
byval tree as ASTNODE ptr, _
1190+
byval cnt as FBSYMBOL ptr, _
1191+
byval label as FBSYMBOL ptr, _
1192+
byval exitlabel as FBSYMBOL ptr, _
1193+
byval flush_label as integer = TRUE _
1194+
) as ASTNODE ptr
1195+
11771196
declare function astBuildForBegin _
11781197
( _
11791198
byval tree as ASTNODE ptr, _

src/compiler/parser-quirk-mem.bas

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,14 @@ function cOperatorNew( ) as ASTNODE ptr
114114
if( elementsexpr = NULL ) then
115115
elementsexpr = astNewCONSTi( 1, FB_DATATYPE_UINT )
116116
else
117-
'' hack(?): make sure it's a uinteger, otherwise it may crash later, fixes bug #2533376 (counting_pine)
118-
elementsexpr = astNewCONV( FB_DATATYPE_UINT, NULL, elementsexpr )
117+
'' Constant?
118+
if( astIsCONST( elementsexpr ) ) then
119+
'' check at compile time
120+
elementsexpr = astNewCONSTi( cConstIntExprRanged( elementsexpr, FB_DATATYPE_UINT ), FB_DATATYPE_UINT )
121+
else
122+
'' make sure it's a uinteger, otherwise it may crash later, fixes bug #2533376 (counting_pine)
123+
elementsexpr = astNewCONV( FB_DATATYPE_UINT, NULL, elementsexpr, AST_CONVOPT_SIGNCONV )
124+
end if
119125
if( elementsexpr = NULL ) then
120126
errReport( FB_ERRMSG_TYPEMISMATCH, TRUE )
121127
elementsexpr = astNewCONSTi( 1, FB_DATATYPE_UINT )

0 commit comments

Comments
 (0)