From 700baa35a69ec9d7b1bbd5551366a24560334451 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Thu, 10 Apr 2014 09:38:28 -0400 Subject: Linux v3.14-12042-g69cd9eba3886 --- secure-modules.patch | 74 ++++++++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'secure-modules.patch') diff --git a/secure-modules.patch b/secure-modules.patch index 0c93fa51..478c62ff 100644 --- a/secure-modules.patch +++ b/secure-modules.patch @@ -1,7 +1,7 @@ Bugzilla: N/A Upstream-status: Fedora mustard. Replaced by securelevels, but that was nak'd -From b0466e5c5483957f8ca30b8f1bcf60bbad9d40aa Mon Sep 17 00:00:00 2001 +From 0f81a4461431941c17ff26fd3d5e284ede4a368a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Aug 2013 17:58:15 -0400 Subject: [PATCH 01/14] Add secure_modules() call @@ -17,10 +17,10 @@ Signed-off-by: Matthew Garrett 2 files changed, 17 insertions(+) diff --git a/include/linux/module.h b/include/linux/module.h -index eaf60ff9ba94..5ab9d81e3b96 100644 +index f520a767c86c..fc9b54eb779e 100644 --- a/include/linux/module.h +++ b/include/linux/module.h -@@ -512,6 +512,8 @@ int unregister_module_notifier(struct notifier_block *nb); +@@ -509,6 +509,8 @@ int unregister_module_notifier(struct notifier_block *nb); extern void print_modules(void); @@ -29,7 +29,7 @@ index eaf60ff9ba94..5ab9d81e3b96 100644 #else /* !CONFIG_MODULES... */ /* Given an address, look for it in the exception tables. */ -@@ -622,6 +624,11 @@ static inline int unregister_module_notifier(struct notifier_block *nb) +@@ -619,6 +621,11 @@ static inline int unregister_module_notifier(struct notifier_block *nb) static inline void print_modules(void) { } @@ -42,10 +42,10 @@ index eaf60ff9ba94..5ab9d81e3b96 100644 #ifdef CONFIG_SYSFS diff --git a/kernel/module.c b/kernel/module.c -index 8dc7f5e80dd8..62f9b72bf85e 100644 +index 11869408f79b..2b9204fe055f 100644 --- a/kernel/module.c +++ b/kernel/module.c -@@ -3833,3 +3833,13 @@ void module_layout(struct module *mod, +@@ -3835,3 +3835,13 @@ void module_layout(struct module *mod, } EXPORT_SYMBOL(module_layout); #endif @@ -63,7 +63,7 @@ index 8dc7f5e80dd8..62f9b72bf85e 100644 1.8.5.3 -From 3df1daaa8cd3c8450fd8fda62ff4836eddbf0f09 Mon Sep 17 00:00:00 2001 +From 806c4ee0e6484b529b88b3d0ceb49f6edf96ae11 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 8 Mar 2012 10:10:38 -0500 Subject: [PATCH 02/14] PCI: Lock down BAR access when module security is @@ -182,7 +182,7 @@ index 24750a1b39b6..fa57896b97dd 100644 1.8.5.3 -From c14a3599cdf71ccd6ea47e8b404412b8e7a5c1b3 Mon Sep 17 00:00:00 2001 +From 16ee82e2add8684e374451e6ba34be3ee41e4ef1 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Thu, 8 Mar 2012 10:35:59 -0500 Subject: [PATCH 03/14] x86: Lock down IO port access when module security is @@ -255,7 +255,7 @@ index 917403fe10da..cdf839f9defe 100644 1.8.5.3 -From ccbc02eee179074b13acc2d7dfd17835726a579a Mon Sep 17 00:00:00 2001 +From 2fd4b35393b19cde87e4770d3b85d12760e72f6a Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 08:39:37 -0500 Subject: [PATCH 04/14] ACPI: Limit access to custom_method @@ -287,7 +287,7 @@ index c68e72414a67..4277938af700 100644 1.8.5.3 -From b40f05f5ec470bc59f41ca7ce66ea09614db60ea Mon Sep 17 00:00:00 2001 +From 543d64276237adb782ec30a5dab67d0b21afc1d4 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 08:46:50 -0500 Subject: [PATCH 05/14] asus-wmi: Restrict debugfs interface when module @@ -342,7 +342,7 @@ index c5e082fb82fa..03c57fc8de8a 100644 1.8.5.3 -From bfa6f400f5e0f98772f3c77b60d8ac3d39b080a8 Mon Sep 17 00:00:00 2001 +From 6e2fec5547b597c43ca72e34729b8a402660a7c1 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Mar 2012 09:28:15 -0500 Subject: [PATCH 06/14] Restrict /dev/mem and /dev/kmem when module loading is @@ -385,7 +385,7 @@ index cdf839f9defe..c63cf93b00eb 100644 1.8.5.3 -From e399403d8b74cbbb23ead4e43b70b4d82ee00402 Mon Sep 17 00:00:00 2001 +From 358cea0a54f726fa61839b411f3f54284d4588bf Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Mon, 25 Jun 2012 19:57:30 -0400 Subject: [PATCH 07/14] acpi: Ignore acpi_rsdp kernel parameter when module @@ -401,7 +401,7 @@ Signed-off-by: Josh Boyer 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c -index 27f84af4e337..bd3ac0947890 100644 +index f7fd72ac69cf..ccdae1c8c386 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -44,6 +44,7 @@ @@ -425,7 +425,7 @@ index 27f84af4e337..bd3ac0947890 100644 1.8.5.3 -From 686268dea5fa802409d99f964005bc57d62f6b04 Mon Sep 17 00:00:00 2001 +From 89751b3ad4dea7cf5b806cd14126dd70657a9148 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Aug 2013 03:33:56 -0400 Subject: [PATCH 08/14] kexec: Disable at runtime if the kernel enforces module @@ -441,18 +441,18 @@ Signed-off-by: Matthew Garrett 1 file changed, 8 insertions(+) diff --git a/kernel/kexec.c b/kernel/kexec.c -index 45601cf41bee..d5819bb45bec 100644 +index c8380ad203bc..e6eb239f567a 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c -@@ -32,6 +32,7 @@ - #include +@@ -33,6 +33,7 @@ #include #include + #include +#include #include #include -@@ -947,6 +948,13 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, +@@ -948,6 +949,13 @@ SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, return -EPERM; /* @@ -470,7 +470,7 @@ index 45601cf41bee..d5819bb45bec 100644 1.8.5.3 -From 4a1068eb94b99cab1d31a8a87eea9aafb39bcea0 Mon Sep 17 00:00:00 2001 +From 31174421a7103571a1c3faf7ba27d4045e5fbc18 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Tue, 3 Sep 2013 11:23:29 -0400 Subject: [PATCH 09/14] uswsusp: Disable when module loading is restricted @@ -510,7 +510,7 @@ index 98d357584cd6..efe99dee9510 100644 1.8.5.3 -From 569d0384d6846dae76910d5104666f11597a6a78 Mon Sep 17 00:00:00 2001 +From ea5cf8801db979fa7d5f90ab3faf72eb22490f9b Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 8 Feb 2013 11:12:13 -0800 Subject: [PATCH 10/14] x86: Restrict MSR access when module loading is @@ -527,7 +527,7 @@ Signed-off-by: Matthew Garrett 1 file changed, 7 insertions(+) diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c -index 05266b5aae22..e2bd647f676e 100644 +index c9603ac80de5..8bef43fc3f40 100644 --- a/arch/x86/kernel/msr.c +++ b/arch/x86/kernel/msr.c @@ -103,6 +103,9 @@ static ssize_t msr_write(struct file *file, const char __user *buf, @@ -555,7 +555,7 @@ index 05266b5aae22..e2bd647f676e 100644 1.8.5.3 -From bca29272512c8646bf2feaf304a0eceb05c0d0c0 Mon Sep 17 00:00:00 2001 +From 2985684ff78972bde7ebf1e295b52afd9bea29e0 Mon Sep 17 00:00:00 2001 From: Matthew Garrett Date: Fri, 9 Aug 2013 18:36:30 -0400 Subject: [PATCH 11/14] Add option to automatically enforce module signatures @@ -591,10 +591,10 @@ index 199f453cb4de..ec38acf00b40 100644 290/040 ALL edd_mbr_sig_buffer EDD MBR signatures 2D0/A00 ALL e820_map E820 memory map table diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index 26237934ac87..e27b78bcca34 100644 +index 5b8ec0f53b57..085d5eb36361 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig -@@ -1597,6 +1597,16 @@ config EFI_MIXED +@@ -1534,6 +1534,16 @@ config EFI_MIXED If unsure, say N. @@ -687,10 +687,10 @@ index 225b0988043a..90dbfb73e11f 100644 * The sentinel is set to a nonzero value (0xff) in header.S. * diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index fa511acff7e6..aa227f68687c 100644 +index 09c76d265550..5a61d732fd5c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c -@@ -1143,6 +1143,12 @@ void __init setup_arch(char **cmdline_p) +@@ -1142,6 +1142,12 @@ void __init setup_arch(char **cmdline_p) io_delay_init(); @@ -704,10 +704,10 @@ index fa511acff7e6..aa227f68687c 100644 * Parse the ACPI tables for possible boot-time SMP configuration. */ diff --git a/include/linux/module.h b/include/linux/module.h -index 5ab9d81e3b96..83144dd56ff0 100644 +index fc9b54eb779e..7377bc851461 100644 --- a/include/linux/module.h +++ b/include/linux/module.h -@@ -191,6 +191,12 @@ const struct exception_table_entry *search_exception_tables(unsigned long add); +@@ -188,6 +188,12 @@ const struct exception_table_entry *search_exception_tables(unsigned long add); struct notifier_block; @@ -721,10 +721,10 @@ index 5ab9d81e3b96..83144dd56ff0 100644 extern int modules_disabled; /* for sysctl */ diff --git a/kernel/module.c b/kernel/module.c -index 62f9b72bf85e..dcfb07ae5e4e 100644 +index 2b9204fe055f..2b8cc2d57c16 100644 --- a/kernel/module.c +++ b/kernel/module.c -@@ -3834,6 +3834,13 @@ void module_layout(struct module *mod, +@@ -3836,6 +3836,13 @@ void module_layout(struct module *mod, EXPORT_SYMBOL(module_layout); #endif @@ -742,7 +742,7 @@ index 62f9b72bf85e..dcfb07ae5e4e 100644 1.8.5.3 -From 67ff850d16232e30c39109d29510d2a4aef34de9 Mon Sep 17 00:00:00 2001 +From b2e4ea728ccab2befbd5fe1bd834881a7dd8f34b Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 5 Feb 2013 19:25:05 -0500 Subject: [PATCH 12/14] efi: Disable secure boot if shim is in insecure mode @@ -801,7 +801,7 @@ index b00745ff398a..bf42cc5f083d 100644 1.8.5.3 -From 53645ba848224ee81978b17c5e5328dca798466f Mon Sep 17 00:00:00 2001 +From fb418c682d01c447d30b5591a591fdbf33b1334e Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 27 Aug 2013 13:28:43 -0400 Subject: [PATCH 13/14] efi: Make EFI_SECURE_BOOT_SIG_ENFORCE depend on EFI @@ -815,10 +815,10 @@ Signed-off-by: Josh Boyer 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig -index e27b78bcca34..dfd068b32cdc 100644 +index 085d5eb36361..3e8d398a976d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig -@@ -1598,7 +1598,8 @@ config EFI_MIXED +@@ -1535,7 +1535,8 @@ config EFI_MIXED If unsure, say N. config EFI_SECURE_BOOT_SIG_ENFORCE @@ -832,7 +832,7 @@ index e27b78bcca34..dfd068b32cdc 100644 1.8.5.3 -From e5b7eaf1b5d04ec739464b6e2df21c666d060c69 Mon Sep 17 00:00:00 2001 +From 87bf357dd4589cfca043ec4b641b912a088b1234 Mon Sep 17 00:00:00 2001 From: Josh Boyer Date: Tue, 27 Aug 2013 13:33:03 -0400 Subject: [PATCH 14/14] efi: Add EFI_SECURE_BOOT bit @@ -847,10 +847,10 @@ Signed-off-by: Josh Boyer 2 files changed, 3 insertions(+) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c -index aa227f68687c..c7cf7919b3c4 100644 +index 5a61d732fd5c..23fe9bf3c401 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c -@@ -1145,7 +1145,9 @@ void __init setup_arch(char **cmdline_p) +@@ -1144,7 +1144,9 @@ void __init setup_arch(char **cmdline_p) #ifdef CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE if (boot_params.secure_boot) { -- cgit 5' href='#n235'>235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
require 'test/unit'

