@@ -3984,6 +3984,134 @@ TEST_P(UncheckedStatusOrAccessModelTest, AccessorCall) {
39843984 )cc" );
39853985}
39863986
3987+ TEST_P (UncheckedStatusOrAccessModelTest, PointerReceivers) {
3988+ // The following examples are not sound as there could be opaque calls between
3989+ // the ok() and the value() calls that change the StatusOr value. However,
3990+ // this is the behavior that users expect so it is here to stay.
3991+ ExpectDiagnosticsFor (R"cc(
3992+ #include "unchecked_statusor_access_test_defs.h"
3993+
3994+ void target(STATUSOR_INT* sor) {
3995+ sor->value(); // [[unsafe]]
3996+ }
3997+ )cc" );
3998+ ExpectDiagnosticsFor (R"cc(
3999+ #include "unchecked_statusor_access_test_defs.h"
4000+
4001+ void target(STATUSOR_INT* sor) {
4002+ sor->emplace(1);
4003+ sor->value();
4004+ }
4005+ )cc" );
4006+ ExpectDiagnosticsFor (R"cc(
4007+ #include "unchecked_statusor_access_test_defs.h"
4008+
4009+ void target(STATUSOR_INT* sor) {
4010+ if (sor->ok())
4011+ sor->value();
4012+ else
4013+ sor->value(); // [[unsafe]]
4014+ }
4015+ )cc" );
4016+ ExpectDiagnosticsFor (R"cc(
4017+ #include "unchecked_statusor_access_test_defs.h"
4018+
4019+ void target(STATUS* s) {
4020+ STATUSOR_INT* sor = Make<STATUSOR_INT*>();
4021+ if (!s->ok()) return;
4022+ if (*s == sor->status())
4023+ sor->value();
4024+ else
4025+ sor->value(); // [[unsafe]]
4026+ }
4027+ )cc" );
4028+ ExpectDiagnosticsFor (R"cc(
4029+ #include "unchecked_statusor_access_test_defs.h"
4030+
4031+ struct Foo {
4032+ STATUSOR_INT* sor;
4033+ };
4034+
4035+ void target(Foo foo) {
4036+ if (foo.sor->ok())
4037+ foo.sor->value();
4038+ else
4039+ foo.sor->value(); // [[unsafe]]
4040+ }
4041+ )cc" );
4042+ ExpectDiagnosticsFor (R"cc(
4043+ #include "unchecked_statusor_access_test_defs.h"
4044+
4045+ struct Foo {
4046+ STATUSOR_INT* sor;
4047+ };
4048+
4049+ void target(Foo foo) {
4050+ if (foo.sor->status().ok())
4051+ foo.sor->value();
4052+ else
4053+ foo.sor->value(); // [[unsafe]]
4054+ }
4055+ )cc" );
4056+ }
4057+
4058+ TEST_P (UncheckedStatusOrAccessModelTest, PointerReceiversWithSelfReferentials) {
4059+ // Same as PointerReceivers, but with a self-referential pointer.
4060+ ExpectDiagnosticsFor (R"cc(
4061+ #include "unchecked_statusor_access_test_defs.h"
4062+
4063+ struct Bar;
4064+ struct Foo {
4065+ STATUSOR_INT* sor;
4066+ Bar* bar;
4067+ };
4068+ struct Bar {
4069+ Foo* foo;
4070+ };
4071+
4072+ void target(Bar* bar) {
4073+ if (bar->foo->sor->status().ok())
4074+ bar->foo->sor->value();
4075+ else
4076+ bar->foo->sor->value(); // [[unsafe]]
4077+ }
4078+ )cc" );
4079+
4080+ ExpectDiagnosticsFor (R"cc(
4081+ #include "unchecked_statusor_access_test_defs.h"
4082+
4083+ struct Foo {
4084+ Foo* next;
4085+ STATUSOR_INT* sor;
4086+ };
4087+
4088+ void target(Foo* foo) {
4089+ if (foo->next->sor->status().ok())
4090+ // False positive, should be safe.
4091+ foo->next->sor->value(); // [[unsafe]]
4092+ else
4093+ foo->next->sor->value(); // [[unsafe]]
4094+ }
4095+ )cc" );
4096+ }
4097+
4098+ TEST_P (UncheckedStatusOrAccessModelTest, PointerReceiversWithUnion) {
4099+ ExpectDiagnosticsFor (R"cc(
4100+ #include "unchecked_statusor_access_test_defs.h"
4101+
4102+ union Foo {
4103+ STATUSOR_INT* sor;
4104+ };
4105+
4106+ void target(Foo foo) {
4107+ if (foo.sor->ok())
4108+ foo.sor->value();
4109+ else
4110+ foo.sor->value(); // [[unsafe]]
4111+ }
4112+ )cc" );
4113+ }
4114+
39874115TEST_P (UncheckedStatusOrAccessModelTest, PointerLike) {
39884116 ExpectDiagnosticsFor (R"cc(
39894117#include "unchecked_statusor_access_test_defs.h"
0 commit comments