Skip to content
This repository was archived by the owner on Dec 6, 2024. It is now read-only.

Commit 61f186a

Browse files
authored
Fix use-after-free if prerequisite has null offVariation (#214)
* Fix null pointer causing segfault within event processor * Add unit test for use-after-free * Fix memory leak due to failure to clear LDDetails
1 parent 0cecc8d commit 61f186a

File tree

3 files changed

+89
-0
lines changed

3 files changed

+89
-0
lines changed

src/evaluate.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,9 @@ static LDBoolean addValue(
200200
LD_ASSERT(o_error);
201201

202202
if(!getValue(flag, result, index, o_error, &validatedVariationIndex)) {
203+
204+
LDDetailsClear(details);
205+
203206
*result = NULL;
204207
details->hasVariation = LDBooleanFalse;
205208
details->reason = LD_ERROR;

src/variations.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ variation(
329329
detailsRef->extra.errorKind = LD_MALFORMED_FLAG;
330330

331331
LDJSONFree(subEvents);
332+
subEvents = NULL;
332333

333334
/* In this case the value will be null, so after LDi_processEvaluation the value will be checked,
334335
* and then it will move on to the error condition. */

tests/test-variations.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,88 @@ TEST_F(VariationsFixture, OffWithUndefinedOffVariation) {
385385
LDClientClose(client);
386386
LDDetailsClear(&details);
387387
}
388+
389+
390+
TEST_F(VariationsFixture, TestNullOffVariationInPrerequisiteDoesNotCauseUseAfterFree) {
391+
struct LDJSON *flag;
392+
struct LDDetails details;
393+
struct LDClient *client;
394+
struct LDUser *user = LDUserNew("foo");
395+
396+
ASSERT_TRUE(client = makeTestClient());
397+
398+
LDDetailsInit(&details);
399+
400+
ASSERT_TRUE(flag = LDNewObject());
401+
ASSERT_TRUE(LDObjectSetKey(flag, "clientSide", LDNewBool(LDBooleanFalse)));
402+
ASSERT_TRUE(LDObjectSetKey(flag, "debugEventsUntilDate", LDNewNull()));
403+
ASSERT_TRUE(LDObjectSetKey(flag, "deleted", LDNewBool(LDBooleanFalse)));
404+
ASSERT_TRUE(LDObjectSetKey(flag, "key", LDNewText("streaming.03.featureKey")));
405+
ASSERT_TRUE(LDObjectSetKey(flag, "on", LDNewBool(LDBooleanTrue)));
406+
ASSERT_TRUE(LDObjectSetKey(flag, "salt", LDNewText("")));
407+
ASSERT_TRUE(LDObjectSetKey(flag, "offVariation", LDNewNull()));
408+
ASSERT_TRUE(LDObjectSetKey(flag, "trackEvents", LDNewBool(LDBooleanTrue)));
409+
ASSERT_TRUE(LDObjectSetKey(flag, "trackEventsFallthrough", LDNewBool(LDBooleanFalse)));
410+
ASSERT_TRUE(LDObjectSetKey(flag, "targets", LDNewArray()));
411+
ASSERT_TRUE(LDObjectSetKey(flag, "rules", LDNewArray()));
412+
ASSERT_TRUE(LDObjectSetKey(flag, "version", LDNewNumber(0)));
413+
414+
415+
struct LDJSON *variations = LDNewArray();
416+
ASSERT_TRUE(LDArrayPush(variations, LDNewText("A")));
417+
ASSERT_TRUE(LDArrayPush(variations, LDNewText("B")));
418+
419+
ASSERT_TRUE(LDObjectSetKey(flag, "variations", variations));
420+
421+
struct LDJSON *fallthrough;
422+
ASSERT_TRUE(fallthrough = LDNewObject());
423+
ASSERT_TRUE(LDObjectSetKey(fallthrough, "variation", LDNewNumber(0)));
424+
ASSERT_TRUE(LDObjectSetKey(flag, "fallthrough", fallthrough));
425+
426+
struct LDJSON *prerequisites = LDNewArray();
427+
struct LDJSON *prereq = LDNewObject();
428+
ASSERT_TRUE(LDObjectSetKey(prereq, "key", LDNewText("streaming.03.prereqFeatureKey")));
429+
ASSERT_TRUE(LDObjectSetKey(prereq, "variation", LDNewNumber(0)));
430+
ASSERT_TRUE(LDArrayPush(prerequisites, prereq));
431+
432+
ASSERT_TRUE(LDObjectSetKey(flag, "prerequisites", prerequisites));
433+
434+
struct LDJSON *prerequisite = LDNewObject();
435+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "clientSide", LDNewBool(LDBooleanFalse)));
436+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "debugEventsUntilDate", LDNewNull()));
437+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "deleted", LDNewBool(LDBooleanFalse)));
438+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "key", LDNewText("streaming.03.prereqFeatureKey")));
439+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "offVariation", LDNewNull()));
440+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "on", LDNewBool(LDBooleanFalse)));
441+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "prerequisites", LDNewArray()));
442+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "rules", LDNewArray()));
443+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "salt", LDNewText("")));
444+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "trackEvents", LDNewBool(LDBooleanTrue)));
445+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "trackEventsFallthrough", LDNewBool(LDBooleanFalse)));
446+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "targets", LDNewArray()));
447+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "version", LDNewNumber(0)));
448+
449+
struct LDJSON *pfallthrough;
450+
ASSERT_TRUE(pfallthrough = LDNewObject());
451+
ASSERT_TRUE(LDObjectSetKey(pfallthrough, "variation", LDNewNumber(0)));
452+
ASSERT_TRUE(LDObjectSetKey(prerequisite, "fallthrough", pfallthrough));
453+
454+
struct LDJSON *pvariations = LDNewArray();
455+
LDArrayPush(pvariations, LDNewText("first"));
456+
LDArrayPush(pvariations, LDNewText("second"));
457+
458+
LDObjectSetKey(prerequisite, "variations", pvariations);
459+
460+
ASSERT_TRUE(LDStoreInitEmpty(client->store));
461+
462+
LDStoreUpsert(client->store, LD_FLAG, prerequisite);
463+
LDStoreUpsert(client->store, LD_FLAG, flag);
464+
465+
char *result = LDStringVariation(client, user, "streaming.03.featureKey", "default", &details);
466+
467+
LDUserFree(user);
468+
LDDetailsClear(&details);
469+
LDFree(result);
470+
LDClientClose(client);
471+
472+
}

0 commit comments

Comments
 (0)