class TestAssignment < Test::Unit::TestCase
  def test_assign
    a=[]; a[0] ||= "bar";
    assert_equal("bar", a[0])
    h={}; h["foo"] ||= "bar";
    assert_equal("bar", h["foo"])

    aa = 5
    aa ||= 25
    assert_equal(5, aa)
    bb ||= 25
    assert_equal(25, bb)
    cc &&=33
    assert_nil(cc)
    cc = 5
    cc &&=44
    assert_equal(44, cc)

    a = nil; assert_nil(a)
    a = 1; assert_equal(1, a)
    a = []; assert_equal([], a)
    a = [1]; assert_equal([1], a)
    a = [nil]; assert_equal([nil], a)
    a = [[]]; assert_equal([[]], a)
    a = [1,2]; assert_equal([1,2], a)
    a = [*[]]; assert_equal([], a)
    a = [*[1]]; assert_equal([1], a)
    a = [*[1,2]]; assert_equal([1,2], a)

    a = *[]; assert_equal([], a)
    a = *[1]; assert_equal([1], a)
    a = *[nil]; assert_equal([nil], a)
    a = *[[]]; assert_equal([[]], a)
    a = *[1,2]; assert_equal([1,2], a)
    a = *[*[]]; assert_equal([], a)
    a = *[*[1]]; assert_equal([1], a)
    a = *[*[1,2]]; assert_equal([1,2], a)

    *a = nil; assert_equal([nil], a)
    *a = 1; assert_equal([1], a)
    *a = []; assert_equal([], a)
    *a = [1]; assert_equal([1], a)
    *a = [nil]; assert_equal([nil], a)
    *a = [[]]; assert_equal([[]], a)
    *a = [1,2]; assert_equal([1,2], a)
    *a = [*[]]; assert_equal([], a)
    *a = [*[1]]; assert_equal([1], a)
    *a = [*[1,2]]; assert_equal([1,2], a)

    *a = *[]; assert_equal([], a)
    *a = *[1]; assert_equal([1], a)
    *a = *[nil]; assert_equal([nil], a)
    *a = *[[]]; assert_equal([[]], a)
    *a = *[1,2]; assert_equal([1,2], a)
    *a = *[*[]]; assert_equal([], a)
    *a = *[*[1]]; assert_equal([1], a)
    *a = *[*[1,2]]; assert_equal([1,2], a)

    a,b,*c = nil; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = 1; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = []; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = [1]; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = [nil]; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = [[]]; assert_equal([[],nil,[]], [a,b,c])
    a,b,*c = [1,2]; assert_equal([1,2,[]], [a,b,c])
    a,b,*c = [*[]]; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = [*[1]]; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = [*[1,2]]; assert_equal([1,2,[]], [a,b,c])

    a,b,*c = *[]; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = *[1]; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = *[nil]; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = *[[]]; assert_equal([[],nil,[]], [a,b,c])
    a,b,*c = *[1,2]; assert_equal([1,2,[]], [a,b,c])
    a,b,*c = *[*[]]; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = *[*[1]]; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = *[*[1,2]]; assert_equal([1,2,[]], [a,b,c])
  end

  def test_yield
    def f; yield(nil); end; f {|a| assert_nil(a)}; undef f
    def f; yield(1); end; f {|a| assert_equal(1, a)}; undef f
    def f; yield([]); end; f {|a| assert_equal([], a)}; undef f
    def f; yield([1]); end; f {|a| assert_equal([1], a)}; undef f
    def f; yield([nil]); end; f {|a| assert_equal([nil], a)}; undef f
    def f; yield([[]]); end; f {|a| assert_equal([[]], a)}; undef f
    def f; yield([*[]]); end; f {|a| assert_equal([], a)}; undef f
    def f; yield([*[1]]); end; f {|a| assert_equal([1], a)}; undef f
    def f; yield([*[1,2]]); end; f {|a| assert_equal([1,2], a)}; undef f

    def f; yield(*[1]); end; f {|a| assert_equal(1, a)}; undef f
    def f; yield(*[nil]); end; f {|a| assert_equal(nil, a)}; undef f
    def f; yield(*[[]]); end; f {|a| assert_equal([], a)}; undef f
    def f; yield(*[*[1]]); end; f {|a| assert_equal(1, a)}; undef f

    def f; yield; end; f {|*a| assert_equal([], a)}; undef f
    def f; yield(nil); end; f {|*a| assert_equal([nil], a)}; undef f
    def f; yield(1); end; f {|*a| assert_equal([1], a)}; undef f
    def f; yield([]); end; f {|*a| assert_equal([[]], a)}; undef f
    def f; yield([1]); end; f {|*a| assert_equal([[1]], a)}; undef f
    def f; yield([nil]); end; f {|*a| assert_equal([[nil]], a)}; undef f
    def f; yield([[]]); end; f {|*a| assert_equal([[[]]], a)}; undef f
    def f; yield([1,2]); end; f {|*a| assert_equal([[1,2]], a)}; undef f
    def f; yield([*[]]); end; f {|*a| assert_equal([[]], a)}; undef f
    def f; yield([*[1]]); end; f {|*a| assert_equal([[1]], a)}; undef f
    def f; yield([*[1,2]]); end; f {|*a| assert_equal([[1,2]], a)}; undef f

    def f; yield(*[]); end; f {|*a| assert_equal([], a)}; undef f
    def f; yield(*[1]); end; f {|*a| assert_equal([1], a)}; undef f
    def f; yield(*[nil]); end; f {|*a| assert_equal([nil], a)}; undef f
    def f; yield(*[[]]); end; f {|*a| assert_equal([[]], a)}; undef f
    def f; yield(*[*[]]); end; f {|*a| assert_equal([], a)}; undef f
    def f; yield(*[*[1]]); end; f {|*a| assert_equal([1], a)}; undef f
    def f; yield(*[*[1,2]]); end; f {|*a| assert_equal([1,2], a)}; undef f

    def f; yield; end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(nil); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(1); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
    def f; yield([]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield([1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
    def f; yield([nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield([[]]); end; f {|a,b,*c| assert_equal([[],nil,[]], [a,b,c])}; undef f
    def f; yield([*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield([*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
    def f; yield([*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f

    def f; yield(*[]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(*[1]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
    def f; yield(*[nil]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(*[[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(*[*[]]); end; f {|a,b,*c| assert_equal([nil,nil,[]], [a,b,c])}; undef f
    def f; yield(*[*[1]]); end; f {|a,b,*c| assert_equal([1,nil,[]], [a,b,c])}; undef f
    def f; yield(*[*[1,2]]); end; f {|a,b,*c| assert_equal([1,2,[]], [a,b,c])}; undef f
  end

  def test_return
    def r; return; end; a = r(); assert_nil(a); undef r
    def r; return nil; end; a = r(); assert_nil(a); undef r
    def r; return 1; end; a = r(); assert_equal(1, a); undef r
    def r; return []; end; a = r(); assert_equal([], a); undef r
    def r; return [1]; end; a = r(); assert_equal([1], a); undef r
    def r; return [nil]; end; a = r(); assert_equal([nil], a); undef r
    def r; return [[]]; end; a = r(); assert_equal([[]], a); undef r
    def r; return [*[]]; end; a = r(); assert_equal([], a); undef r
    def r; return [*[1]]; end; a = r(); assert_equal([1], a); undef r
    def r; return [*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r

    def r; return *[]; end; a = r(); assert_equal([], a); undef r
    def r; return *[1]; end; a = r(); assert_equal([1], a); undef r
    def r; return *[nil]; end; a = r(); assert_equal([nil], a); undef r
    def r; return *[[]]; end; a = r(); assert_equal([[]], a); undef r
    def r; return *[*[]]; end; a = r(); assert_equal([], a); undef r
    def r; return *[*[1]]; end; a = r(); assert_equal([1], a); undef r
    def r; return *[*[1,2]]; end; a = r(); assert_equal([1,2], a); undef r

    def r; return *[[]]; end; a = *r(); assert_equal([[]], a); undef r
    def r; return *[*[1,2]]; end; a = *r(); assert_equal([1,2], a); undef r

    def r; return; end; *a = r(); assert_equal([nil], a); undef r
    def r; return nil; end; *a = r(); assert_equal([nil], a); undef r
    def r; return 1; end; *a = r(); assert_equal([1], a); undef r
    def r; return []; end; *a = r(); assert_equal([], a); undef r
    def r; return [1]; end; *a = r(); assert_equal([1], a); undef r
    def r; return [nil]; end; *a = r(); assert_equal([nil], a); undef r
    def r; return [[]]; end; *a = r(); assert_equal([[]], a); undef r
    def r; return [1,2]; end; *a = r(); assert_equal([1,2], a); undef r
    def r; return [*[]]; end; *a = r(); assert_equal([], a); undef r
    def r; return [*[1]]; end; *a = r(); assert_equal([1], a); undef r
    def r; return [*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r

    def r; return *[]; end; *a = r(); assert_equal([], a); undef r
    def r; return *[1]; end; *a = r(); assert_equal([1], a); undef r
    def r; return *[nil]; end; *a = r(); assert_equal([nil], a); undef r
    def r; return *[[]]; end; *a = r(); assert_equal([[]], a); undef r
    def r; return *[1,2]; end; *a = r(); assert_equal([1,2], a); undef r
    def r; return *[*[]]; end; *a = r(); assert_equal([], a); undef r
    def r; return *[*[1]]; end; *a = r(); assert_equal([1], a); undef r
    def r; return *[*[1,2]]; end; *a = r(); assert_equal([1,2], a); undef r

    def r; return *[[]]; end; *a = *r(); assert_equal([[]], a); undef r
    def r; return *[1,2]; end; *a = *r(); assert_equal([1,2], a); undef r
    def r; return *[*[1,2]]; end; *a = *r(); assert_equal([1,2], a); undef r

    def r; return; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return nil; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return 1; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
    def r; return []; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return [1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
    def r; return [nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return [[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r
    def r; return [1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
    def r; return [*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return [*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
    def r; return [*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r

    def r; return *[]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return *[1]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
    def r; return *[nil]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return *[[]]; end; a,b,*c = r(); assert_equal([[],nil,[]], [a,b,c]); undef r
    def r; return *[1,2]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r
    def r; return *[*[]]; end; a,b,*c = r(); assert_equal([nil,nil,[]], [a,b,c]); undef r
    def r; return *[*[1]]; end; a,b,*c = r(); assert_equal([1,nil,[]], [a,b,c]); undef r
    def r; return *[*[1,2]]; end; a,b,*c = r(); assert_equal([1,2,[]], [a,b,c]); undef r

    def r; return 1, *[]; end; a,b = r(); assert_equal([1,nil], [a,b]); undef r
    def r; return 1,2,*[1]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r
    def r; return 1,2,3,*[1,2]; end; a,b = r(); assert_equal([1,2], [a,b]); undef r
  end

  def test_lambda
    f = lambda {|r,| assert_equal([], r)}
    f.call([], *[])

    f = lambda {|r,*l| assert_equal([], r); assert_equal([1], l)}
    f.call([], *[1])

    f = lambda{|x| x}
    assert_equal(42, f.call(42))
    assert_equal([42], f.call([42]))
    assert_equal([[42]], f.call([[42]]))
    assert_equal([42,55], f.call([42,55]))

    f = lambda{|x,| x}
    assert_equal(42, f.call(42))
    assert_equal([42], f.call([42]))
    assert_equal([[42]], f.call([[42]]))
    assert_equal([42,55], f.call([42,55]))

    f = lambda{|*x| x}
    assert_equal([42], f.call(42))
    assert_equal([[42]], f.call([42]))
    assert_equal([[[42]]], f.call([[42]]))
    assert_equal([[42,55]], f.call([42,55]))
    assert_equal([42,55], f.call(42,55))
  end

  def test_multi
    a,=*[1]
    assert_equal(1, a)
    a,=*[[1]]
    assert_equal([1], a)
    a,=*[[[1]]]
    assert_equal([[1]], a)

    x, (y, z) = 1, 2, 3
    assert_equal([1,2,nil], [x,y,z])
    x, (y, z) = 1, [2,3]
    assert_equal([1,2,3], [x,y,z])
    x, (y, z) = 1, [2]
    assert_equal([1,2,nil], [x,y,z])
  end

  def test_break
    a = loop do break; end; assert_nil(a)
    a = loop do break nil; end; assert_nil(a)
    a = loop do break 1; end; assert_equal(1, a)
    a = loop do break []; end; assert_equal([], a)
    a = loop do break [1]; end; assert_equal([1], a)
    a = loop do break [nil]; end; assert_equal([nil], a)
    a = loop do break [[]]; end; assert_equal([[]], a)
    a = loop do break [*[]]; end; assert_equal([], a)
    a = loop do break [*[1]]; end; assert_equal([1], a)
    a = loop do break [*[1,2]]; end; assert_equal([1,2], a)

    a = loop do break *[]; end; assert_equal([], a)
    a = loop do break *[1]; end; assert_equal([1], a)
    a = loop do break *[nil]; end; assert_equal([nil], a)
    a = loop do break *[[]]; end; assert_equal([[]], a)
    a = loop do break *[*[]]; end; assert_equal([], a)
    a = loop do break *[*[1]]; end; assert_equal([1], a)
    a = loop do break *[*[1,2]]; end; assert_equal([1,2], a)

    *a = loop do break; end; assert_equal([nil], a)
    *a = loop do break nil; end; assert_equal([nil], a)
    *a = loop do break 1; end; assert_equal([1], a)
    *a = loop do break []; end; assert_equal([], a)
    *a = loop do break [1]; end; assert_equal([1], a)
    *a = loop do break [nil]; end; assert_equal([nil], a)
    *a = loop do break [[]]; end; assert_equal([[]], a)
    *a = loop do break [1,2]; end; assert_equal([1,2], a)
    *a = loop do break [*[]]; end; assert_equal([], a)
    *a = loop do break [*[1]]; end; assert_equal([1], a)
    *a = loop do break [*[1,2]]; end; assert_equal([1,2], a)

    *a = loop do break *[]; end; assert_equal([], a)
    *a = loop do break *[1]; end; assert_equal([1], a)
    *a = loop do break *[nil]; end; assert_equal([nil], a)
    *a = loop do break *[[]]; end; assert_equal([[]], a)
    *a = loop do break *[1,2]; end; assert_equal([1,2], a)
    *a = loop do break *[*[]]; end; assert_equal([], a)
    *a = loop do break *[*[1]]; end; assert_equal([1], a)
    *a = loop do break *[*[1,2]]; end; assert_equal([1,2], a)

    *a = *loop do break *[[]]; end; assert_equal([[]], a)
    *a = *loop do break *[1,2]; end; assert_equal([1,2], a)
    *a = *loop do break *[*[1,2]]; end; assert_equal([1,2], a)

    a,b,*c = loop do break; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break nil; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break 1; end; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = loop do break []; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break [1]; end; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = loop do break [nil]; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break [[]]; end; assert_equal([[],nil,[]], [a,b,c])
    a,b,*c = loop do break [1,2]; end; assert_equal([1,2,[]], [a,b,c])
    a,b,*c = loop do break [*[]]; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break [*[1]]; end; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = loop do break [*[1,2]]; end; assert_equal([1,2,[]], [a,b,c])

    a,b,*c = loop do break *[]; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break *[1]; end; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = loop do break *[nil]; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break *[[]]; end; assert_equal([[],nil,[]], [a,b,c])
    a,b,*c = loop do break *[1,2]; end; assert_equal([1,2,[]], [a,b,c])
    a,b,*c = loop do break *[*[]]; end; assert_equal([nil,nil,[]], [a,b,c])
    a,b,*c = loop do break *[*[1]]; end; assert_equal([1,nil,[]], [a,b,c])
    a,b,*c = loop do break *[*[1,2]]; end; assert_equal([1,2,[]], [a,b,c])
  end

  def test_next
    def r(val); a = yield(); assert_equal(val, a); end
    r(nil){next}
    r(nil){next nil}
    r(1){next 1}
    r([]){next []}
    r([1]){next [1]}
    r([nil]){next [nil]}
    r([[]]){next [[]]}
    r([]){next [*[]]}
    r([1]){next [*[1]]}
    r([1,2]){next [*[1,2]]}

    r([]){next *[]}
    r([1]){next *[1]}
    r([nil]){next *[nil]}
    r([[]]){next *[[]]}
    r([]){next *[*[]]}
    r([1]){next *[*[1]]}
    r([1,2]){next *[*[1,2]]}
    undef r

    def r(val); *a = yield(); assert_equal(val, a); end
    r([nil]){next}
    r([nil]){next nil}
    r([1]){next 1}
    r([]){next []}
    r([1]){next [1]}
    r([nil]){next [nil]}
    r([[]]){next [[]]}
    r([1,2]){next [1,2]}
    r([]){next [*[]]}
    r([1]){next [*[1]]}
    r([1,2]){next [*[1,2]]}
    undef r

    def r(val); *a = *yield(); assert_equal(val, a); end
    r([[]]){next *[[]]}
    r([1,2]){next *[1,2]}
    r([1,2]){next *[*[1,2]]}
    undef r

    def r(val); a,b,*c = yield(); assert_equal(val, [a,b,c]); end
    r([nil,nil,[]]){next}
    r([nil,nil,[]]){next nil}
    r([1,nil,[]]){next 1}
    r([nil,nil,[]]){next []}
    r([1,nil,[]]){next [1]}
    r([nil,nil,[]]){next [nil]}
    r([[],nil,[]]){next [[]]}
    r([1,2,[]]){next [1,2]}
    r([nil,nil,[]]){next [*[]]}
    r([1,nil,[]]){next [*[1]]}
    r([1,2,[]]){next [*[1,2]]}
    undef r

    def r(val); a,b,*c = *yield(); assert_equal(val, [a,b,c]); end
    r([[],nil,[]]){next *[[]]}
    r([1,2,[]]){next *[1,2]}
    r([1,2,[]]){next *[*[1,2]]}
    undef r
  end

  def test_massign
    a = nil
    assert(defined?(a))
    assert_nil(a)

    # multiple asignment
    a, b = 1, 2
    assert_equal 1, a
    assert_equal 2, b

    a, b, c = 1, 2, 3
    assert_equal 1, a
    assert_equal 2, b
    assert_equal 3, c

    a = 1
    b = 2
    a, b = b, a
    assert_equal 2, a
    assert_equal 1, b

    a, = 1, 2
    assert_equal 1, a

    a, = 1, 2, 3
    assert_equal 1, a

    a, * = 1, 2, 3
    assert_equal 1, a

    a, *b = 1, 2, 3
    assert_equal 1, a
    assert_equal [2, 3], b

    # not supported yet
    #a, *b, c = 1, 2, 3, 4
    #assert_equal 1, a
    #assert_equal [2,3], b
    #assert_equal 4, c

    a = 1, 2
    assert_equal [1, 2], a

    a = [1, 2], [3, 4]
    assert_equal [[1,2], [3,4]], a

    a, (b, c), d = 1, [2, 3], 4
    assert_equal 1, a
    assert_equal 2, b
    assert_equal 3, c
    assert_equal 4, d

    *a = 1, 2, 3
    assert_equal([1, 2, 3], a)

    *a = 4
    assert_equal([4], a)

    *a = nil
    assert_equal([nil], a)

    a, b = 1
    assert_equal 1, a
    assert_nil b

    a, b = [1, 2]
    assert_equal 1, a
    assert_equal 2, b
  end

  def test_nested_massign
    (a, b), c = [[1, 2], 3]; assert_equal [1,2,3], [a,b,c]
    a, (b, c) = [[1, 2], 3]; assert_equal [[1,2], 3, nil], [a,b,c]
    a, (b, c) = [1, [2, 3]]; assert_equal [1,2,3], [a,b,c]
    (a, b), *c = [[1, 2], 3]; assert_equal [1,2,[3]], [a,b,c]
    (a,b),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,3,4,5],[a,b,c,d,e]
    (a,*b),c,(d,e,*) = [[1,2],3,[4,5]]; assert_equal [1,[2],3,4,5],[a,b,c,d,e]
    (a,b),c,(d,*e) = [[1,2,3],4,[5,6,7,8]]; assert_equal [1,2,4,5,[6,7,8]],[a,b,c,d,e]
    (a,(b1,b2)),c,(d,e) = [[1,2],3,[4,5]]; assert_equal [1,2,nil,3,4,5],[a,b1,b2,c,d,e]
    (a,(b1,b2)),c,(d,e) = [[1,[21,22]],3,[4,5]]; assert_equal [1,21,22,3,4,5],[a,b1,b2,c,d,e]
  end

  class MyObj
    def to_ary
      [[1,2],[3,4]]
    end
  end

  def test_to_ary_splat
    a, b = MyObj.new
    assert_equal [[1,2],[3,4]], [a,b]
  end

  A = 1
  B = 2
  X, Y = A, B
  class Base
    A = 3
    B = 4
  end

  def test_const_massign
    assert_equal [1,2], [X,Y]
    a, b = Base::A, Base::B
    assert_equal [3,4], [a,b]
  end
end

require_relative 'sentence'
class TestAssignmentGen < Test::Unit::TestCase
  Syntax = {
    :exp => [["0"],
             ["nil"],
             ["false"],
             ["[]"],
             ["[",:exps,"]"]],
    :exps => [[:exp],
              [:exp,",",:exps]],
    :arg => [[:exp]],
    :mrhs => [[:args,",",:arg],
              [:args,",","*",:arg],
              ["*",:arg]],
    :args => [[:arg],
              ["*",:arg],
              [:args,",",:arg],
              [:args,",","*",:arg]],
    :mlhs => [[:mlhs_basic],
              ["(",:mlhs_inner,")"]],
    :mlhs_inner => [[:mlhs_basic],
              ["(",:mlhs_inner,")"]],
    :mlhs_basic => [[:mlhs_head],
                    [:mlhs_head,:mlhs_item],
                    [:mlhs_head,"*",:mlhs_node],
                    [:mlhs_head,"*",:mlhs_node,",",:mlhs_post],
                    [:mlhs_head,"*"],
                    [:mlhs_head,"*",",",           :mlhs_post],
                    [           "*",:mlhs_node],
                    [           "*",:mlhs_node,",",:mlhs_post],
                    [           "*"],
                    [           "*",",",           :mlhs_post]],
    :mlhs_head => [[:mlhs_item,","],
                   [:mlhs_head,:mlhs_item,","]],
    :mlhs_post => [[:mlhs_item],
                   [:mlhs_post,",",:mlhs_item]],
    :mlhs_item => [[:mlhs_node],
                   ["(",:mlhs_inner,")"]],
    :mlhs_node => [["var"]],
    :xassign => [["var"," = ",:exp],
                 ["var"," = ",:mrhs],
                 [:mlhs," = ",:exp],
                 [:mlhs," = ",:mrhs]],
  }

  def rename_var(obj)
    vars = []
    r = obj.subst('var') {
      var = "v#{vars.length}"
      vars << var
      var
    }
    return r, vars
  end

  def expand_except_paren(obj)
    return obj if obj.respond_to? :to_str
    obj.expand {|s|
      !(s[0] == '(' && s[-1] == ')') &&
      !(s[0] == '[' && s[-1] == ']')
    }
  end

  def extract_single_element(ary)
    raise "not a single element array: #{ary.inspect}" if ary.length != 1
    ary[0]
  end

  def emu_assign_ary(lhs, rv, h)
    rv = rv.respond_to?(:to_ary) ? rv : [rv]
    rv = rv.dup
    a = [[]]
    lhs.each {|e|
      if e == ','
        a << []
      else
        a.last << e
      end
    }
    a.pop if a.last == []
    pre = []
    star = post = nil
    a.each {|e|
      if post
        post << e
      elsif e[0] == '*'
        star = e
        post = []
      else
        pre << e