@@ -467,6 +467,8 @@ namespace
467467 Capability capToIntPointer = baseFilter (myGlobalIntPointer);
468468 Capability storeData = dataFilter (&myLocalInt);
469469 bool expectCrash = anExpectedMCause.has_value ();
470+ // set target memory to NULL so we can detect if a store took place
471+ myGlobalIntPointer[0 ] = NULL ;
470472 if (expectCrash)
471473 {
472474 expectedMCause = anExpectedMCause;
@@ -480,10 +482,21 @@ namespace
480482 expectCrash ? " Expected" : " Did not expect" ,
481483 storeData,
482484 capToIntPointer);
485+ // Check whether the store happened and, if it did, what it stored.
486+ Capability targetAfterStore {myGlobalIntPointer[0 ]};
487+ if (expectCrash) {
488+ TEST_EQUAL (targetAfterStore, NULL , " target memory modified after faulting store" );
489+ } else {
490+ // all tests expect the tag to be cleared even if the store doesn't
491+ // fault, so invalidate storeData before comparing with the result.
492+ storeData.invalidate ();
493+ TEST_EQUAL (targetAfterStore, storeData, " target memory did not match expected after non-faulting store" );
494+ }
483495 }
484496
485497 void test_store_faults ()
486498 {
499+ // Faulting cases
487500 debug_log (" Attempting to store via untagged capability" );
488501 do_store_test (CauseCode::TagViolation, clear_tag_filter);
489502
@@ -499,8 +512,20 @@ namespace
499512 permission_filter<PermissionSet{Permission::Load,
500513 Permission::Store}>);
501514
502- // TODO this is no longer expected to trap -- but would be good to check
503- // tag is cleared
515+ debug_log (" Attempt to store capability via too small bounds" );
516+ do_store_test (CauseCode::BoundsViolation, restrict_bounds_filter,
517+ clear_tag_filter);
518+
519+ debug_log (" Attempt to store capability via misaligned pointer" );
520+ do_store_test (std::nullopt ,
521+ misalign_filter,
522+ clear_tag_filter,
523+ priv::MCAUSE_STORE_MISALIGNED);
524+
525+ // Non-faulting but special cases
526+
527+ // Storing a local capability via a cap without store-local is
528+ // expected to succeed, but will clear the tag of the stored data
504529 debug_log (" Attempting to store local capability in global" );
505530 do_store_test (
506531 std::nullopt ,
@@ -510,34 +535,15 @@ namespace
510535 identity_filter,
511536 std::nullopt );
512537
513- debug_log (" Attempt to store capability via too small bounds" );
514- do_store_test (
515- CauseCode::BoundsViolation, restrict_bounds_filter, clear_tag_filter);
516-
517- debug_log (" Attempt to store capability via misaligned pointer" );
518- do_store_test (std::nullopt ,
519- misalign_filter,
520- clear_tag_filter,
521- priv::MCAUSE_STORE_MISALIGNED);
522-
523538 debug_log (
524539 " Attempting to store untagged capability via data only pointer" );
525540 // Storing untagged cap via data-only cap is allowed.
541+ // Contrast with PermitStoreCapabilityViolation case above.
526542 do_store_test (
527543 std::nullopt ,
528544 permission_filter<PermissionSet{Permission::Load, Permission::Store}>,
529545 clear_tag_filter,
530546 std::nullopt );
531-
532- debug_log (" Attempting to store untagged local capability in global" );
533- // Storing untagged local cap via not-store-local cap is allowed.
534- do_store_test (
535- std::nullopt ,
536- permission_filter<PermissionSet{Permission::Load,
537- Permission::Store,
538- Permission::LoadStoreCapability}>,
539- clear_tag_filter,
540- std::nullopt );
541547 }
542548
543549 void test_restricted_load (bool invalidateData,
0 commit comments