source: src/Concurrency/Waitfor.cc@ cf85f96

ADT ast-experimental enum forall-pointer-decay jacob/cs343-translation new-ast-unique-expr pthread-emulation qualifiedEnum
Last change on this file since cf85f96 was b81fd95, checked in by Michael Brooks <mlbrooks@…>, 5 years ago

Fix bug where pointer and reference types allow unsound initialization and return. Fixes #189

There are two instances of the same basic change, which is using conversionCost instead of castCost for resolving...
A: an InitExpr, always; affects variable initializations
B: a CastExpr, for type-system-generated casts only; affects function returns

Changing the behaviour of the typechecker on initialization (do A) and cast (do B):
src/ResolvExpr/AlternativeFinder.cc
src/SynTree/Expression.h
testsinit1.*

Making type of string literal consistent with how C defines it (accommodate A):
src/Parser/ExpressionNode.cc

Making type system happy with incumbent use of void* (accommodate A):
libcfa/src/concurrency/kernel.cfa
libcfa/src/containers/list.hfa
tests/bugs/66.cfa
tests/avltree/avl1.cfa
tests/concurrent/signal/block.cfa
tests/searchsort.cfa

Making type system happy with incumbent plan-9 downcast (accommodate B):
libcfa/src/containers/list.hfa

Fixing previously incorrect constness of declarations (accommodate A):
tests/exceptions/defaults.cfa
libcfa/src/iostream.hfa

Fixing previously incorrect isGenerated classification of casts that desugaring introduces (accommodate B):
src/Concurrency/Keywords.cc
src/Concurrency/Waitfor.cc

Working around trac #207 (revealed by A):
tests/io2.cfa

Working around trac #208 (speculatively created by B):
libcfa/src/bits/locks.hfa
libcfa/src/concurrency/preemption.cfa

Misc:
tests/exceptions/conditional.cfa (accommodate A)

a _msg function for an exception was declared with wrong return type, so it was not compatible for assignment into the vtable instance

libcfa/src/stdlib.hfa

the compiler now prohibits a prior attempt to call a nonexistent realloc overload; calling alloc_align in its place

  • Property mode set to 100644
