Skip to content

Integer copy constructor incorrectly handles negative values #272

@yebing115

Description

@yebing115

Issue: Integer copy constructor incorrectly handles negative values

Description

When copying a PList::Integer object that contains a negative value, the copied object incorrectly represents the value as a large positive integer instead of preserving the original negative value.

Steps to Reproduce

#include <plist/plist++.h>
#include <string>

std::string to_xml(plist_t node) {
  std::string ret;

  char* s = nullptr;
  uint32_t len = 0;
  if (plist_to_xml(node, &s, &len) != PLIST_ERR_SUCCESS) {
    return ret;
  }

  ret.append(s, len);

  plist_mem_free(s);

  return ret;
}

int main() {
  int64_t v = -1;
  PList::Integer i1(v);
  PList::Integer i2(i1);  // Copy constructor

  printf("i1 xml:\n%s\n", to_xml(i1.GetPlist()).c_str());
  printf("i2 xml:\n%s\n", to_xml(i2.GetPlist()).c_str());

  return 0;
}

Compile and run:

clang++ -std=c++11 -lplist++-2.0 -lplist-2.0  test.cpp -o test
./test

Expected Behavior

Both i1 and i2 should produce the same XML representation:

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<integer>-1</integer>
</plist>

Actual Behavior

i1 produces the correct XML, but i2 (the copy) produces:

<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">
<plist version=\"1.0\">
<integer>18446744073709551615</integer>
</plist>

This happens because 18446744073709551615 is the unsigned representation of -1 in a 64-bit two's complement integer.

Root Cause

In the copy constructor for PList::Integer, the code was using plist_set_uint_val with GetValue(), which converts the negative signed integer to an unsigned integer, causing the value to wrap around to a large positive number.

Fix

The fix replaces the problematic code in the copy constructor with a proper node copy:

// Before (problematic):
plist_set_uint_val(_node, i.GetValue());

// After (fixed):
plist_free(_node);
_node = plist_copy(i.GetPlist());

This ensures that all attributes of the original node, including its sign, are properly preserved in the copy.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions