Opened 11 years ago

Closed 11 years ago

#2603 closed defect (fixed)

generated C code contains newlines in string literals

Reported by: Bill Janssen Owned by: Martin Sjölund
Priority: critical Milestone: 1.9.1
Component: Code Generation Version: trunk
Keywords: Cc:

Description

My generated simulation code doesn't compile, because of constructs like this. Note that C code only allows newlines in string literals if they are escaped.


     tmp3980 = cat_modelica_string("
      Temperature T (= ",tmp3979);
      tmp3981 = cat_modelica_string(tmp3980," K) is not
      in the allowed range (");

Change History (27)

comment:1 by Bill Janssen, 11 years ago

Traced this back to an assert statement in the library I'm using. It contains Modelica string literals with CR LF newlines in it, which are copied literally into the C code. We can't just copy them; Modelica string literals allow unescaped newlines, C string literals don't. Perhaps there are other differences as well, though none come immediately to mind.

comment:2 by Lennart Ochel, 11 years ago

Status: newaccepted

comment:3 by Martin Sjölund, 11 years ago

Which is why we have code that escapes string literals... I would guess it helps if we knew what expression caused this (\r, \n are escaped properly).

comment:4 by Adrian Pop, 11 years ago

I got an email from janssen which (non public) model has this issue.
I'll have a look at how the assert expression looks like and come back with some more info.

comment:5 by Adrian Pop, 11 years ago

Seems the error comes from MSL Media PartialMedium or all the other Mediums:

  redeclare replaceable model extends BaseProperties
  equation
    assert(T >= T_min and T <= T_max, "
    Temperature T (= " + String(T) + " K) is not
    in the allowed range (" + String(T_min) + " K <= T <= " + String(T_max) + " K)
    required from medium model \"" + mediumName + "\".
    ");
   // ...
  end BaseProperties;

However, strangely I can simulate the model fine:

adrpo@ida-liu050 /c/dev/avm
$ ~/dev/OpenModelica/build/bin/omc +locale=C vu.mos 
true
""
true
""
true
record SimulationResult
    resultFile = "",
    simulationOptions = "startTime = 0.0, stopTime = 30.0, numberOfIntervals = 500, tolerance = 1e-006, method = 'dassl', fileNamePrefix = 'C2M2L_Decl.C2M2L_Delivered_Component_Implementations.Drive_Line.Cross_Drive_Transmission.Test_cross_drive_PTO_Steer', options = '', outputFormat = 'mat', variableFilter = '.*', measureTime = false, cflags = '', simflags = ''",
    messages = "Simulation execution failed for model: C2M2L_Decl.C2M2L_Delivered_Component_Implementations.Drive_Line.Cross_Drive_Transmission.Test_cross_drive_PTO_Steer
stdout            | warning | Error in initialization. Storing results and exiting.
|                 | |       | Use -lv=LOG_INIT -w for more information.
",
    timeFrontend = 7.677711035848936,
    timeBackend = 1.62388912798616,
    timeSimCode = 0.8358188328751135,
    timeTemplates = 3.080788487196918,
    timeCompile = 7.874059468752382
end SimulationResult;

well, more or less as there is an error at initialization, but it can compile.

Where vu.mos looks like:

loadModel(Modelica); getErrorString();
loadFile("VU/C2M2L_Decl/package.mo"); getErrorString();

simulate(C2M2L_Decl.C2M2L_Delivered_Component_Implementations.Drive_Line.Cross_Drive_Transmission.Test_cross_drive_PTO_Steer); getErrorString();

You could do "make distclean" and recompile
OpenModelica as it seems something went
horribly wrong.

Last edited 11 years ago by Adrian Pop (previous) (diff)

comment:6 by Adrian Pop, 11 years ago

Just for posterity, I tested with r19322 and compilation works fine.

comment:7 by Bill Janssen, 11 years ago

Well, my OM is from last week's sources :-). I'll update and rebuild.

comment:8 by Bill Janssen, 11 years ago

Checked out an update, and rebuilt. Same problem.

<Gripe> "make distclean" is really a non-starter. For one thing, it blows away config.log, which records my carefully crafted configure line. </Gripe>

So maybe this is really a bug report about the makefiles.

comment:9 by Adrian Pop, 11 years ago

Ouch. Sorry about the config.log.
How do you try to build the model? From OMEdit? With omc + script? What OS?

comment:10 by Adrian Pop, 11 years ago

Ok. You're right. Seems I can reproduce this on Linux.

comment:11 by Bill Janssen, 11 years ago

Sorry, I should have said I was using a Unix machine. A Snow Leopard Mac, to be precise.

comment:12 by Bill Janssen, 11 years ago

I use omc on the command-line to generate the simulation code, then invoke make on the generated makefile.

comment:13 by Adrian Pop, 11 years ago

I asked sjoelund.se to have a look at this.
Seems is working if dos2unix is used on the .mo files loaded.
I guess the old everybody with its own line ending \n vs. \r vs. \n\r stuff :)

comment:14 by Bill Janssen, 11 years ago

I guess that's one way to look at it. But it seems that the code which is doing the Modelica-to-C transliteration is making some unwarranted assumptions.

comment:15 by Adrian Pop, 11 years ago

I guess not too many unwarranted assumptions as this
would have been apparent in all the testing quite a lot.

This is the function. Can anybody spot the issue?

extern char* omc__escapedString(const char* str, int nl)
{
  int len1,len2;
  char *res;
  int i=0;
  len1 = strlen(str);
  len2 = omc__escapedStringLength(str,nl);
  if(len1 == len2) return NULL;
  res = (char*) malloc(len2+1);
  while(*str) {
    switch (*str) {
      case '"': res[i++] = '\\'; res[i++] = '"'; break;
      case '\\': res[i++] = '\\'; res[i++] = '\\'; break;
      case '\a': res[i++] = '\\'; res[i++] = 'a'; break;
      case '\b': res[i++] = '\\'; res[i++] = 'b'; break;
      case '\f': res[i++] = '\\'; res[i++] = 'f'; break;
      case '\v': res[i++] = '\\'; res[i++] = 'v'; break;
      case '\r': if(nl) {res[i++] = '\\'; res[i++] = 'n'; if(str[1] == '\n') str++;} else {res[i++] = *str;} break;
      case '\n': if(nl) {res[i++] = '\\'; res[i++] = 'n'; if(str[1] == '\r') str++;} else {res[i++] = *str;} break;
      default: res[i++] = *str;
    }
    str++;
  }
  res[i] = '\0';
  return res;
}
Last edited 11 years ago by Lennart Ochel (previous) (diff)

comment:16 by Bill Janssen, 11 years ago

What's this nl flag doing, and what code generates it?

comment:17 by Bill Janssen, 11 years ago

There is no world in which \n followed by \r is a newline, so the case for '\n' doesn't seem right. But that's not the problem.

comment:18 by Lennart Ochel, 11 years ago

I don't get the both else cases. I would just leave them out - but I know that this is already well tested. So probably it's just me.

comment:19 by Adrian Pop, 11 years ago

The nl flag comes from above to tell this function to either escape or not the new lines.
But as far as I can see, in the compiler is called with true to transform a Modelica to a C string.

in reply to:  18 comment:20 by Lennart Ochel, 11 years ago

Replying to lochel:

I don't get the both else cases. I would just leave them out - but I know that this is already well tested. So probably it's just me.

That's not true.

in reply to:  17 comment:21 by Martin Sjölund, 11 years ago

Replying to janssen:

There is no world in which \n followed by \r is a newline, so the case for '\n' doesn't seem right. But that's not the problem.

You mean except old-world Mac? (Or wait, that was only \r?)

Anyway, the problem is the logic that if old strlen is same as new strlen, we don't need to run the algorithm. "abc\r\n" => "abc\\\n"

Last edited 11 years ago by Martin Sjölund (previous) (diff)

comment:22 by Bill Janssen, 11 years ago

You think it would run on old-world Mac?

It probably should just quote any control character, instead of considering specific cases.

But if this function is being called consistently, there should be no \r characters in the output, and there clearly are. So I'm guessing there's some path for code generation of assertions that doesn't invoke this function.

comment:23 by Bill Janssen, 11 years ago

I think old-world Mac just used CR, anyway.

in reply to:  22 comment:24 by Martin Sjölund, 11 years ago

Replying to janssen:

But if this function is being called consistently, there should be no \r characters in the output, and there clearly are. So I'm guessing there's some path for code generation of assertions that doesn't invoke this function.

Read above. The algorithm is not run for specific cases. I'm running the testsuite now.

comment:25 by Bill Janssen, 11 years ago

Yep. The unwarranted assumption was that appropriate quoting would always change the length of the string.

comment:26 by Martin Sjölund, 11 years ago

Owner: changed from Lennart Ochel to Martin Sjölund
Status: acceptedassigned

comment:27 by Martin Sjölund, 11 years ago

Resolution: fixed
Status: assignedclosed

Fixed in r19323.

Note: See TracTickets for help on using tickets.