File size: 15.4 KB
RevLine 
[9f5ecf5]1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// Waitfor.cc --
8//
9// Author : Thierry Delisle
10// Created On : Mon Aug 28 11:06:52 2017
11// Last Modified By :
12// Last Modified On :
[cca568e]13// Update Count : 12
[9f5ecf5]14//
15
16#include "Concurrency/Keywords.h"
17
18#include <cassert> // for assert
19#include <string> // for string, operator==
20
21using namespace std::string_literals;
22
23#include "Common/PassVisitor.h" // for PassVisitor
24#include "Common/SemanticError.h" // for SemanticError
[312029a]25#include "Common/UniqueName.h" // for UniqueName
[9f5ecf5]26#include "Common/utility.h" // for deleteAll, map_range
27#include "CodeGen/OperatorTable.h" // for isConstructor
28#include "InitTweak/InitTweak.h" // for getPointerBase
[1dcd9554]29#include "ResolvExpr/Resolver.h" // for findVoidExpression
[07de76b]30#include "SynTree/LinkageSpec.h" // for Cforall
[9f5ecf5]31#include "SynTree/Constant.h" // for Constant
32#include "SynTree/Declaration.h" // for StructDecl, FunctionDecl, ObjectDecl
33#include "SynTree/Expression.h" // for VariableExpr, ConstantExpr, Untype...
34#include "SynTree/Initializer.h" // for SingleInit, ListInit, Initializer ...
35#include "SynTree/Label.h" // for Label
36#include "SynTree/Statement.h" // for CompoundStmt, DeclStmt, ExprStmt
37#include "SynTree/Type.h" // for StructInstType, Type, PointerType
38#include "SynTree/Visitor.h" // for Visitor, acceptAll
39
40class Attribute;
41/*
42void foo() {
43 while( true ) {
[cca568e]44 when( a < 1 ) waitfor( f : a ) { bar(); }
[9f5ecf5]45 or timeout( swagl() );
[cca568e]46 or waitfor( g : a ) { baz(); }
47 or waitfor( ^?{} : a ) { break; }
[9f5ecf5]48 or waitfor( ^?{} ) { break; }
49 }
50}
51
52void f(int i, float f, A & mutex b, struct foo * );
53void f(int );
54
55
56 | |
57 | |
58 | |
59 | |
60 | |
61 \ | | /
62 \ /
63 \ /
64 \/
65
66
67void foo() {
68 while( true ) {
[42506e1]69 {
70 acceptable_t acceptables[3];
71 if( a < 1 ) {
72 acceptables[0].func = f;
73 acceptables[0].mon = a;
74 }
75 acceptables[1].func = g;
76 acceptables[1].mon = a;
[9f5ecf5]77
[42506e1]78 acceptables[2].func = f;
79 acceptables[2].mon = a;
80 acceptables[2].is_dtor = true;
[9f5ecf5]81
[42506e1]82 int ret = waitfor_internal( acceptables, swagl() );
[9f5ecf5]83
[42506e1]84 switch( ret ) {
85 case 0:
86 {
87 bar();
88 }
89 case 1:
[9f5ecf5]90 {
[42506e1]91 baz();
[9f5ecf5]92 }
[42506e1]93 case 2:
94 signal(a);
95 {
96 break;
97 }
98 }
[9f5ecf5]99 }
100 }
101}*/
102
103namespace Concurrency {
104 //=============================================================================================
105 // Pass declarations
106 //=============================================================================================
107
[1dcd9554]108 class GenerateWaitForPass final : public WithIndexer {
[9f5ecf5]109 public:
110
111 void premutate( FunctionDecl * decl );
112 void premutate( StructDecl * decl );
113
114 Statement * postmutate( WaitForStmt * stmt );
115
116 static void generate( std::list< Declaration * > & translationUnit ) {
117 PassVisitor< GenerateWaitForPass > impl;
118 acceptAll( translationUnit, impl );
119 }
120
121 ObjectDecl * declare( unsigned long count, CompoundStmt * stmt );
[aaa4f93]122 ObjectDecl * declareFlag( CompoundStmt * stmt );
123 Statement * makeSetter( ObjectDecl * flag );
[9f5ecf5]124 ObjectDecl * declMon( WaitForStmt::Clause & clause, CompoundStmt * stmt );
[aaa4f93]125 void init( ObjectDecl * acceptables, int index, WaitForStmt::Clause & clause, Statement * settter, CompoundStmt * stmt );
126 Expression * init_timeout( Expression *& time, Expression *& time_cond, bool has_else, Expression *& else_cond, Statement * settter, CompoundStmt * stmt );
[1dcd9554]127 Expression * call(size_t count, ObjectDecl * acceptables, Expression * timeout, CompoundStmt * stmt);
128 void choose( WaitForStmt * waitfor, Expression * result, CompoundStmt * stmt );
[9f5ecf5]129
130 static void implement( std::list< Declaration * > & translationUnit ) {
131 PassVisitor< GenerateWaitForPass > impl;
132 mutateAll( translationUnit, impl );
133 }
134
135
136 private:
137 FunctionDecl * decl_waitfor = nullptr;
[aaa4f93]138 StructDecl * decl_mask = nullptr;
[9f5ecf5]139 StructDecl * decl_acceptable = nullptr;
140 StructDecl * decl_monitor = nullptr;
141
142 static std::unique_ptr< Type > generic_func;
143
144 UniqueName namer_acc = "__acceptables_"s;
[aaa4f93]145 UniqueName namer_idx = "__index_"s;
146 UniqueName namer_flg = "__do_run_"s;
147 UniqueName namer_msk = "__mask_"s;
148 UniqueName namer_mon = "__monitors_"s;
[9f5ecf5]149 UniqueName namer_tim = "__timeout_"s;
150 };
151
152 //=============================================================================================
153 // General entry routine
154 //=============================================================================================
155 void generateWaitFor( std::list< Declaration * > & translationUnit ) {
156 GenerateWaitForPass ::implement( translationUnit );
157 }
158
159 //=============================================================================================
160 // Generic helper routine
161 //=============================================================================================
162
163 namespace {
164 Expression * makeOpIndex( DeclarationWithType * array, unsigned long index ) {
[1dcd9554]165 return new UntypedExpr(
[9f5ecf5]166 new NameExpr( "?[?]" ),
167 {
168 new VariableExpr( array ),
169 new ConstantExpr( Constant::from_ulong( index ) )
170 }
171 );
172 }
173
174 Expression * makeOpAssign( Expression * lhs, Expression * rhs ) {
[1dcd9554]175 return new UntypedExpr(
[9f5ecf5]176 new NameExpr( "?=?" ),
177 { lhs, rhs }
178 );
179 }
180
[1dcd9554]181 Expression * makeOpMember( Expression * sue, const std::string & mem ) {
182 return new UntypedMemberExpr( new NameExpr( mem ), sue );
[9f5ecf5]183 }
184
[1dcd9554]185 Statement * makeAccStatement( DeclarationWithType * object, unsigned long index, const std::string & member, Expression * value, const SymTab::Indexer & indexer ) {
[08da53d]186 Expression * expr = makeOpAssign(
[1dcd9554]187 makeOpMember(
188 makeOpIndex(
189 object,
190 index
[9f5ecf5]191 ),
[1dcd9554]192 member
193 ),
194 value
[08da53d]195 );
196
197 ResolvExpr::findVoidExpression( expr, indexer );
[1dcd9554]198
[ba3706f]199 return new ExprStmt( expr );
[9f5ecf5]200 }
201
202 Expression * safeCond( Expression * expr, bool ifnull = true ) {
203 if( expr ) return expr;
204
205 return new ConstantExpr( Constant::from_bool( ifnull ) );
206 }
[310e5b7]207
208 VariableExpr * extractVariable( Expression * func ) {
209 if( VariableExpr * var = dynamic_cast< VariableExpr * >( func ) ) {
210 return var;
211 }
212
213 CastExpr * cast = strict_dynamic_cast< CastExpr * >( func );
214 return strict_dynamic_cast< VariableExpr * >( cast->arg );
215 }
216
[8f98b78]217 Expression * detectIsDtor( Expression * func ) {
[310e5b7]218 VariableExpr * typed_func = extractVariable( func );
219 bool is_dtor = InitTweak::isDestructor( typed_func->var );
220 return new ConstantExpr( Constant::from_bool( is_dtor ) );
221 }
[9f5ecf5]222 };
223
224
225 //=============================================================================================
226 // Generate waitfor implementation
227 //=============================================================================================
228
229 void GenerateWaitForPass::premutate( FunctionDecl * decl) {
[310e5b7]230 if( decl->name != "__waitfor_internal" ) return;
[9f5ecf5]231
232 decl_waitfor = decl;
233 }
234
235 void GenerateWaitForPass::premutate( StructDecl * decl ) {
236 if( ! decl->body ) return;
237
238 if( decl->name == "__acceptable_t" ) {
239 assert( !decl_acceptable );
240 decl_acceptable = decl;
241 }
[aaa4f93]242 else if( decl->name == "__waitfor_mask_t" ) {
243 assert( !decl_mask );
244 decl_mask = decl;
245 }
[ac2b598]246 else if( decl->name == "$monitor" ) {
[9f5ecf5]247 assert( !decl_monitor );
248 decl_monitor = decl;
249 }
250 }
251
252 Statement * GenerateWaitForPass::postmutate( WaitForStmt * waitfor ) {
[d55d7a6]253 if( !decl_monitor || !decl_acceptable || !decl_mask )
[73abe95]254 SemanticError( waitfor, "waitfor keyword requires monitors to be in scope, add #include <monitor.hfa>" );
[9f5ecf5]255
[ba3706f]256 CompoundStmt * stmt = new CompoundStmt();
[9f5ecf5]257
258 ObjectDecl * acceptables = declare( waitfor->clauses.size(), stmt );
[aaa4f93]259 ObjectDecl * flag = declareFlag( stmt );
260 Statement * setter = makeSetter( flag );
[9f5ecf5]261
262 int index = 0;
263 for( auto & clause : waitfor->clauses ) {
[aaa4f93]264 init( acceptables, index, clause, setter, stmt );
[9f5ecf5]265
266 index++;
267 }
268
269 Expression * timeout = init_timeout(
270 waitfor->timeout.time,
271 waitfor->timeout.condition,
272 waitfor->orelse .statement,
273 waitfor->orelse .condition,
[aaa4f93]274 setter,
[9f5ecf5]275 stmt
276 );
277
[ba3706f]278 CompoundStmt * compound = new CompoundStmt();
[aaa4f93]279 stmt->push_back( new IfStmt(
280 safeCond( new VariableExpr( flag ) ),
281 compound,
282 nullptr
283 ));
284
285 Expression * result = call( waitfor->clauses.size(), acceptables, timeout, compound );
[9f5ecf5]286
[aaa4f93]287 choose( waitfor, result, compound );
[9f5ecf5]288
289 return stmt;
290 }
291
292 ObjectDecl * GenerateWaitForPass::declare( unsigned long count, CompoundStmt * stmt )
293 {
[1dcd9554]294 ObjectDecl * acceptables = ObjectDecl::newObject(
[9f5ecf5]295 namer_acc.newName(),
296 new ArrayType(
297 noQualifiers,
298 new StructInstType(
299 noQualifiers,
300 decl_acceptable
301 ),
302 new ConstantExpr( Constant::from_ulong( count ) ),
303 false,
304 false
305 ),
306 nullptr
307 );
308
[ba3706f]309 stmt->push_back( new DeclStmt( acceptables) );
[9f5ecf5]310
[08da53d]311 Expression * set = new UntypedExpr(
[aaa4f93]312 new NameExpr( "__builtin_memset" ),
313 {
314 new VariableExpr( acceptables ),
315 new ConstantExpr( Constant::from_int( 0 ) ),
316 new SizeofExpr( new VariableExpr( acceptables ) )
317 }
318 );
319
[08da53d]320 ResolvExpr::findVoidExpression( set, indexer );
[aaa4f93]321
[ba3706f]322 stmt->push_back( new ExprStmt( set ) );
[aaa4f93]323
[9f5ecf5]324 return acceptables;
325 }
326
[aaa4f93]327 ObjectDecl * GenerateWaitForPass::declareFlag( CompoundStmt * stmt ) {
328 ObjectDecl * flag = ObjectDecl::newObject(
329 namer_flg.newName(),
330 new BasicType(
331 noQualifiers,
[e15853c]332 BasicType::Bool
[aaa4f93]333 ),
334 new SingleInit( new ConstantExpr( Constant::from_ulong( 0 ) ) )
335 );
336
[ba3706f]337 stmt->push_back( new DeclStmt( flag) );
[aaa4f93]338
339 return flag;
340 }
341
342 Statement * GenerateWaitForPass::makeSetter( ObjectDecl * flag ) {
[08da53d]343 Expression * expr = new UntypedExpr(
[aaa4f93]344 new NameExpr( "?=?" ),
345 {
346 new VariableExpr( flag ),
347 new ConstantExpr( Constant::from_ulong( 1 ) )
348 }
349 );
350
[08da53d]351 ResolvExpr::findVoidExpression( expr, indexer );
[aaa4f93]352
[ba3706f]353 return new ExprStmt( expr );
[aaa4f93]354 }
355
[9f5ecf5]356 ObjectDecl * GenerateWaitForPass::declMon( WaitForStmt::Clause & clause, CompoundStmt * stmt ) {
357
[1dcd9554]358 ObjectDecl * mon = ObjectDecl::newObject(
[9f5ecf5]359 namer_mon.newName(),
360 new ArrayType(
361 noQualifiers,
[8f98b78]362 new PointerType(
[9f5ecf5]363 noQualifiers,
[8f98b78]364 new StructInstType(
365 noQualifiers,
366 decl_monitor
367 )
[9f5ecf5]368 ),
369 new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ),
370 false,
371 false
372 ),
373 new ListInit(
374 map_range < std::list<Initializer*> > ( clause.target.arguments, [this](Expression * expr ){
[08da53d]375 Expression * init = new CastExpr(
[8f98b78]376 new UntypedExpr(
377 new NameExpr( "get_monitor" ),
378 { expr }
379 ),
380 new PointerType(
381 noQualifiers,
382 new StructInstType(
383 noQualifiers,
384 decl_monitor
385 )
[b81fd95]386 ),
387 false
[8f98b78]388 );
389
[08da53d]390 ResolvExpr::findSingleExpression( init, indexer );
[8f98b78]391 return new SingleInit( init );
[9f5ecf5]392 })
393 )
394 );
395
[ba3706f]396 stmt->push_back( new DeclStmt( mon) );
[9f5ecf5]397
398 return mon;
399 }
400
[aaa4f93]401 void GenerateWaitForPass::init( ObjectDecl * acceptables, int index, WaitForStmt::Clause & clause, Statement * setter, CompoundStmt * stmt ) {
[9f5ecf5]402
403 ObjectDecl * monitors = declMon( clause, stmt );
404
[1dcd9554]405 Type * fptr_t = new PointerType( noQualifiers, new FunctionType( noQualifiers, true ) );
406
[9f5ecf5]407 stmt->push_back( new IfStmt(
408 safeCond( clause.condition ),
[aaa4f93]409 new CompoundStmt({
410 makeAccStatement( acceptables, index, "is_dtor", detectIsDtor( clause.target.function ) , indexer ),
[b81fd95]411 makeAccStatement( acceptables, index, "func" , new CastExpr( clause.target.function, fptr_t, false ) , indexer ),
[0cf5b79]412 makeAccStatement( acceptables, index, "data" , new VariableExpr( monitors ) , indexer ),
[aaa4f93]413 makeAccStatement( acceptables, index, "size" , new ConstantExpr( Constant::from_ulong( clause.target.arguments.size() ) ), indexer ),
414 setter->clone()
415 }),
[9f5ecf5]416 nullptr
417 ));
418
419 clause.target.function = nullptr;
420 clause.target.arguments.empty();
421 clause.condition = nullptr;
422 }
423
424 Expression * GenerateWaitForPass::init_timeout(
425 Expression *& time,
426 Expression *& time_cond,
427 bool has_else,
428 Expression *& else_cond,
[aaa4f93]429 Statement * setter,
[9f5ecf5]430 CompoundStmt * stmt
431 ) {
[1dcd9554]432 ObjectDecl * timeout = ObjectDecl::newObject(
[9f5ecf5]433 namer_tim.newName(),
434 new BasicType(
435 noQualifiers,
436 BasicType::LongLongUnsignedInt
437 ),
438 new SingleInit(
439 new ConstantExpr( Constant::from_int( -1 ) )
440 )
441 );
442
[ba3706f]443 stmt->push_back( new DeclStmt( timeout ) );
[9f5ecf5]444
445 if( time ) {
446 stmt->push_back( new IfStmt(
[1dcd9554]447 safeCond( time_cond ),
[aaa4f93]448 new CompoundStmt({
449 new ExprStmt(
450 makeOpAssign(
451 new VariableExpr( timeout ),
452 time
453 )
454 ),
455 setter->clone()
456 }),
[9f5ecf5]457 nullptr
458 ));
459
460 time = time_cond = nullptr;
461 }
462
463 if( has_else ) {
464 stmt->push_back( new IfStmt(
465 safeCond( else_cond ),
[aaa4f93]466 new CompoundStmt({
467 new ExprStmt(
468 makeOpAssign(
469 new VariableExpr( timeout ),
470 new ConstantExpr( Constant::from_ulong( 0 ) )
471 )
472 ),
473 setter->clone()
474 }),
[9f5ecf5]475 nullptr
476 ));
477
478 else_cond = nullptr;
479 }
480
[aaa4f93]481 delete setter;
482
[9f5ecf5]483 return new VariableExpr( timeout );
484 }
[1dcd9554]485
486 Expression * GenerateWaitForPass::call(
487 size_t count,
488 ObjectDecl * acceptables,
489 Expression * timeout,
490 CompoundStmt * stmt
491 ) {
[aaa4f93]492 ObjectDecl * index = ObjectDecl::newObject(
493 namer_idx.newName(),
[1dcd9554]494 new BasicType(
495 noQualifiers,
[aaa4f93]496 BasicType::ShortSignedInt
[1dcd9554]497 ),
498 new SingleInit(
[aaa4f93]499 new ConstantExpr( Constant::from_int( -1 ) )
[1dcd9554]500 )
501 );
502
[ba3706f]503 stmt->push_back( new DeclStmt( index ) );
[aaa4f93]504
505 ObjectDecl * mask = ObjectDecl::newObject(
506 namer_msk.newName(),
507 new StructInstType(
508 noQualifiers,
509 decl_mask
510 ),
511 new ListInit({
512 new SingleInit( new AddressExpr( new VariableExpr( index ) ) ),
[d2d50d7]513 new ListInit({
514 new SingleInit( new VariableExpr( acceptables ) ),
515 new SingleInit( new ConstantExpr( Constant::from_ulong( count ) ) )
516 })
[aaa4f93]517 })
518 );
519
[ba3706f]520 stmt->push_back( new DeclStmt( mask ) );
[aaa4f93]521
522 stmt->push_back( new ExprStmt(
523 new ApplicationExpr(
524 VariableExpr::functionPointer( decl_waitfor ),
525 {
526 new CastExpr(
527 new VariableExpr( mask ),
528 new ReferenceType(
529 noQualifiers,
530 new StructInstType(
531 noQualifiers,
532 decl_mask
533 )
[b81fd95]534 ),
535 false
[aaa4f93]536 ),
537 timeout
538 }
539 )
540 ));
[1dcd9554]541
[aaa4f93]542 return new VariableExpr( index );
[1dcd9554]543 }
544
545 void GenerateWaitForPass::choose(
546 WaitForStmt * waitfor,
547 Expression * result,
548 CompoundStmt * stmt
549 ) {
550 SwitchStmt * swtch = new SwitchStmt(
551 result,
552 std::list<Statement *>()
553 );
554
555 unsigned long i = 0;
556 for( auto & clause : waitfor->clauses ) {
557 swtch->statements.push_back(
558 new CaseStmt(
559 new ConstantExpr( Constant::from_ulong( i++ ) ),
560 {
[42506e1]561 new CompoundStmt({
562 clause.statement,
563 new BranchStmt(
564 "",
565 BranchStmt::Break
566 )
567 })
[1dcd9554]568 }
569 )
570 );
571 }
572
573 if(waitfor->timeout.statement) {
574 swtch->statements.push_back(
575 new CaseStmt(
[b18830e]576 new ConstantExpr( Constant::from_int( -2 ) ),
[1dcd9554]577 {
[42506e1]578 new CompoundStmt({
579 waitfor->timeout.statement,
580 new BranchStmt(
581 "",
582 BranchStmt::Break
583 )
584 })
[1dcd9554]585 }
586 )
587 );
588 }
589
590 if(waitfor->orelse.statement) {
591 swtch->statements.push_back(
592 new CaseStmt(
[b18830e]593 new ConstantExpr( Constant::from_int( -1 ) ),
[1dcd9554]594 {
[42506e1]595 new CompoundStmt({
596 waitfor->orelse.statement,
597 new BranchStmt(
598 "",
599 BranchStmt::Break
600 )
601 })
[1dcd9554]602 }
603 )
604 );
605 }
606
607 stmt->push_back( swtch );
608 }
[9f5ecf5]609};
610
611// Local Variables: //
612// mode: c //
613// tab-width: 4 //
[08da53d]614// End: //
Note: See TracBrowser for help on using the repository browser.