GithubHelp home page GithubHelp logo

Comments (19)

macovedj avatar macovedj commented on May 30, 2024

fwiw by changing my bindings to use this

function myEncode(s, realloc, memory) {
  let encodedLen
  if (typeof s !== 'string') throw new TypeError('expected a string');
  if (s.length === 0) {
    encodedLen = 0;
    return 1;
  }
  let allocLen = 0;
  let ptr = 0;
  let writtenTotal = 0;
  while (s.length > 0) {
    ptr = realloc(ptr, allocLen, 1, allocLen + s.length);
    allocLen += s.length;
    const { read, written } = utf8Encoder.encodeInto(
    s,
    new Uint8Array(memory.buffer, ptr + writtenTotal, allocLen - writtenTotal),
    );
    writtenTotal += written;
    s = s.slice(read);
  }
  if (allocLen > writtenTotal)
  ptr = realloc(ptr, allocLen, 1, writtenTotal);
  encodedLen = writtenTotal;
  return {ptr, encodedLen};
}

instead of utf8Encode and replacing the above usage with

const var1 = myEncode(v0_0, realloc1, memory0);
const var2 = myEncode(v0_1, realloc1, memory0);
const {logRoot: v3_0, logLength: v3_1, mapRoot: v3_2 } = arg1;
const var4 = myEncode(v3_0, realloc1, memory0);
const var5 = myEncode(v3_2, realloc1, memory0);
exports1['protocol#prove-inclusion'](var1.ptr, var1.encodedLen, var2.ptr, var2.encodedLen, var4.ptr, var4.encodedLen, toUint32(v3_1), var5.ptr, var5.encodedLen);

I was able to resolve my bugs

from jco.

esoterra avatar esoterra commented on May 30, 2024

It looks like what you say is true and the global value is used to return part of the result, but I'm not clear what part of that is the "bug". Is there some sort of reentrancy, concurrency, parallelism type issue you hit with this approach or is it more that you would prefer it to return an object?

from jco.

macovedj avatar macovedj commented on May 30, 2024

Ah sorry I guess I was a little unclear on that. As things are, the lengths of the different variables are incorrect when I pass them to my guest code. The bytes are written to memory properly, but the first value will contain bytes from the second variable in my case, due to having a length associated with the most recent value of utf8EncodedLength, rather than the value from from when utf8Encode was originally called. I'd guess that one could also produce cases where the length is too short, and guest input variables end up missing bytes of data in their value, even though the bytes were written to memory properly.

from jco.

esoterra avatar esoterra commented on May 30, 2024

Is this mismatch between values in utf8EncodedLength when utf8Encode was initially called vs. when the value is needed something that happens in generated code or in your calling code? If it's in your calling code, then I would expect you can store the values as an object together yourself without needing a jco change and if it's in generator code then we should probably fix that code.

from jco.

macovedj avatar macovedj commented on May 30, 2024

It's in the generated code. Actually, in the current code I'm working with, the exposed guest function takes three args, the first of which is a struct with two string fields, and the issue is happening in those two fields. The first field is getting the first handful of characters from the second field appended to the end, because the generated code communicates the wrong length of the first field to the guest export from what I can tell. So it's happening even though a single object argument containing two strings is passed to it, or so it seems to me.

from jco.

guybedford avatar guybedford commented on May 30, 2024

@macovedj can you share a simple example of the case here? Sounds like a bug we need to fix to me.

from jco.

macovedj avatar macovedj commented on May 30, 2024

Here are js bindings https://github.com/macovedj/package-explorer/blob/main/src/protocol/protocol_wasm.js#L884
generated from a component created using this wit file https://github.com/bytecodealliance/registry/pull/93/files#diff-15d3507a7e5943bee0c1ece505f3bfe26e781745ceb0fdd330d207a4d8750336R80. Snippets above were sourced from this, and I got the code to behave as I expected by implementing the myEncode function in the above snippet over in the bindings I just linked. I have made some changes to the project since opening this issue, but I think it should still display what's going on well.

from jco.

macovedj avatar macovedj commented on May 30, 2024

I'll try and generate some logs that show the appended bytes

from jco.

macovedj avatar macovedj commented on May 30, 2024

Screen Shot 2023-04-12 at 3 42 49 PM

Having a little bit of trouble logging the actual bytes this time around, but you can see that the lengths being passed are both `71`, where I'm logging the lengths that are actually fed to the guest bindings in my rust code, However the strings have different lengths on the host side, and I believe 71 is the length of the final string that gets encoded that is passed from host to guest.

from jco.

macovedj avatar macovedj commented on May 30, 2024

Screen Shot 2023-04-12 at 3 46 40 PM

Managed to log the bytes... and what the strings look like on the host. You can see that the first bytes of the second string are appended to the end of the first string on the guest side, because the guest thinks the first string is longer than it should be

from jco.

guybedford avatar guybedford commented on May 30, 2024

@macovedj it's hard to speculate without having a full end to end example here, because there could be a number of reasons for this.

If you'd like to add some logging, I'd suggest adding console.log(utf8EncodedLen) at each point at which an assignment occurs, and comparing that to your own implementation. I'd be very surprised if you truly are seeing different numbers. Execution in JavaScript is very much deterministic (thankfully, the language isn't that bad :P), so that the utf8EncodedLen global variable should always take the correct value when used immediately after the last call. And because numbers are assigned by copy in JavaScript, the len1 and len2 values should be copies of the length at that point in time in the execution.

So there must be some other factor going on here (or a browser bug..!). Which environment are you testing on? Again if you can share a direct replicable example I can run I can happily investigate further. If I clone the repo, how would I set up the web server to get the bad output?

from jco.

guybedford avatar guybedford commented on May 30, 2024

Another thing to check - in your build process output, are you running the script as a global somehow so that window.utf8EncodedLen is a number?

(in JS, scripts treat top-level assignments as globals, while modules treat top-level assignments as locals)

from jco.

macovedj avatar macovedj commented on May 30, 2024

So you should be able to just clone this repo, then do npm i followed by npm run preview, and click the update button in order to reproduce. There's some caching of some web/service worker stuff going on, so I'd maybe use an incognito window. The protocol folder in components contains the jco generated javascript. If you want to dig into the wasm, you can rebuild the wasm component by running cargo component build in the protocol-wasm folder in this branch of this repo. Traveling to Europe from Texas for CNCF today, but I intend to spend some time thinking about this some more soon.

from jco.

macovedj avatar macovedj commented on May 30, 2024

So you should be able to just clone this repo, then do npm i followed by npm run preview, and click the update button in order to reproduce. There's some caching of some web/service worker stuff going on, so I'd maybe use an incognito window. The protocol folder in components contains the jco generated javascript. If you want to dig into the wasm, you can rebuild the wasm component by running cargo component build in the protocol-wasm folder in this branch of this repo. Traveling to Europe from Texas for CNCF today, but I intend to spend some time thinking about this some more soon.

Actually, you'll also need to run the warg server, which you can do by running the setup-server.sh script in the registry repo, and then use the cli to publish a package. I'll try and move that logic into one repo, to make it easier to reproduce when I can.

from jco.

macovedj avatar macovedj commented on May 30, 2024

Ok, sorry for the complicated steps I described prior. I just made a new repo for displaying the bug. A clone and npm i and npm run preview should do the trick. Generated javascript is in example-wasm, and there's a component crate called example if you want to rebuild the wasm. You should be able to just click the button titled "Wasm Functions" and observe that chars from one field of the input object are being added to the other in the dev tools.

from jco.

guybedford avatar guybedford commented on May 30, 2024

@macovedj thanks, I took a look and here's the generated code for that same section you mentioned before:

D || re();
        const {a: r, b: l} = e
          , o = h(r, E, i)
          , s = h(l, E, i);
        A["foo#hello-world"](o, p, s, p)

In the above, h is the utf8Encode function and p is the global utf8EncodedLen value.

As you can see, the JS optimization code has replaced the intermediate len1 and len2 with a direct inlining at the function call location of a single p variable, which misses the intermediate assignment value.

This is therefore a bug with the quik optimizer in that it is assuming that the assignment can be inlined when it cannot due to it being a multi-assigned variable.

We could potentially alter our output - but the quik optimizer will have other bugs from this optimization issue, so it's probably worth reporting there. Let me know if I can help with creating that issue at all, and feel free to copy me in.

from jco.

macovedj avatar macovedj commented on May 30, 2024

@guybedford Ah wow thanks for looking into it. Makes sense. Will try and put some thought into an issue soon, and keep you in the loop.

from jco.

esoterra avatar esoterra commented on May 30, 2024

I wonder if we could wrap utf8EncodedLen with a function that returns the global so that optimizers treat it more opaquely as a function which might have side causes and side effects.

from jco.

guybedford avatar guybedford commented on May 30, 2024

This issue has now been resolved in the Quik optimizer. This isn't a normal JS build bug by any means - most JS build tools would support this fine. So I'm confident we can mark this as resolved for the next Quik release and that will be the end of it.

from jco.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.