Skip to content

feat(nft): move NFT tracking helpers from jsartoolkitNFT into WebARKitNFT (#75) - #76

Merged
kalwalt merged 11 commits into
devfrom
feat/issue-75-webarkit-nft
Oct 6, 2026
Merged

kalwalt merged 11 commits into
devfrom
feat/issue-75-webarkit-nft

Conversation

@kalwalt

@kalwalt kalwalt commented Oct 6, 2026

Copy link
Copy Markdown
Member

Closes #75 (WebARKitLib side; the jsartoolkitNFT switch-over follows in a separate PR and resolves webarkit/jsartoolkitNFT#453).

Summary

  • Imports trackingMod, trackingMod2d, trackingSub, markerDecompress and NFTMarkerState from jsartoolkitNFT/emscripten into WebARKit/WebARKitTrackers/WebARKitNFT/ (headers under include/WebARKitTrackers/WebARKitNFT/).
  • New CMake options in WebARKit/CMakeLists.txt:
    • WEBARKIT_BUILD_OPTICAL (ON, default): the existing OpenCV WebARKitLib target, unchanged
    • WEBARKIT_BUILD_NFT (OFF): WebARKitNFT static library, no OpenCV; also compiles the ARToolKit5 sources it needs (AR, ARICP, AR2, KPM, ARUtil + minizip), lists mirror jsartoolkitNFT/tools/makem.js
    • WEBARKIT_NFT_THREADS (OFF): adds trackingSub + pthreads
  • Fixes in the imported code:
    • ar2Tracking2dSub renamed to ar2Tracking2dSubMod (public here, static in AR2/tracking2d.c)
    • markerDecompress.c: dropped unused <emscripten.h>, <zlib/zlib.h> → <zlib.h>, include guard; returns -1 instead of calling exit() on errors
    • ar2CreateHandleSubMod now initialises icpHandle/cparamLT (deleting a handle created with it segfaulted natively)
  • lib/SRC/KPM/FreakMatcher: added missing <limits> / <unordered_map> includes, needed for GCC 13 / libstdc++. ⚠️ This touches the vendored ARToolKit5 sources: two include lines, no behaviour change.
  • New tests/webarkit_nft_test.cc (6 tests), wired into CI (zlib1g-dev added). README section on the NFT helpers.

Test plan

  • Native (Ubuntu 24.04, GCC 13): webarkit_nft_test 6/6, webarkit_test 28/28
  • Emscripten 4.0.17: WebARKitNFT builds with threads on; smoke binary links and runs
  • .zft decompression output byte-identical to jsartoolkitNFT's original markerDecompress.c (examples/DataNFT/zft/pinball.zft)
  • CI on this PR
  • jsartoolkitNFT builds and examples against this branch (follow-up PR)

🤖 Generated with Claude Code

kalwalt and others added 8 commits October 6, 2026 00:12
Copy trackingMod, trackingMod2d, trackingSub, markerDecompress and
NFTMarkerState from jsartoolkitNFT/emscripten (master) into
WebARKit/WebARKitTrackers/WebARKitNFT. Local includes now use
<WebARKitTrackers/WebARKitNFT/...>. No functional changes; build
integration and fixes follow in separate commits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- rename ar2Tracking2dSub to ar2Tracking2dSubMod: it is public here but
  static in AR2/tracking2d.c
- markerDecompress.c: drop unused <emscripten.h>, use <zlib.h>
- markerDecompress.h: add include guard

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#75)

- WEBARKIT_BUILD_OPTICAL (ON): the existing OpenCV WebARKitLib target
- WEBARKIT_BUILD_NFT (OFF): static WebARKitNFT library with the NFT
  helpers plus the AR, ARICP, AR2, KPM and ARUtil sources they need
  (lists mirror jsartoolkitNFT/tools/makem.js); no OpenCV
- WEBARKIT_NFT_THREADS (OFF): adds trackingSub and ARUtil/thread_sub

Emscripten uses the libjpeg/zlib ports; native builds use find_package.
Built with emsdk 4.0.17; linked and smoke-tested with threads on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
decompressMarkers() and extractDataAndSave() killed the whole process on a missing or malformed .zft. They now free their buffers and return -1; extractDataAndSave() returns int. Callers in jsartoolkitNFT already ignore the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The function is public, but left icpHandle uninitialised, so ar2DeleteHandleMod() freed a garbage pointer on a handle made with it directly (segfault on native builds; wasm memory starts zeroed, so it went unnoticed).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FreakMatcher relied on libc++ pulling them in transitively; GCC 13 (libstdc++) fails without them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- webarkit_nft_test: markerDecompress (round trip, missing file, malformed data), NFTMarkerState defaults, ar2 handle create/delete, trackingSub worker start/quit
- WebARKitNFT also builds the minizip sources file_utils.c needs (crypt, ioapi, unzip, zip), with USE_FILE32API on Emscripten
- CI installs zlib1g-dev and runs webarkit_nft_test

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Move NFT tracking helpers into an independent WebARKitNFT library

✨ Enhancement 🐞 Bug fix 🧪 Tests ⚙️ Configuration changes 📝 Documentation 🕐 40+ Minutes

Grey Divider

AI Description

• Bring NFT tracking and marker-decompression helpers into WebARKit ahead of the jsartoolkitNFT
 switch-over.
• Add an optional, OpenCV-free NFT library while preserving the default optical build.
• Fix native portability and handle cleanup; add NFT tests, CI coverage, and build documentation.
Diagram

graph TD
  Options["CMake options"] --> NFT["WebARKitNFT"] --> Helpers["NFT helpers"] --> ARTK["ARToolKit5 sources"]
  NFT --> JPEG["JPEG and zlib"]
  NFT --> Threads["Optional pthreads"]
  Options --> Optical["WebARKitLib"] --> OpenCV["OpenCV"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extract a reusable ARToolKit5 core target
  • ➕ Could centralize the ARToolKit5 source list for future consumers.
  • ➖ Requires broader build-system changes before the jsartoolkitNFT switch-over.
  • ➖ Adds migration and link-compatibility work beyond this PR.

Recommendation: Keep the isolated WebARKitNFT target for this incremental move: it avoids OpenCV and leaves the default optical build intact. Consider a shared ARToolKit5 core target if subsequent consumers need the same source list.

Files changed (16) +2023 / -5

Enhancement (8) +1788 / -0
NFTMarkerState.hExpose per-marker NFT tracking state +22/-0

Expose per-marker NFT tracking state

• Adds a C++ structure for a marker's tracking status, pose, error, and filter state. The PR does not yet switch bindings to this structure.

WebARKit/WebARKitTrackers/WebARKitNFT/include/WebARKitTrackers/WebARKitNFT/NFTMarkerState.h

markerDecompress.hExpose marker decompression functions +26/-0

Expose marker decompression functions

• Declares the .zft decompression and file helpers with C++ linkage compatibility and an include guard.

WebARKit/WebARKitTrackers/WebARKitNFT/include/WebARKitTrackers/WebARKitNFT/markerDecompress.h

trackingMod.hExpose modified AR2 tracking APIs +83/-0

Expose modified AR2 tracking APIs

• Declares the single-threaded tracking, handle lifecycle, and renamed 2D tracking functions under the WebARKitNFT include path.

WebARKit/WebARKitTrackers/WebARKitNFT/include/WebARKitTrackers/WebARKitNFT/trackingMod.h

trackingSub.hExpose threaded KPM detection APIs +95/-0

Expose threaded KPM detection APIs

• Declares worker lifecycle functions, a bounded multi-page result type, and a legacy single-result interface.

WebARKit/WebARKitTrackers/WebARKitNFT/include/WebARKitTrackers/WebARKitNFT/trackingSub.h

markerDecompress.cImport native-compatible .zft decompression +203/-0

Import native-compatible .zft decompression

• Unpacks compressed marker content into .iset, .fset, and .fset3 files using zlib. Removes the Emscripten-only include and returns errors for missing or malformed input instead of terminating the process.

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c

trackingMod.cImport single-threaded AR2 tracking +913/-0

Import single-threaded AR2 tracking

• Adds modified AR2 handle management and tracking, including feature selection and pose estimation. Initializes handle pointers so a handle created without camera parameters can be deleted natively.

WebARKit/WebARKitTrackers/WebARKitNFT/trackingMod.c

trackingMod2d.cImport 2D feature matching without symbol collision +216/-0

Import 2D feature matching without symbol collision

• Adds the modified AR2 template-matching routine as ar2Tracking2dSubMod, avoiding a name collision with the vendored AR2 source.

WebARKit/WebARKitTrackers/WebARKitNFT/trackingMod2d.c

trackingSub.cImport the threaded KPM detection worker +230/-0

Import the threaded KPM detection worker

• Adds asynchronous marker matching with bounded multi-page results and a best-match legacy interface. Retrieves the KPM result array after each match to avoid retaining a pointer that marker loading can invalidate.

WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c

Bug fix (2) +3 / -0
visual_database_facade.cppInclude the unordered-map dependency explicitly +1/-0

Include the unordered-map dependency explicitly

• Adds the standard-library include needed to compile the vendored matcher with GCC 13.

lib/SRC/KPM/FreakMatcher/facade/visual_database_facade.cpp

hamming.hInclude the numeric-limits dependency explicitly +2/-0

Include the numeric-limits dependency explicitly

• Adds the standard-library include needed to compile the vendored matcher with GCC 13.

lib/SRC/KPM/FreakMatcher/math/hamming.h

Documentation (1) +25 / -1
README.mdDocument NFT helpers and build options +25/-1

Document NFT helpers and build options

• Describes the public helper headers, library dependencies, CMake switches, and an Emscripten NFT build command. Adds the NFT test binary to the testing documentation.

README.md

Other (5) +207 / -4
test.ymlRun NFT tests in native CI +3/-3

Run NFT tests in native CI

• Installs zlib development headers and runs the new NFT test binary after the existing optical tests.

.github/workflows/test.yml

CMakeLists.txtMake optical and NFT builds selectable +11/-0

Make optical and NFT builds selectable

• Adds an opt-in NFT subdirectory and a switch to skip the existing optical target and its OpenCV setup.

WebARKit/CMakeLists.txt

CMakeLists.txtDefine the OpenCV-free WebARKitNFT target +96/-0

Define the OpenCV-free WebARKitNFT target

• Builds the imported helpers with their required ARToolKit5 sources. Configures native or Emscripten JPEG and zlib dependencies, with optional threading support.

WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt

CMakeLists.txtBuild and register threaded NFT tests +9/-1

Build and register threaded NFT tests

• Enables the NFT target and worker for the test build, links a new GoogleTest executable, and registers it alongside the existing suite.

tests/CMakeLists.txt

webarkit_nft_test.ccCover NFT helper smoke and error paths +88/-0

Cover NFT helper smoke and error paths

• Adds six tests for .zft extraction and errors, marker-state defaults, AR2 handle cleanup, and KPM worker startup and shutdown.

tests/webarkit_nft_test.cc

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Oct 6, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Default NFT builds fail to link tracking ✓ Resolved
Description
WebARKitNFT includes the native AR2 handle and tracking sources but compiles thread_sub.c only
when WEBARKIT_NFT_THREADS is enabled. With the default option off, consumers using the included
native AR2 APIs encounter unresolved thread utility symbols.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[R56-58]

+if(WEBARKIT_NFT_THREADS)
+  list(APPEND ARUTIL_SOURCES ${ARTK_SRC}/ARUtil/thread_sub.c)
+  list(APPEND NFT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/trackingSub.c)
Evidence
The new target includes handle.c and tracking.c unconditionally but includes thread_sub.c only
under the default-OFF option. Native handle.c calls threadInit, threadWaitQuit, and
threadFree; native tracking.c calls threadStartSignal and threadEndWait.

WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[5-5]
WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[26-31]
WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[56-59]
lib/SRC/AR2/handle.c[95-135]
lib/SRC/AR2/tracking.c[128-138]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The default NFT target includes native AR2 sources that require thread utility symbols, but omits their implementation.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[26-31]
- WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt[56-59]
## Recommended Fix
Include and link the thread utilities required by native AR2 regardless of the optional KPM worker setting, or omit the native AR2 APIs that require them.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Invalid archives read beyond the buffer ✓ Resolved
Description
decompressMarkers() ignores the inflate result and passes a fixed-size output buffer to
extractDataAndSave() without terminating it as a string. A truncated, invalid, or oversized stream
reaches strstr() with incomplete or non-terminated data, which can read beyond that buffer.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[R63-69]

+    inflateInit(&infstream);
+    inflate(&infstream, Z_NO_FLUSH);
+    inflateEnd(&infstream);
+
+    free(in);
+
+    int result = extractDataAndSave(c, outTemp);
Evidence
The 4 MiB allocation is also the entire avail_out; neither zlib status nor total_out is checked
before extraction. Extraction uses C-string searches that require a terminator.

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[25-25]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[54-69]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[100-125]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Inflation does not establish that the parser receives a complete, NUL-terminated string within the allocated output buffer.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[25-25]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[54-69]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[100-128]
## Recommended Fix
Check zlib initialization and inflation status, handle output exhaustion, and parse using the validated output length or reserve space and append a terminator before any string search.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unpacking can delete an unrelated file ✓ Resolved
Description
decompressMarkers() builds its removal path with nameConcat(src, "zft"), whereas openZFT()
opens src followed by .zft. If a file named srczft exists, unpacking deletes that file before
validating the archive and leaves the actual input in place.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[R50-51]

+    char *tempName = nameConcat(src, ext);
+    remove(tempName);
Evidence
openZFT() formats the opened path as %s.%s, while nameConcat() joins its arguments without a
separator and its result is passed to remove().

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[27-27]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[50-52]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[182-185]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[194-202]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The removal path omits the dot in the archive extension and can name another file.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[27-27]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[50-52]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[174-189]
## Recommended Fix
Use the same path construction for opening and any intended removal, and perform removal only after successful extraction; otherwise omit the removal.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View high (2)
4. Unwritable destinations crash unpacking ✓ Resolved
Description
extractDataAndSave() passes the results of its three fopen() calls directly to fwrite()
without checking for failure. A nonexistent or unwritable output directory can therefore crash the
caller; failed writes or closes can instead leave incomplete files while the function returns
success.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[R139-143]

+    char *isetName = nameConcat(name, ".iset");
+    tempIset = fopen(isetName, "w");
+    fwrite(iset_contentHex, iset_content_size, 1, tempIset);
+    // printf(iset_contentHex);
+    fclose(tempIset);
Evidence
Each output open is immediately followed by an unchecked write, and the function returns zero after
all three writes regardless of their results.

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[139-143]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[152-155]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[164-171]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Output file creation and writing failures are not handled, despite the extraction API returning an error code.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[135-171]
## Recommended Fix
Check each allocation, open, write, and close before proceeding; release resources and return an error on failure, and avoid leaving a partially extracted marker set.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Malformed marker fields can crash extraction ✓ Resolved
Description
extractDataAndSave() subtracts delimiter positions to form the fset and fset3 sizes but
validates only the iset size. If delimiters occur out of order or an earlier "} is found, a
negative size reaches malloc() and strncpy() after conversion to an unsigned size.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[R119-128]

+    int fset_content_size = fset3_initial_index - fset_final_index;
+
+    char *endOfStr = strstr(str, "\"}");
+    if (endOfStr == NULL) {
+        ARLOGe("Error: end of string not found.\n");
+        return -1;
+    }
+    int endPos = endOfStr - str;
+
+    int fset3_content_size = endPos - fset3_final_index;
Evidence
The fset size is calculated from two independently located delimiters, and the fset3 size from
an independently located terminator. Only iset_content_size has a nonpositive-size check before
the later sizes are passed to allocation and copying.

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[100-128]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[130-135]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[148-149]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[160-161]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Malformed marker field ordering can produce negative content lengths that are used as allocation and copy sizes.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[98-135]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[148-165]
## Recommended Fix
Verify the ordered boundaries and positive lengths of all three fields before allocating or writing any output; reject malformed content with `-1`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. Windows marker files can be corrupted ✓ Resolved
Description
extractDataAndSave() opens all three extracted marker files in text mode using "w". On Windows,
newline translation can change their bytes even though the AR2 readers open these files in binary
mode and read binary fields.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[R139-141]

+    char *isetName = nameConcat(name, ".iset");
+    tempIset = fopen(isetName, "w");
+    fwrite(iset_contentHex, iset_content_size, 1, tempIset);
Evidence
The new extractor uses text-mode output for .iset, .fset, and .fset3. The repository's AR2
image-set and feature-set readers open those files with "rb" and read binary values.

WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[139-141]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[152-154]
WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[164-166]
lib/SRC/AR2/imageSet.c[92-106]
lib/SRC/AR2/featureSet.c[49-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Text-mode output can alter the bytes of marker files on Windows.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[139-140]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[152-153]
- WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c[164-165]
## Recommended Fix
Open every extracted marker file with `"wb"` so its bytes match the archive content on all platforms.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. Overlapping scans race on image data ✓ Resolved
Description
trackingInitStart() overwrites the worker's shared image buffer and signals another job without
checking whether one is active or pending. Calling it twice before collecting a result can change a
frame while kpmMatching() reads it and can overlap result production with result retrieval.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[R122-123]

+    memcpy( trackingInitHandle->imageLumaPtr, imageLumaPtr, trackingInitHandle->imageSize );
+    threadStartSignal( threadHandle );
Evidence
trackingInitStart() copies without a busy check; the worker reads that buffer during matching and
writes shared results. The thread utility's start signal merely sets a pending flag, and its
completion synchronization does not protect the image or result buffers.

WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[117-123]
WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[137-145]
WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[204-225]
lib/SRC/ARUtil/thread_sub.c[91-101]
lib/SRC/ARUtil/thread_sub.c[181-203]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The public start API allows a new frame to overwrite data used by an unfinished scan.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[108-125]
- WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[128-145]
- WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[204-225]
## Recommended Fix
Reject or safely queue starts while a scan is active or its results await collection. Synchronize image copying and result access with the worker state.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Failed allocation can stall worker shutdown ✓ Resolved
Description
trackingInitInit() starts its thread without checking whether allocation of imageLumaPtr
succeeded. If that allocation fails, the worker exits before entering its start-wait loop, while
trackingInitQuit() waits for a quit acknowledgement that the worker can no longer send.
Code

WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[R100-104]

+    trackingInitHandle->imageSize = kpmHandleGetXSize(kpmHandle) * kpmHandleGetYSize(kpmHandle);
+    trackingInitHandle->imageLumaPtr  = (ARUint8 *)malloc(trackingInitHandle->imageSize);
+    trackingInitHandle->resultNum = 0;
+
+    threadHandle = threadInit(0, trackingInitHandle, trackingInitMain);
Evidence
The unchecked allocation is passed to a newly started worker. A null image pointer makes that worker
return, whereas quit waits until threadStartWait() sets endF to 2.

WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[97-105]
WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[67-83]
WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[196-205]
lib/SRC/ARUtil/thread_sub.c[91-105]
lib/SRC/ARUtil/thread_sub.c[247-252]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
An unchecked image-buffer allocation can leave a worker handle whose thread exits without acknowledging shutdown.
## Fix Focus Areas
- WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[97-105]
- WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c[196-205]
## Recommended Fix
Return an initialization error and free the tracking handle if image allocation fails, before calling `threadInit`; also clean up both allocations if thread creation fails.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can add REVIEW.md to your repo root and Qodo follows it on every PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/CMakeLists.txt
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c Outdated
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c Outdated
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c Outdated
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c Outdated
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/markerDecompress.c Outdated
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c
Comment thread WebARKit/WebARKitTrackers/WebARKitNFT/trackingSub.c
@kalwalt kalwalt self-assigned this Oct 6, 2026
@kalwalt kalwalt added enhancement New feature or request C/C++ code concerning the C/C++ code design and improvements Emscripten tests native-linux labels Oct 6, 2026
kalwalt and others added 3 commits October 6, 2026 14:46
AR2 handle.c and tracking.c call threadInit()/threadStartSignal() whatever WEBARKIT_NFT_THREADS says, so thread_sub.c is now always compiled and native builds always link Threads. The option now only adds trackingSub (and -pthread on Emscripten). Reported by Qodo on #76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- check zlib init/inflate results, grow the output buffer past 4 MB and NUL-terminate it before searching it
- validate field order and non-empty lengths before writing anything
- write marker files in binary mode, check fopen/fwrite/fclose and remove partial output on failure
- drop the remove() of the source archive: it built a wrong name and never deleted anything
Reported by Qodo on #76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- trackingInitStart() returns -1 while the previous search is uncollected, instead of overwriting the image the worker reads
- trackingInitInit() checks the image allocation and thread creation and frees everything on failure
- tests: >4 MB marker, binary bytes, field order, non-zlib data, source archive kept, start rejected until results are collected
Reported by Qodo on #76.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kalwalt
kalwalt merged commit dfe8570 into dev Oct 6, 2026
1 check passed
kalwalt added a commit to webarkit/jsartoolkitNFT that referenced this pull request Oct 6, 2026
- emscripten/WebARKitLib: dfe8570 on WebARKitLib dev, the squash merge of
  webarkit/WebARKitLib#76 (same tree as the 480fdb9 used so far)
- build/ and dist/ rebuilt with emsdk 4.0.17 (npm run build-docker,
  npm run build-ts)

The earlier commits of this PR (0cff312, 3543c45, 00cf36e) changed
C/C++, JS and TS sources without committing the rebuilt build/ and dist/;
this commit brings them up to date with those changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
kalwalt added a commit to webarkit/jsartoolkitNFT that referenced this pull request Oct 7, 2026
* refactor: use the NFT helpers from WebARKitLib (#453)

trackingMod, trackingMod2d, trackingSub, markerDecompress and
NFTMarkerState moved to WebARKitLib (webarkit/WebARKitLib#75, #76) under
WebARKit/WebARKitTrackers/WebARKitNFT.

- tools/makem.js: take those sources from WebARKitLib and add its include
  directory
- bindings (JS and Python): include <WebARKitTrackers/WebARKitNFT/...>
- python-bindings/setup.py: new source and include paths
- remove the copies from emscripten/
- bump the WebARKitLib submodule to feat/issue-75-webarkit-nft

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: report a failed .zft decompression through onError

decompressMarkers() now returns -1 for a missing or malformed archive instead of exiting. The decompressZFT bindings returned 1 regardless, so loadZFT read temporary files that were never written and threw ENOENT before any callback ran. The bindings now return -1 on failure and loadZFT calls onError(prefix + ".zft"). Reported by Qodo on #687.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf: free the .zft archive from MEMFS once decompressed

loadZFT kept /markerNFT_N.zft in the Emscripten filesystem for the whole session; the old C-side remove() built the name without the dot, so it never deleted it either. Suggested by Qodo on #687.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: bump WebARKitLib to dev and rebuild build/ and dist/ (#453)

- emscripten/WebARKitLib: dfe8570 on WebARKitLib dev, the squash merge of
  webarkit/WebARKitLib#76 (same tree as the 480fdb9 used so far)
- build/ and dist/ rebuilt with emsdk 4.0.17 (npm run build-docker,
  npm run build-ts)

The earlier commits of this PR (0cff312, 3543c45, 00cf36e) changed
C/C++, JS and TS sources without committing the rebuilt build/ and dist/;
this commit brings them up to date with those changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: bump WebARKitLib to b2d6166 and rebuild build/ and dist/

- emscripten/WebARKitLib: b2d6166 on WebARKitLib dev, which adds
  webarkit/WebARKitLib#77 (#40: random template index computed in double
  precision in AR2/selectTemplate.c, fixing the
  -Wimplicit-const-int-float-conversion warning)
- build/ and dist/ rebuilt with emsdk 4.0.17 (npm run build-docker,
  npm run build-ts); vitest 182 passed / 6 skipped, node 7/7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: bump WebARKitLib to b5e4770 and rebuild build/ and dist/

- emscripten/WebARKitLib: b5e4770 on WebARKitLib dev, which adds
  webarkit/WebARKitLib#80 (review fixes before 0.10.0: capped .zft
  decompression, trackingInitMain null check, explicit #error for
  AR2_CAPABLE_ADAPTIVE_TEMPLATE)
- build/ and dist/ rebuilt with emsdk 4.0.17 (npm run build-docker,
  npm run build-ts); vitest 182 passed / 6 skipped, node 7/7

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: pin WebARKitLib to the 0.10.0 release tag

Move emscripten/WebARKitLib from b5e4770 (dev) to 4fd3034, the
merge commit on master tagged 0.10.0, as the 0.9.0 pin pointed at
master. Both commits have the same tree, so build/ and dist/ are
unchanged and need no rebuild.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C/C++ code concerning the C/C++ code design and improvements Emscripten enhancement New feature or request native-linux tests

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant