Jump to content

Syreldar

Honorable Member
  • Posts

    1401
  • Joined

  • Last visited

  • Days Won

    40
  • Feedback

    100%

Syreldar last won the day on September 13 2025

Syreldar had the most liked content!

About Syreldar

  • Birthday 12/22/1997

Informations

  • Gender
    Male
  • Country
    Italy
  • Nationality
    Italian

Recent Profile Visitors

20929 profile views

Syreldar's Achievements

Veteran

Veteran (13/16)

  • Well Followed Rare
  • Reacting Well
  • Dedicated
  • Very Popular Rare
  • One Year In

Recent Badges

2.7k

Reputation

  1. Very useful, many thanks for the heads-up. Something to point out is that the problem is not the destructor by itself as much as it is the combination of an owning raw pointer plus compiler-generated memberwise copying. A destructor still allows implicit copy operations, but prevents implicit move operation. Also, In copy assignment, saying the destructor does not run is.. technically true, but slightly imprecise: assignment never invokes the destination object's destructor. The bug is that its currently owned buffer is overwritten without an explicit buffer_delete, creating a leak before the eventual double-return/corruption. The analysis is accurate. After the same pooled buffer is deleted twice: pool[pi] = b; b->next = b; The first later buffer_new() returns b while leaving pool[pi] still pointing at it, meaning it resets b->next to nullptr and the second buffer_new() then returns that exact same b again. So two apparently separate owners receive one allocation. The LS result in the mock is expected, but it is not directly detecting the double-return. x and y are raw pointers that are never passed to buffer_delete; because both refer to the same allocation, LS reports one buffer object plus its 8192-byte payload as leaked. Simply adding assert(x != y) or something similiar makes the allocator corruption visible immediately. Mock: [Hidden Content] For a prevention-only fix, deleting copies and implementing moves is the right choice: TEMP_BUFFER(const TEMP_BUFFER&) = delete; TEMP_BUFFER& operator=(const TEMP_BUFFER&) = delete; TEMP_BUFFER(TEMP_BUFFER&& other) noexcept : buf(std::exchange(other.buf, nullptr)) , forceDelete(std::exchange(other.forceDelete, false)) { } TEMP_BUFFER& operator=(TEMP_BUFFER&& other) noexcept { if (this != &other) { buffer_delete(buf); buf = std::exchange(other.buf, nullptr); forceDelete = std::exchange(other.forceDelete, false); } return *this; } but the deep-copy assignment example you proposed has one meaningful weakness: it deletes the current buffer before allocating and filling the replacement. If allocation or buffer_write can fail, buf may remain dangling or the object may be left partially modified. A copy-and-swap approach is preferable: void swap(TEMP_BUFFER& other) noexcept { using std::swap; swap(buf, other.buf); swap(forceDelete, other.forceDelete); } TEMP_BUFFER& operator=(const TEMP_BUFFER& other) { if (this != &other) { TEMP_BUFFER copy(other); swap(copy); } return *this; } That is only safe if the copy constructor itself correctly handles allocation/write failure according to the real buffer_new and buffer_write contracts, and the deep-copy constructor must preserve every semantically relevant buffer field. Copying only write_point_pos is fine only if TEMP_BUFFER intentionally represents a fresh writable snapshot. If it can wrap a partly-read packet, it should also preserve read position and any other state that affects interpretation. If TEMP_BUFFER has unique ownership and no meaningful use case where you have to duplicate a buffer, making it move-only is the better design imo. struct TEMP_BUFFER { LPBUFFER buf{nullptr}; bool forceDelete{false}; TEMP_BUFFER(const TEMP_BUFFER&) = delete; TEMP_BUFFER& operator=(const TEMP_BUFFER&) = delete; TEMP_BUFFER(TEMP_BUFFER&& other) noexcept : buf(std::exchange(other.buf, nullptr)) , forceDelete(std::exchange(other.forceDelete, false)) { } TEMP_BUFFER& operator=(TEMP_BUFFER&& other) noexcept { if (this != &other) { buffer_delete(buf); buf = std::exchange(other.buf, nullptr); forceDelete = std::exchange(other.forceDelete, false); } return *this; } ~TEMP_BUFFER() { buffer_delete(buf); } }; Copy semantics are only required where code genuinely needs an independent duplicate, for example: TEMP_BUFFER b = a; Passing an lvalue TEMP_BUFFER by value. Storing it in an API or container operation that copies elements. Returning or assigning from an lvalue where a move is not requested. Normal return-by-value code does not usually require copying because NRVO or move construction handles it. Standard containers can also hold move-only types, provided the element is movable and preferably noexcept movable.
  2. The motion files for the boss on the serverside probably got a degree of knockback, while your clientsided ones don't. The server thinks you moved, so the boss moves with you, but doesn't reflect the change on the client because of this mismatch. When you move, you refresh your position, so the boss comes back and the cycle repeats itself.
  3. We already have mysql_direct_query. every modern server pretty much uses this btw.
  4. item_proto is read from the locale in 99.99% of the cases. Dunno why you would have it in your root.
  5. You only need to change those, so if it doesn't work, either: 1. The tool doesn't work. 2. You didn't update your current proto with the new one after generating it. 3. You didn't repack the file after updating it. 4. Your client is reading a different proto from a different path (could be if you're using multilanguage)
  6. ..As I said, values working in game but not on the tooltip (the preview you mentioned) can only mean the clientside proto wasn't updated properly to reflect the value changes you did serverside.
  7. That's not how it works. The client wouldn't start if your proto wasn't using the proper proto structure your binary reads, not if the items have mismatching values in their columns compared to the server.
  8. It means the clientsided itemproto doesn't have the change you made.
  9. I'm gonna hold your hand when I say this, but the old one was a bug.
  10. Literally just add setdelay(0) at the beginning of say_title function, in questlib.lua. It's not necessary to overcomplicate things.
  11. This is not a turkish forum. While the topic is surely appreciated, please rewrite it in English.
  12. The /warp gm command does not include an index, just global coordinates, meaning you don't warp to the dungeon (3580000~3589999), but to the normal map (358). You get thrown out because there's probably an internal check to throw you out of the dungeon map if you're in the normal version of it (so not in a dungeon instance). It's a very common thing to have in dungeon systems/quests, since you're not supposed to be in the normal version of the dungeon map ever.
  13. If you warp to the dungeon normally and you immediately get kicked out, I'd wager the game doesn't know where to place you, which usually happens when you place a dungeon map in more than 1 core per ch, ch99 included. Each map, dungeons included, must only be located in the MAP_ALLOW of a single core for each channel. Dungeons are usually located (and must, unless the entrance is in their map itself, like the Demon Tower) in the same MAP_ALLOW where the map they are entered from is.
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.